Boter-kaas-en-eieren (ook wel oo maal oo of kruisje nulletje genoemd) is een eenvoudig spel voor twee spelers. Het wordt met potlood en papier gespeeld op een $$3 \times 3$$ rooster. Bij aanvang zijn alle velden leeg. Een speler zet kruisjes (hier voorgesteld door de letter X) en de andere speler zet rondjes (hier voorgesteld door de letter O). De spelers zetten om beurt elk hun eigen symbool op één van de lege velden van het rooster. De speler die kruisjes zet mag altijd beginnen. Degene die drie van zijn eigen symbolen op een rij heeft (diagonaal, verticaal of horizontaal) heeft gewonnen. Als alle veldjes ingevuld zijn zonder dat één van de spelers wint, dan eindigt het spel in een gelijkspel. Het volgende spelletje werd bijvoorbeeld gewonnen door de speler die kruisjes zet.
Voor iemand die het spel goed genoeg kent, is het eenvoudig om ieder spel in een gelijkspel te laten eindigen, ongeacht wat de tegenstander doet. Zeker voor beginners is het veld in het midden het belangrijkste veld. Er zijn in totaal 764 mogelijke bordposities, zonder daarbij het lege bord mee te rekenen en zonder posities dubbel te rekenen die door roteren of spiegelen hetzelfde zijn. Er zijn in totaal 2096 zetten toegestaan vanaf de eerste zet en daarna tussen de opeenvolgende bordposities. Zo zijn er drie verschillende openingszetten mogelijk: in het midden, in een hoek of in het midden van een rand.
Een gegeven tekstbestand bevat de configuratie van een spelletje boter-kaas-en-eieren dat net is afgelopen. Het bestand bestaat uit drie regels, die elk drie karakters bevatten. De mogelijke karakters zijn i) een spatie die staat voor een leeg veld, ii) een letter X die is neergezet door de eerste speler, of iii) een letter O die is neergezet door de tweede speler. Aan jou de vraag om te bepalen welke speler gewonnen heeft. Hiervoor definieer je een klasse BoterKaasEieren, die minstens de volgende drie methoden ondersteunt:
Een initialisatiemethode waaraan de locatie van een tekstbestand met de configuratie van een spelletje boter-kaas-en-eieren moet doorgegeven worden. De methode moet de informatie uit het bestand inlezen, en opslaan in een attribuut bord van het nieuw aangemaakte object. Het attribuut bord moet hierbij verwijzen naar een lijst van strings, waarbij elke string bestaat uit de drie karakters uit de overeenkomstige regel in het gegeven tekstbestand.
Een implementatie van de ingebouwde __str__ methode die een stringvoorstelling teruggeeft van het rooster waarop het spelletje gespeeld wordt. Deze stringvoorstelling moet een opgemaakte weergave van het rooster voorstellen. Hiervoor moet de string bestaan uit drie regels, die de rijen van het rooster voorstellen. De kolommen van het rooster worden in de string van elkaar gescheiden door een spatie. Lege veldjes moeten voorgesteld worden door een punt (.).
Een methode winnaar die de winnaar van het spelletje boter-kaas-en-eieren teruggeeft. De methode moet de string X wint teruggeven als de speler die kruisjes zet het spel heeft gewonnen, de string O wint als de speler die rondjes zet het spel heeft gewonnen, en de string gelijkspel als het spel geëindigd is op een gelijkspel.
Bij onderstaande voorbeeldsessie gaan we ervan uit dat de tekstbestanden tictactoe1.txt1, tictactoe2.txt2 en tictactoe3.txt3 zich in de huidige directory bevinden.
>>> spel = BoterKaasEieren('tictactoe1.txt')
>>> spel.bord
['OX ', 'OX ', ' X ']
>>> print(spel)
O X .
O X .
. X .
>>> spel.winnaar()
'X wint'
>>> spel = BoterKaasEieren('tictactoe2.txt')
>>> spel.bord
['OOO', ' XX', 'X ']
>>> print(spel)
O O O
. X X
X . .
>>> spel.winnaar()
'O wint'
>>> spel = BoterKaasEieren('tictactoe3.txt')
>>> spel.bord
['XXO', 'OOX', 'XOX']
>>> print(spel)
X X O
O O X
X O X
>>> spel.winnaar()
'gelijkspel'