wiki.neuro.tu-berlin.de

Slitherlink

Slitherlink

Slitherlink oder Suriza (japanisch スリザーリンク - surizā rinku) ist ein japanisches Puzzle. Es wurde erstmals 1989 vom Sudoku-Herausgeber Nikoli veröffentlicht. Es ist ein nachgewiesen NP-vollständiges Problem[1].

Spielregeln

Abb. 1 - Ein gelöstes Slitherlink-Puzzle.

Das Spielfeld ist ein m x n Gittergraph. In den Zellen können Zahlen von 0 bis 3 stehen. Das Ziel ist es, benachbarte Knoten so zu verbinden, dass ein Zyklus entsteht. Dabei gilt es, die folgenden drei Regeln zu beachten:[2]

  1. Verbinde benachbarte Knoten mit horizontalen oder vertikalen Kanten, sodass genau ein Zyklus entsteht.
  2. Die Zahlen geben an, wie viele Linien eine Zelle umgeben müssen. Leere Zellen können durch beliebig viele Linien umgeben werden.
  3. Der Zyklus kreuzt sich nicht selbst nicht und es gibt keine Verzweigungen.

Gute Slitherlink-Puzzles haben eine eindeutige Lösung. In Abbildung 1[3] ist ein kleines Slitherlink-Puzzle dargestellt.

Spielvarianten

Abb. 2 - Ein gelöstes Hexagonal Slitherlink-Puzzle.

Hexagonal Slitherlink[4]

Es wird nach den selben Regeln gespielt, aber das Spielfeld besteht aus Hexagonen. Die Zahlen in den Zellen können entsprechend größer sein. In dem Beispiel aus Abbildung 2[4:1] gibt es auch Zellen mit der Nummer 4 oder 5.

No-Square Slitherlink[5]

Es gilt neben den Standardregeln noch die Zusatzregeln, dass es keinen 2x2 Bereich an Zellen innerhalb des Zyklus geben darf. Lösungen die zuvor bei Slitherlink möglich waren, können dadurch wie in Abbildung 3[5:1] verboten werden.

Colorlink[6]

Die Slitherlink-Regeln werden um die Folgenden ergänzt:

Abb. 3 - Ein gelöstes No-Square Slitherlink-Puzzle. Die roten Linien deuten einen Zyklus an, der ohne Sonderregel erlaubt wäre. Abbildung angepasst.
Abb. 4 - Ein gelöstes Colorlink-Puzzle.

Lösungsstrategien

Für gewöhnlich geht man so vor, dass man damit beginnt kleinere eindeutige Teillösungen zu bestimmen, um diese dann zu einem geschlossenen Kreis zu verbinden[7]. Zudem ist es sinnvoll, Linien auszustreichen, die nicht Teil der Lösung sein können. In Abbildung 5[2:1] ist die Progression beim Lösen von Slitherlink exemplarisch dargestellt.

Abb. 5 - Schrittweises Lösen eines Slitherlink-Puzzles. Beginnend mit kleinen Teillösungen.

Ausgewählte Linien stimmen mit Zellennummer überein

Für den Fall, dass die Anzahl ausgewählter Linien mit der Nummer einer Zelle übereinstimmt, können alle anliegenden und noch nicht gewählten Kanten ausgeschlossen werden. Dies ist bei Zellen mit der Nummer 0 wie in Abbildung 6[8] leicht zu erkennen.

Abb. 6 - 0-Zellen auf dem Spielfeld.

0 oder 2 angrenzende Linien an jedem Knotenpunkt

Die Erkenntnis, dass jeder Knoten nur 0 oder 2 angrenzende Linien hat, führt zu vielen verschiedenen Deduktionsstrategien, wie z.B. die Folgenden.

Zellen mit 3:

Abb. 7 - 3-Zelle mit angrenzender 0-Zelle.
Abb. 8 - 3-Zelle mit diagonaler 0-Zelle.
Abb. 9 - 3-Zelle mit benachbarter 3-Zelle.

Diese Regel gilt nicht für triviale Slitherlink-Puzzles, welche durch einen einfachen Zyklus um zwei benachbarte 3-Zellen gelöst werden können, weil es keine anderen Zahlen gibt.[9]

Zellen mit 1:

Abb. 10 - 1-Zelle an bestehender Teillösung.

Spielfeldecken:

Abb. 11 - Eckzellen mit Zahlen.

Lösungsansatz mithilfe von ZDDs

Basierend auf dem SIMPATH-Algorithmus zur Repräsentation von s-t Pfaden als ZDD haben Yoshinaka et. al.[10] einen Solver für Instanzen von Slitherlink entworfen. Es soll ein ZDD generiert werden, welches alle Lösungen für eine gegebene Slitherlinkinstanz darstellt. Mit anderen Worten sollen alle Zellen entsprechend ihrer Zahl abgedeckt sein.

Definition Slitherlinkinstanz

Eine Instanz für Slitherlink ist ein Tupel aus einem Eingabegraphen G=(V,E) und einer partiellen Funktion h(E'): 2^E \rightharpoonup \mathbb{N}, wobei h(E')\leq |E'|. Für ein E' \subseteq E bedeutet h(E')=c dabei, dass genau c Kanten aus E' in der Lösung enthalten sein müssen. Eine Lösung für eine gegebene Instanz (G, h) ist ein Kreis C unter der Bedingung, dass für alle E' aus der Definitionsmenge von h h(E')= | C \cap E'| gilt.

Pseudocode (angepasst)

initialize mate;
initialize count;
create root labeled with first edge;
create 0-terminal, 1-terminal;
Q = new Queue;
Q.enqueue(root);
while Q not empty
		node = Q.enqueue;
    e = edge node is labeled with;
    if node has fixed end or is incompatible with h
    		create 0-arc from node to 0-terminal;
    else 
    		childnode = create new node;
        create 0-arc from node to childnode;
    if taking e forms a cycle matching h
    		create 1-arc from node to 1-terminal;
		else if taking e declines state of n or is incompatible with h
    		create 1-arc from node to 0-terminal;
		else 
    		childnode = create new node;
        create 0-arc from node to childnode    		

Arbeitsweise

Der Algorithmus iteriert ähnlich wie SIMPATH in einer Art Breitensuche über die Kanten. Auch hier müssen die Kanten zunächst in einer totalen Ordnung sein.

Es wird eine Funktion mate : V^{\geq e_i} \rightarrow V \cup \{0\} anstelle der mate-Tabelle verwendet, um den Zustand eines Knoten im ZDD zu speichern. V^{\geq e_i} bedeutet, dass die Funktion nur für Knoten aus Kanten definiert ist, die entsprechend der Kantenordnung größer oder gleich der aktuell betrachteten Kante e_i sind. Informationen über bereits untersuchte Kanten müssen also nicht gemerkt werden. Dabei gilt:

Neben der mate-Funktion gibt es eine Funktion count: \text{Dom}(h) \rightarrow \mathbb{N} für jeden Knoten des ZDDs. Diese Funktion zählt für alle E' \subseteq E in der Definitionsmenge von h, die Anzahl bereits abgedeckter Kanten. Am Anfang, wenn noch keine Kanten ausgewählt wurden, ist für alle E' count(E') = 0.

Intitial ist mate für alle v \in V definiert als mate(v)=v. Wie bei SIMPATH werden zu Beginn der Wurzelknoten und die Endknoten (0-terminal und 1-terminal) generiert und dann alle Kanten über die Queue iteriert. Für jeden Knoten, der neu generiert wird und in die Queue hinzugefügt wird, wird zusätzlich der Zustand mit mate und count gespeichert. Nachdem alle Kanten untersucht wurden, werden die Lösungen durch den 1-terminal Knoten repräsentiert, d.h. alle gültigen Pfade zu 1-terminal repräsentieren eine Lösung für die Slitherlinkinstanz.

mate updaten:
Nach Wahl einer Kante j-m (1-arc) wird mate wie folgt angepasst:

  1. j^* = mate(j)
  2. m^* = mate(m)
  3. mate(j)=0
  4. mate(m)=0
  5. mate(j^*) = m^*
  6. mate(m^*)= j^*

Außerdem wird der Definitionsbereich von mate so angepasst, dass nur noch Knoten aus V^{\geq e_{i+1}} betrachtet werden. Also nur noch Knoten größer oder gleich der nächsten zu untersuchenden Kante e_{i+1}. Dies gilt unabhängig davon, ob die Kante gewählt wird oder nicht (0-arc und 1-arc).

count updaten:
Nach Wahl einer Kante j-m (1-arc), wird der Zähler für jedes E' \in \text{Dom}(h) um 1 erhöht, wenn j-m \in E'.

Definitionen:
Es gibt einen festen Endpunkt für eine Kante j-m, wenn mate(v) \neq 0 und mate(v) \neq v für ein v \in \{ j, m\} \setminus V^{\geq e_{i+1}}.

Der Zustand eines Knoten ist inkompatibel mit h, falls es ein E' \in \text{Dom}(h) gibt, sodass count(E')>h(E') oder count(E') + |E' \cap E^{\geq e_{i+1}}| < h(E'), wobei E^{\geq e_{i+1}} alle Kanten meint, die gemäß Ordnung größer als die aktuelle Kante e_i sind. Der Zustand ist also inkompatibel, wenn entweder eine Zelle "überabgedeckt" ist oder mit den noch zu untersuchenden Kanten nicht mehr alle Zellen abgedeckt werden können.

Das Auswählen einer Kante e_i erzeugt einen Kreis, wenn für alle v \in \text{Dom}(mate) mate(v)=u falls e_i=\{u,v\} und mate(v)=v oder mate(v)=0 falls v \notin e_i.

Das Auswählen einer Kante erfüllt h, wenn alle Zellen genau abgedeckt sind (count = h).

Das Auswählen einer Kante j-m wird abgelehnt, wenn mate(j)=0, mate(m)=0, mate(m)=j oder mate(j)=m.

Folgezustände erkennen:
Innerhalb der while-Schleife (Z. 8-21 im Pseudocode) werden verschiedene Bedingungen geprüft, um den passenden Folgeknoten im ZDD für den 0-arc bzw. 1-arc zu finden.

Fall 1: Die aktuelle Kante soll nicht ausgewählt werden (0-arc).

Fall 2: Die aktuelle Kante soll ausgewählt werden (1-arc).

Abb. 12 - Einfaches Slitherlink-Puzzle. Es wurden noch keine Linien eingezeichnet. Eigene Abbildung.

Beispiele:
Das einfache Beispiel in Abbildung 12 wird betrachtet und verschiedene Zustände, die bei der Anwendung des Algorithmus auftreten werden, werden untersucht. Die Kantenordnung wird entsprechend der angegebenen Knotennummerierung betrachtet, z.B. 1-2 \leq 1-3. Seien mate' und count' die Belegung der Funktionen nach der Auswahl einer Kante (1-arc). Für dieses Beispiel gibt es 4 verschiedene Beschränkungen für die umliegenden Linien der Zellen. Sei h wie folgt definiert:

  1. Aktuelle Kante 2-5, nachdem 1-2, 1-3 und 2-4 nicht gewählt wurden (Abbildung 13).
Abb. 13 - Möglicher betrachteter Zustand. Die rot markierte Kante wird aktuell untersucht. Graue Linien sind noch nicht untersuchte Kanten. Keine Linie heißt, die Kante wurde untersucht aber nicht gewählt (0-arc). Eigene Abbildung.
j m mate(1, \dots, 9) mate'(1, \dots, 9) count(E_1, \dots, E_4) count'(E_1, \dots, E_4)
2 5 1 2 3 4 5 6 7 8 9 1 5 3 4 2 6 7 8 9 0 0 0 0 1 1 0 0

Der Zustand des Knoten ist inkompatibel mit h. Für E_1 \subseteq E ist count(E_1)=0. Die nächste zu untersuchende Kante wäre 3-5, d.h. count(E_1) + |E_1 \cap E^{\geq 3-5}|= 0 + 1 = 1 < h(E_1). Falls auch die Kante 2-5 nicht genommen wird, gibt es nur noch eine Kante, um count(E_1)=2 zu erreichen, aber zwei wären notwendig. Nicht-Wahl der Kante führt also zur Unlösbarkeit, der 0-arc führt zu 0-terminal.

Allerdings führt das Auswählen von 2-5 auch zur Unlösbarkeit. 2-5 ist die letzte Kante über den Knoten 2 des Eingabegraphen. Um einen Kreis zu erzeugen, wird jedoch eine weitere Kante mit 2 als Endpunkt benötigt. Die nächste Kante gemäß Kantenordnung wäre 3-5, d.h. für 2 \in \{2,5\} \setminus V^{\geq 3-5} ist mate'(2) = 5. Es gibt einen festen Endpunkt, also führt auch der 1-arc zu 0-terminal.

  1. Aktuelle Kante 2-5, nachdem 1-2, 1-3 und 2-4 gewählt wurden (Abbildung 14).
Abb. 14 - Möglicher betrachteter Zustand. Durchgezogene Linie heißt, die Kante wurde untersucht und gewählt (1-arc). Eigene Abbildung.
j m mate(1, \dots, 9) mate'(1, \dots, 9) count(E_1, \dots, E_4) count'(E_1, \dots, E_4)
2 5 0 0 4 3 5 6 7 8 9 - 2 1 0 0 -

Das Auswählen von 2-5 wird abgelehnt, denn mate(2)=0. Der Knoten 2 des Eingabegraphen wurde bereits zweimal besucht, ein drittes Mal ist verboten. Der 1-arc führt also zu 0-terminal. Die Nicht-Wahl (0-arc) von 2-5 ist hingegen in diesem Fall möglich und ein neuer Knoten im ZDD wird generiert.

  1. Aktuelle Kante 8-9, nachdem 1-2, 1-3, 2-4, 3-6, 4-7, 6-8 und 7-9 gewählt wurden (Abbildung 15).
Abb. 15 - Möglicher betrachteter Zustand. Eigene Abbildung.
j m mate(1, \dots, 9) mate'(1, \dots, 9) count(E_1, \dots, E_4) count'(E_1, \dots, E_4)
8 9 0 0 0 0 5 0 0 9 8 - 2 2 2 1 2 2 2 2

Die Wahl von 8-9 erzeugt einen Kreis, denn mate(8)=9, mate(9)=8, mate(5)=5 und mate(v)=0 sonst. Außerdem ist count'=h für E_1, E_2, E_3 und E_4, h wird also erfüllt. Es wurde eine Lösung für die Slitherlinkinstanz gefunden, es führt ein 1-arc zu 1-terminal.

Bei einen guten Slitherlink-Puzzle mit nur einer Lösung, kann der Algorithmus bei dem ersten h-erfüllenden gefundenen Kreis abgebrochen werden.

Vergleich mit anderen Solvern

Die Autoren haben ihren Algorithmus für verschiedene Instanzen mit dem SAT-Solver Sugar und dem Integer Programming Solver CPLEX verglichen. Im Ergebnis schlägt der ZDD-Algorithmus für viele Instanzen Sugar. Es gibt auch Beispiele, bei denen Sugar zeiteffizienter war. CPLEX ist in manchen Fällen schneller. Die Instanzen wurden auch mit einem heuristische Solver slink getestet. Dieser war für alle Instanzen deutlich schneller. Laut den Autoren seien diese Ergebnisse damit zu erklären, dass Sugar und CPLEX eher für allgemeinere Zwecke entwickelt wurden, während slink speziell für Slitherlink designt wurde und die ZDD-Lösung eher dazwischen liegt.

Instance Graph size Time Sugar Time CPLEX Time ZDD-Algo Time slink
BS1 11x11 5,460 0,07 0,116 0,001
BS12 11x11 4,696 0,28 0,384 0,004
BS25 11x11 6,496 0,12 0,060 0,001
BS37 11x11 8,773 0,14 0,044 0,004
BS43 19x11 8,349 0,17 0,060 0,001
BS54 19x11 7,380 0,40 0,304 0,008
BS68 25x15 12,433 0,39 0,384 0,004
BS77 25x15 13,281 0,90 0,376 0,004
BS89 37x21 48,035 1,56 9,329 0,016
BS96 37x21 186,612 3,07 26,286 0,104
S10 37x21 1411,944 41,43 4569,330 0,036
C95 32x46 1076,839 95,93 - 0,088

Laufzeit angegeben in Sekunden für das Lösen von Slitherlink. Für C95 konnte der ZDD-Solver keine Lösung finden aufgrund nicht ausreichenden Speichers.

Lösungsansatz mit SMT-Solver

Eine Lösungsmöglichkeit ist der Constrained-Based Ansatz dabei generiert man aus einem gegebenen Spielfeld eine aussagenlogische Formel und sucht eine Lösung mithilfe von bekannten SAT oder SMT Solvern. Miyauchi und Tanaka[11] haben eine SMT-Lösung entwickelt, die für einige Fälle bessere Ergebnisse als vorherige Slitherlink-Solver erreichen konnte.

Referenzen


  1. T. Yato und T. Seta, "Complexity and completeness of finding another solution and its application to puzzles," IEICE transactions on fundamentals of electronics, communications and computer sciences, Jg. 86, Nr. 5, S. 1052–1060, 2003. pdf ↩︎

  2. Nikoli. "Slitherlink.” https://www.nikoli.co.jp/en/puzzles/slitherlink/ ↩︎ ↩︎

  3. Wikipedia. "Suriza." https://de.wikipedia.org/wiki/Suriza ↩︎

  4. puzzlephil. "Slitherlink-Specials." https://puzzlephil.com/puzzles/slitherlinkspecials/de/ ↩︎ ↩︎

  5. janko. "No-Square Slitherlink." https://www.janko.at/Raetsel/Varianten/017.a.htm ↩︎ ↩︎

  6. janko. "Colorlink." https://www.janko.at/Raetsel/Varianten/019.a.htm ↩︎ ↩︎

  7. Wikipedia. "Slitherlink." https://en.wikipedia.org/wiki/Slitherlink#Solution_methods ↩︎

  8. Conceptis. "Slitherlink Techniken." https://www.conceptispuzzles.com/de/index.aspx?uri=puzzle/slitherlink/techniques, ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  9. D. Westreicher, „Slitherlink Reloaded," Bachelorarbeit, 2011. pdf ↩︎

  10. R. Yoshinaka, T. Saitoh, J. Kawahara, K. Tsuruma, H. Iwashita und S. Minato, "Finding All Solutions and Instances of Numberlink and Slitherlink by ZDDs," Algorithms, Jg. 5, Nr. 2, S. 176–213, 2012, doi: 10.3390/a5020176. pdf ↩︎

  11. T. Miyauchi und K. Tanaka, "Solving Slitherlink with FPGA and SMT Solver," Journal of Information Processing, Jg. 28, S. 959–969, 2020, doi: 10.2197/ipsjjip.28.959. pdf ↩︎