Kluizenaar is een strategiespel voor twee spelers. Het wordt gespeeld op een spelbord met $$n \times n$$ vierkante velden die gerangschikt zijn in een vierkant rooster met $$n$$ rijen en $$n$$ kolommen. Bij aanvang van een spel is het spelbord leeg. Naast het spelbord ligt een voorraad balkvormige blokken met afmetingen van $$1 \times 1 \times 2$$ eenheden, waarbij een eenheid ongeveer even lang is als de zijde van een veld op het spelbord. De blokken hebben drie verschillende kleuren: rood, geel en blauw.

kluizenaar
Dit spelbord van het spelletje Kluizenaar bestaat uit 16 vierkante velden die gerangschikt zijn in een vierkant $$4 \times 4$$ rooster met 4 rijen en 4 kolommen. De twee spelers hebben al enkele gekleurde balkvormige blokken op het spelbord geplaatst en naast het spelbord ligt nog een voorraad blokken die ze op het spelbord kunnen leggen. In deze configuratie kunnen er enkel nog gele blokken rechtopstaand op het spelbord geplaatst worden op de twee lege velden aan de linkerrand van het rooster.
beginopstelling
Schematische voorstelling van een $$4 \times 4$$ spelbord van het spelletje Kluizenaar. Aan het begin van een spelletje zijn er nog geen blokken op het spelbord geplaatst, aangeduid door de witte kleur van de velden.

Elke speler kiest om de beurt een blok van een bepaalde kleur. Het blok mag rechtopstaand op het bord geplaatst worden zodat het slechts één veld bedekt of op een lange kant neergelegd worden zodat het twee aangrenzende velden bedekt.

plaatsing
De gekleurde balkvormige blokken kunnen rechtopstaand op het spelbord geplaatst worden zodat ze slechts één veld bedekken (links). Ze kunnen ook horizontaal (centraal) of verticaal (rechts) op hun lange kant neergelegd worden zodat ze twee aangrenzende velden bedekken.

Blokken mogen alleen maar op lege velden geplaatst worden. Ze mogen ook niet raken aan een blok van dezelfde kleur, ook niet diagonaal. In onderstaand schema liggen er al blokken op dezelfde posities als op de foto hierboven. De gele cirkels geven de enige mogelijkheden aan om nog een blok te plaatsen: een geel blok dat rechtopstaand geplaatst wordt op positie $$(1, 0)$$ of positie $$(3, 0)$$.

mogelijke zetten
De gele cirkels geven aan waar er in deze configuratie van het spelbord nog blokken kunnen geplaatst worden: er kunnen enkel nog gele blokken rechtopstaand geplaatst op het spelbord worden op posities $$(1, 0)$$ en $$(3, 0)$$.

De eerste speler die geen enkel blok meer kan plaatsen, verliest het spel. Gelijkspel is niet mogelijk.

Opgave

Om naar de velden op een Kluizenaar spelbord te kunnen verwijzen, worden de rijen van boven naar onder genummerd en de kolommen van links naar rechts, telkens vanaf nul. De positie van een veld op het spelbord wordt aangeduid met een tuple $$(r, k)$$, waarbij $$r \in \mathbb{N}$$ (int) het rijnummer en $$k \in \mathbb{N}$$ (int) het kolomnummer aanduidt.

De kleur van een blok wordt aangeduid met een hoofdletter: Y (geel), B (blauw) of R (rood).

De plaatsing van een blok wordt aangeduid met een hoofdletter: U (rechtopstaand), H (horizontaal) of V (verticaal).

Definieer een klasse Kluizenaar waarmee het verloop van een spelletje Kluizenaar kan gesimuleerd worden. Bij het aanmaken van een nieuw spel (Kluizenaar) moet de dimensie $$n$$ (int) van het spelbord doorgegeven worden. Bij aanvang van het spel staan er nog geen blokken op het spelbord.

Als er een spel (Kluizenaar) wordt doorgegeven aan de ingebouwde functie str, dan moet een stringvoorstelling (str) van het spelbord teruggegeven worden. Daarin vormt elke rij een afzonderlijke regel. Lege velden worden voorgesteld door een punt (.) en velden waarop een blok ligt door de hoofdletter die de kleur van het blok aanduidt. De voorstellingen van aangrenzende velden op dezelfde rij worden telkens van elkaar gescheiden door één spatie.

Daarnaast moeten op een spel $$s$$ (Kluizenaar) minstens de volgende methoden kunnen aangeroepen worden:

Voorbeeld

>>> spelbord = Kluizenaar(4)
>>> print(spelbord)
. . . .
. . . .
. . . .
. . . .
>>> spelbord.posities((0, 0), 'H')
{(0, 0), (0, 1)}
>>> spelbord.isgeldig('R', (0, 0))
True
>>> spelbord.isgeldig('R', (0, 1))
True
>>> print(spelbord.zet('R', (0, 0), 'H'))
R R . .
. . . .
. . . .
. . . .
>>> print(spelbord.zet('R', (1, 2), 'V'))
Traceback (most recent call last):
AssertionError: ongeldige zet
>>> print(spelbord.zet('B', (0, 2), 'U').zet('Y', (1, 2), 'U'))
R R B .
. . Y .
. . . .
. . . .
>>> print(spelbord.zet('R', (3, 1), 'U').zet('Y', (3, 2), 'H'))
R R B .
. . Y .
. . . .
. R Y Y
>>> print(spelbord.zet('R', (1, 3), 'V').zet('B', (2, 0), 'H'))
R R B .
. . Y R
B B . R
. R Y Y
>>> spelbord.mogelijke_zetten()
{('Y', (1, 0), 'U'), ('Y', (3, 0), 'U')}
>>> print(spelbord.zet('Y', (3, 0), 'U'))
R R B .
. . Y R
B B . R
Y R Y Y
>>> spelbord.mogelijke_zetten()
{('Y', (1, 0), 'U')}
>>> print(spelbord.zet('Y', (1, 0), 'U'))
R R B .
Y . Y R
B B . R
Y R Y Y
>>> spelbord.mogelijke_zetten()
set()