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.
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:
begin met 0
als de tegel een aansluiting naar boven heeft, tel er dan 1 bij op
als de tegel een aansluiting naar rechts heeft, tel er dan 2 bij op
als de tegel een aansluiting naar onder heeft, tel er dan 4 bij op
als de tegel een aansluiting naar links heeft, tel er dan 8 bij op
Dit wordt grafisch voorgesteld in onderstaande figuur.
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
het eerste cijfer vanaf rechts aangeeft of de tegel een aansluiting naar boven heeft
het tweede cijfer vanaf rechts aangeeft of de tegel een aansluiting naar rechts heeft
het derde cijfer vanaf rechts aangeeft of de tegel een aansluiting naar onder heeft
het vierde cijfer vanaf rechts aangeeft of de tegel een aansluiting naar links heeft
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:
boven: Booleaanse waarde die aangeeft of de tegel een aansluiting naar boven heeft
rechts: Booleaanse waarde die aangeeft of de tegel een aansluiting naar rechts heeft
onder: Booleaanse waarde die aangeeft of de tegel een aansluiting naar onder heeft
links: Booleaanse waarde die aangeeft of de tegel een aansluiting naar links heeft
Voorts moet de klasse Tegel minstens de volgende methoden ondersteunen:
Een methode toString die een stringvoorstelling van de tegel teruggeeft. Deze stringvoorstelling bestaat uit het Unicode-karakter op de positie in de tabel uit de inleiding van deze opgave die overeenkomt met de voorstelling van de tegel als natuurlijk getal.
Een methode draai waaraan een Booleaanse waarde kan doorgegeven worden (standaardwaarde: true). Indien de waarde true wordt doorgegeven, dan moet de methode de tegel 90° in wijzerzin draaien. Anders moet de tegel 90° in tegenwijzerzin gedraaid worden. De methode moet een verwijzing teruggeven naar het object waarop de methode wordt aangeroepen.
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:
Een methode toString die een stringvoorstelling van het rooster met tegels teruggeeft. In deze stringvoorstelling wordt elke rij voorgesteld als de samenstelling van de stringvoorstellingen van de individuele tegels op de rij (van links naar rechts), en worden de verschillende rijen van elkaar gescheiden door newlines.
Een methode draai waaraan de rij- en kolomindex van een cel uit het rooster moeten doorgegeven worden. Hierbij worden de rijen van boven naar onder, en de kolommen van links naar rechts geïndexeerd vanaf 0. Bovendien kan als derde argument ook nog een Booleaanse waarde doorgegeven worden (standaardwaarde: true). Indien de waarde true wordt doorgegeven, dan moet de methode de tegel op de aangegeven positie in het rooster 90° in wijzerzin draaien. Anders moet deze tegel 90° in tegenwijzerzin gedraaid worden. De methode moet een verwijzing teruggeven naar het object waarop de methode wordt aangeroepen. Indien de gegeven rij- en kolomindex geen geldige positie van een tegel in het rooster aanwijzen, dan moet een AssertionError opgeworpen worden met de boodschap ongeldige positie.
Een methode opgelost waaraan geen argumenten moeten doorgegeven worden. De methode moet een Booleaanse waarde teruggeven, die aangeeft of de tegels in het rooster een gesloten circuit vormen, zoals omschreven in de inleiding van deze opgave.
>>> 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.
┛┓┓┏ ┏┓┏┓ ┏┓┏┓ ┏┓┏┓ ━┫┫┃ ━┫┫┃ ┃┣┫┃ ┃┣┫┃ ┗┗┛┗ ┗┗┛┗ ┗┗┛┗ ┗┛┗┛