Mastermind

 

 

I 70'erne kom der et nyt spil, der hed Mastermind. Jeg husker det fra jeg var barn, og det var et af de første spil jeg implementerede på en Texas Instrument TI-99/4A, i starten af 80'erne. Formålet med denne opgave er at gøre det samme — dog med en mere tidsvarende teknologi!
Spillet var en overgang meget populært, og det kom i mange forskellige udgaver. Følgende er en af de mest udbredte:
Der er to deltagere i spillet. Den ene spiller (som vi vil lade være computeren) vælger en kode bestående af fire farvede plastik-pinde som han placerer i de fire huller, der optræder nederst til venstre på billedet. De tages fra æsken til højre, og der er tale om de "store" pinde (ikke de små hvide og sorte pinde). Der må gerne optræde den samme farve flere gange, så en lovlig kode kunne f.eks. være grøn, rød, grøn og blå. Øverst til venstre i billedet aner man et lille stykke plastik som man placerer over koden, så det kun er den der har lavet koden, der kan se den. Det er nu den anden spillers opgave at gætte koden. Den anden spiller er brugeren af vores program!
Spillet forløber nu ved at den anden spiller kommer med et gæt, ved at han placerer fire farvede platik-pinde i den øverste række til venstre på billedet (næste gæt placeres på næste række osv.). Den første spiller, der kender koden, placerer nu en række sort og hvide pinde (de små pinde) ved siden gættet. På billedet er det de fire små huller til højre for gættet. Han placerer en lille sort pind for hvert gæt der har den rigtige farve og er placeret det rigtige sted, og han placerer en lille hvid pind for hvert gæt der har den rigtige farve, men er placeret forkert. De små sorte og hvide pinde betegnes som et hint, og det er ud fra disse hints at spilleren der skal gætte koden må arbejde sig frem. Der er ingen sammenhæng mellem hvor de sorte og hvide pinde placeres i de fire små huller til højre for gættet, og hvor de rigtige farver er placeret. Og den spiller, der skal gætte koden, kan derfor kun arbejde ud fra antallet af sorte og hvide pinde som hans gæt afstedkommer.
Det kan i starten være vanskeligt helt præcist at forstår hvordan der gives hints, så lad os gennemgå et par eksempler. Hvis koden er grøn, rød, grøn og blå, som nævnt ovenfor, og gættet er grøn, rød, rød og gul, skal hintet være to sorte pinde. Den grønne, og den første røde er placeret korrekt, hvilket giver de to sorte pinde. Den sidste røde giver ikke en hvid pind, da man kun kan få én pind for hver farvet plastik-pind i koden! Så havde der været én gul farve i koden og man havde gættet på fire gule, skulle man altså ikke have én sort og tre hvid, men kun én sort! Er gættet grøn, grøn, grøn, rød, skal hintet være to sorte (for de to grønne i koden) og en hvid (for den røde, der er placeret forkert). Vi skal senere under implementationen se hvordan man forholdsvis enkelt kan holde styr på det.
Når den anden spiller gætter koden (han skal dog nå det inden for det antal rækker/gæt der er til rådighed — på billedet ovenfor er det ti gæt, men det varierede i de forskellige udgaver af spillet, jeg har ét med kun seks!), bytter de to spillere roller. Man konkurrerer på den måde om hvem der er hurtigst til at "bryde" koder.
Når vi i det følgende implementerer Mastermind, vil vi ikke arbejde med farver, da det komplicerer vores arbejde med at lave brugergrænsefladen unødvendigt. Vi vil i stedet arbejde med tal/cifre, idet koden bliver et tal på fire cifre, hvor der må anvendes tallene fra 0-5. I Mastermind er der typisk seks farver, og det passer med de seks mulige cifre. En kode kunne derfor være 4022. Vores implementation vil ikke havde en grafisk brugergrænseflade, men blot læse og udskrive til konsollen.
Jeg vil ikke i detaljer beskriver hvordan man kan implementere spillet — det er trods alt opgaven — men jeg vil komme med en hel del hints!
Det kan være nyttigt, at lave en række hjælpe-metoder, der kan løse mindre opgaver som kan indgå i en løsning:

int[] createRandomCode(int digits): der kan generere en tilfældig kode på det antal cifre der gives med som parameter. Koden returneres som et array bestående af de enkelte cifre. Vi vil bruge det til at lave koder med fire cifre (og dermed arrays med en længde på fire), men vi vil lave metoden så den ikke er bundet til dette antal cifre.

String readInput(): der indlæser en linie fra konsollen, som brugeren indtaster — dvs. et gæt. Brug i den forbindelse System.in. Man kan søge på nettet om hvordan man kan gøre dette (google f.eks.: java system.in read line from console, eller lignende søgeord).

int[] stringToDigits(String line): der kan konvertere en tekststreng bestående af cifre på tekstform (f.eks.: "4022"), til et array bestående af de enkelte cifre. Der vil være tale om brugerens input, som vi med denne metode vil konverere til et gæt, der kan sammenlignes med koden.

int[] copyArray(int[] array): der laver en kopi af det array, der gives med som parameter. Metoden skal altså instantiere et nyt array, af samme længde som det der gives med som parameter, dernæst kopiere værdierne over, så de to array bliver ens, og returnere det nye array. Vi vil senere se hvorfor denne metode kan være praktisk.

String repeatChar(char c, int n): der tager et tegn (c) og et vist antal (n) som parameter, og returnerer en tekststreng bestående af tegnet gentaget det givne antal gange. Hvis parametrene f.eks. er 'H' og 3, vil metoden returnere "HHH". Denne metode kan være nyttig når programmet skal udskrive hints til brugeren.

Vi har tidligere set på, hvordan man kan sammenligne koden og gættet, for at lave de hints som brugeren skal arbejde videre med. Som sagt kan det være lidt vanskeligt, at lave denne del af programmet. Den nemmeste, og mest sikre måde, at gøre det på, er ved at gøre følgende: (1) man laver først en kopi af koden, for at man kan ødelægge den, uden at koden går tabt — så det er altså kopien man ødelægger! (2) man sammenligner dernæst sammenhørende indgange i koden og gættet, for at finde ud af hvor man sorte pinde der skal være. Hver gang man finder et ciffer der står korrekt, tæller man antallet op med én, og man sætter det pågældende ciffer til -1 i både (kopien af) koden og gættet! (3) man sammenligner dernæst gættet med (kopien af) koden (hint: der skal bruges to løkker inden i hinanden), for at se hvor mange cifre der er rigtige, men placeret forkert, altså hvor mange små hvide pinde der skal være i hintet. Man skal se bort fra -1, og man skal igen sætte "brugte" indgange til -1. Hele formålet med at sætte indgange til -1, er at markere dem som "brugte".
Selve spillet forløber ved at man kører en løkke, der først stopper når brugeren har gættet koden. For hver iteration beder man brugeren om et gæt, udskriver hints, og gentager igen, indtil der er fire sorte pinde!