Yin-Yang is een logische puzzel die bestaat uit een vierkant $$n \times n$$ rooster met $$n$$ rijen en $$n$$ kolommen. Bij aanvang zijn sommige vakjes wit of zwart gemarkeerd. Die vakjes kunnen niet van kleur wijzigen. De overige vakjes zijn voorlopig nog leeg.

Yin-Yang puzzel

Het doel is om alle lege vakjes wit of zwart te maken zodat

Daarbij worden vakjes van dezelfde kleur door horizontaal en vertikaal aangrenzende zijden verbonden tot aaneengesloten gebieden.

Dit is een oplossing van bovenstaande Yin-Yang puzzel: de witte vakjes vormen één aaneengesloten gebied (aangeduid met een gele achtergrondkleur), de zwarte vakjes vormen één aaneengesloten gebied (aangeduid met een donkergrijze achtergrond), en er is geen enkel $$2 \times 2$$ vierkant dat bestaat uit vier vakjes met dezelfde kleur.

Yin-Yang puzzel (oplossing)

Dit kan geen oplossing zijn van een Yin-Yang puzzel: de witte vakjes vormen wel één aaneengesloten gebied, maar de zwarte vakjes vormen twee aaneengesloten gebieden.

Yin-Yang puzzel (niet-verbonden)

Dit kan ook geen aanzet zijn tot een oplossing van een Yin-Yang puzzel, omdat het $$2 \times 2$$ vierkant aangeduid met een rode achtergrondkleur bestaat uit vier vakjes met dezelfde kleur.

Yin-Yang puzzel (ongeldig vierkant)

Opgave

We nummeren de rijen in het rooster van een Yin-Yang puzzel van boven naar onder, en de kolommen van links naar rechts, telkens vanaf nul. Zo kunnen we de positie van een vakje in het rooster voorstellen door een tuple $$(r, k)$$, met $$r$$ (int; $$0 \leq r < n$$) het nummer van de rij en $$k$$ (int; $$0 \leq k < n$$) het nummer van de kolom waarop het vakje voorkomt.

Yin-Yang puzzel (coördinaten)

Definieer een klasse YinYang waarmee Yin-Yang puzzels met een vierkant $$n \times n$$ rooster kunnen voorgesteld worden. Bij het aanmaken van een nieuwe puzzel $$\mathcal{Y}$$ (YinYang) moeten drie argumenten doorgegeven worden aan deze drie parameters:

  1. dimensie (int): de dimensie $$n$$ van het rooster van puzzel $$\mathcal{Y}$$

  2. wit (list, tuple of set): een collectie met de posities van vakjes die wit gekleurd zijn in de opgave van puzzel $$\mathcal{Y}$$

  3. zwart (list, tuple of set): een collectie met de posities van vakjes die zwart gekleurd zijn in de opgave van puzzel $$\mathcal{Y}$$

Daarbij moeten de volgende voorwaarden voldaan zijn:

Als minstens één van deze voorwaarden niet voldaan is, dan moet een AssertionError opgeworpen worden met de boodschap ongeldige puzzel.

Het moet mogelijk zijn om lege vakjes zwart of wit te maken, of vakjes die leeg waren in de opgave van de puzzel terug leeg te maken als die ondertussen zwart of wit gemaakt zijn. Daarom moet je op een puzzel $$\mathcal{Y}$$ (YinYang) minstens de volgende methoden kunnen aanroepen:

Als er een puzzel $$\mathcal{Y}$$ (YinYang) wordt doorgegeven aan de ingebouwde functie str, dan moet die een stringvoorstelling (str) van het rooster van puzzel $$\mathcal{Y}$$ teruggeven. Daarin wordt elke rij van het rooster voorgesteld als een afzonderlijke regel, en worden de opeenvolgende vakjes op een rij (van links naar rechts) elk voorgesteld door één karakter:

Voorbeeld

In deze interactieve sessie gebruiken we de Yin-Yang puzzel met een $$6 \times 6$$ rooster uit de inleiding als voorbeeld. Daarbij maken we stap voor stap de lege vakjes wit of zwart, tot we de oplossing krijgen die in de inleiding gegeven wordt.

>>> puzzel = YinYang(dimensie=6, wit=[(2, 0), (1, 2), (3, 2), (5, 5)], zwart=[(2, 1), (2, 4), (3, 1), (4, 1), (4, 3), (5, 0)])
>>> print(puzzel)
------
--W---
WB--B-
-BW---
-B-B--
B----W
>>> print(puzzel.maak_wit((0, 0)))
w-----
--W---
WB--B-
-BW---
-B-B--
B----W
>>> puzzel.maak_zwart((3, 2))     # positie is reeds bezet
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> puzzel.maak_zwart((1, 6))     # positie ligt buiten puzzel
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> print(puzzel.maak_zwart((5, 1)))
w-----
--W---
WB--B-
-BW---
-B-B--
Bb---W
>>> puzzel.maak_zwart((4, 0))       # er wordt een vierkant gevormd
Traceback (most recent call last):
AssertionError: ongeldige actie
>>> print(puzzel.maak_wit((0, 1)).maak_wit((0, 2)).maak_wit((0, 3)).maak_wit((0, 4)).maak_zwart((0, 5)))
wwwwwb
--W---
WB--B-
-BW---
-B-B--
Bb---W
>>> print(puzzel.maak_leeg((0, 5)))
wwwww-
--W---
WB--B-
-BW---
-B-B--
Bb---W
>>> print(puzzel.maak_wit((0, 5)))
wwwwww
--W---
WB--B-
-BW---
-B-B--
Bb---W
>>> print(puzzel.maak_wit((1, 0)).maak_zwart((1, 1)).maak_zwart((1, 3)).maak_zwart((1, 4)).maak_wit((1, 5)))
wwwwww
wbWbbw
WB--B-
-BW---
-B-B--
Bb---W
>>> print(puzzel.maak_wit((2, 2)).maak_wit((2, 3)).maak_wit((2, 5)))
wwwwww
wbWbbw
WBwwBw
-BW---
-B-B--
Bb---W
>>> print(puzzel.maak_wit((3, 0)).maak_zwart((3, 3)).maak_zwart((3, 4)).maak_wit((3, 5)))
wwwwww
wbWbbw
WBwwBw
wBWbbw
-B-B--
Bb---W
>>> print(puzzel.maak_wit((4, 0)).maak_wit((4, 2)).maak_wit((4, 4)).maak_wit((4, 5)))
wwwwww
wbWbbw
WBwwBw
wBWbbw
wBwBww
Bb---W
>>> puzzel.isopgelost()
False
>>> print(puzzel.maak_wit((5, 2)).maak_zwart((5, 3)).maak_zwart((5, 4)))
wwwwww
wbWbbw
WBwwBw
wBWbbw
wBwBww
BbwbbW
>>> puzzel.aaneengesloten_gebied((2, 1))
{(2, 1), (3, 1), (1, 1), (5, 1), (5, 0), (4, 1)}
>>> puzzel.aaneengesloten_gebied((3, 2))
{(4, 0), (0, 2), (0, 5), (2, 2), (1, 0), (2, 5), (4, 2), (3, 0), (4, 5), (0, 1), (1, 2), (0, 4), (1, 5), (3, 2), (3, 5), (5, 2), (4, 4), (5, 5), (0, 0), (0, 3), (2, 0), (2, 3)}
>>> puzzel.isopgelost()
False
>>> print(puzzel.maak_leeg((5, 2)).maak_zwart((5, 2)))
wwwwww
wbWbbw
WBwwBw
wBWbbw
wBwBww
BbbbbW
>>> puzzel.aaneengesloten_gebied((2, 1))
{(1, 3), (2, 4), (2, 1), (3, 4), (4, 3), (3, 1), (1, 1), (5, 4), (5, 1), (1, 4), (3, 3), (5, 0), (5, 3), (4, 1), (5, 2)}
>>> puzzel.aaneengesloten_gebied((3, 2))
{(4, 0), (0, 2), (0, 5), (2, 2), (1, 0), (2, 5), (4, 2), (3, 0), (4, 5), (0, 1), (1, 2), (0, 4), (1, 5), (3, 2), (3, 5), (4, 4), (5, 5), (0, 0), (0, 3), (2, 0), (2, 3)}
>>> puzzel.isopgelost()
True

De oplossingen die je indient, worden ook getest aan de hand van deze puzzels.

3 × 3 puzzel5 × 5 puzzel6 × 6 puzzel7 × 7 puzzel8 × 8 puzzel9 × 9 puzzel10 × 10 puzzel

Bronnen