Het spelletje "∞ lus" wordt gespeeld met $$n \times m$$ tegels, gerangschikt in een $$n \times m$$ rooster met $$n$$ rijen en $$m$$ kolommen. Er zijn in totaal 16 verschillende tegels.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Elke tegel kan met andere woorden aansluitingen hebben naar boven, naar rechts, naar beneden, en naar links. De geldige tegels worden dus gevormd door alle mogelijke combinaties van aansluitingen in deze vier richtingen, inclusief de tegel zonder aansluitingen.

Bij aanvang van het spel wordt het rooster gevuld met een selectie van deze tegels. De speler kiest vervolgens een tegel, en draait deze 90° in wijzerzin of tegenwijzerzin. Als we bijvoorbeeld de tegel in wijzerin draaien dan bekomen we de tegel , de tegel wordt , maar de tegel blijft . De speler kan deze procedure eindeloos blijven herhalen.

Het doel van het spel is om een gesloten circuit te vormen: elke aansluiting moet connecteren op een aansluiting van een naburige tegel. Als een tegel bijvoorbeeld een aansluiting naar rechts heeft, dan moet de tegel die er rechts van ligt in het rooster een aansluiting naar links hebben. Bij wijze van illustratie toont onderstaand videofragment een speler die puzzels uit het spelletje "∞ lus" probeert op te lossen.

Opgave

Een eenvoudige manier om de tegels voor te stellen — zonder gebruik te moeten maken van Unicode-karakters — is door gebruik te maken van een bitmasktechniek. Hierbij wordt elke tegel voorgesteld als een natuurlijk getal uit het interval [0, 15] door gebruik te maken van de volgende code:

Dit wordt grafisch voorgesteld in onderstaande figuur.

tegel
Bitmaptechniek waarmee elke tegel kan voorgesteld worden als een natuurlijk getal uit het interval [0, 15].

Op die manier kan de tegel voorgesteld worden als het getal $$1 + 4 + 8 = 13$$. Als we de binaire voorstelling van het getal bekijken, dan zien we dat

Zo komt 13 overeen met het binaire getal 1101, waaruit we direct kunnen afleiden dat de tegel aansluitingen heeft naar alle richtingen behalve naar rechts.

Gevraagd wordt om een klasse Tegel te definiëren waarmee tegels uit het spelletje "∞ lus" kunnen voorgesteld worden. Bij het instantiëren van objecten van deze klasse kan een natuurlijk getal (standaardwaarde: 0) doorgegeven worden, dat de tegel omschrijft op basis van de bitmasktechniek die hierboven werd beschreven. Indien het gegeven getal niet in het interval [0, 15] ligt, dan moet een AssertionError opgeworpen worden met de boodschap ongeldige tegel. De objecten van de klasse Tegel moeten minstens de volgende eigenschappen hebben:

Voorts moet de klasse Tegel minstens de volgende methoden ondersteunen:

Definieer ook nog een klasse OneindigeLus waarmee een puzzel van het spelletje "∞ lus" kan voorgesteld worden. Bij het instantiëren van objecten van deze klasse moeten twee argumenten doorgegeven worden: i) een array van natuurlijke getallen uit het interval [0, 15] die de tegels in het rooster voorstellen, uitgelezen van links naar rechts en van boven naar onder, en ii) een natuurlijk getal dat aangeeft hoeveel kolommen het rooster telt. Indien deze argumenten niet corresponderen met een geldig rooster van tegels, dan moet een AssertionError opgeworpen worden met de boodschap ongeldig rooster. De klasse OneindigeLus moet minstens de volgende methoden ondersteunen:

Voorbeeld

>>> const tegel = new Tegel(11);
>>> tegel.boven;
true
>>> tegel.rechts;
true
>>> tegel.onder;
false
>>> tegel.links;
true
>>> tegel.toString();
"┻"
>>> tegel.draai().toString();
"┣"
>>> tegel.draai().draai().toString();
"┫"
>>> tegel.draai(false).toString();
"┳"
>>> tegel.draai(false).draai(false).toString();
"┻"

>>> const spel = new OneindigeLus([9, 12, 12, 6, 10, 13, 13, 5, 3, 3, 9, 3], 4);
>>> spel.toString();
"┛┓┓┏\n━┫┫┃\n┗┗┛┗"
>>> spel.opgelost();
false
>>> spel.draai(0, 0).draai(0, 0).draai(0, 2, false).draai(0, 3).toString();
"┏┓┏┓\n━┫┫┃\n┗┗┛┗"
>>> spel.opgelost();
false
>>> spel.draai(1, 0).draai(1, 1).draai(1, 1).toString();
"┏┓┏┓\n┃┣┫┃\n┗┗┛┗"
>>> spel.opgelost();
false
>>> spel.draai(2, 1, false).draai(2, 2).draai(2, 3, false).toString();
"┏┓┏┓\n┃┣┫┃\n┗┛┗┛"
>>> spel.opgelost();
true

De vier stringvoorstellingen van roosters met tegels uit bovenstaande interactieve sessie worden hieronder grafisch weergegeven.

┛┓┓┏          ┏┓┏┓          ┏┓┏┓          ┏┓┏┓
━┫┫┃          ━┫┫┃          ┃┣┫┃          ┃┣┫┃
┗┗┛┗          ┗┗┛┗          ┗┗┛┗          ┗┛┗┛