Überprüfen Sie eine Tower of Hanoi-Lösung


29

Wenn Sie nicht wissen, was der Turm von Hanoi ist, erkläre ich es kurz: Es gibt drei Stangen und einige Scheiben, von denen jede eine andere Größe hat. Am Anfang befinden sich alle Scheiben in sortierter Reihenfolge auf dem ersten Turm: Die größte befindet sich unten, die kleinste oben. Ziel ist es, alle Scheiben auf die dritte Stange zu bringen. Klingt einfach? Hier ist der Haken: Sie können keine CD auf eine CD legen, die kleiner als die andere ist. Sie können immer nur eine Scheibe auf einmal in der Hand halten, um sie auf eine andere Stange zu bewegen, und Sie können die Scheibe nur auf Stangen legen, nicht auf den Tisch, Sie hinterhältiger Bastard.

ASCII-Beispiellösung:

  A      B      C
  |      |      |      
 _|_     |      |      
__|__    |      |


  A      B      C
  |      |      |      
  |      |      |      
__|__   _|_     |


  A      B      C
  |      |      |      
  |      |      |      
  |     _|_   __|__


  A      B      C
  |      |      |      
  |      |     _|_     
  |      |    __|__      

Herausforderung

Es gibt drei Stäbe mit den Bezeichnungen A, B und C. (Sie können sie auch mit 1,2 bzw. 3 bezeichnen, wenn das hilft) Am Anfang befinden sich alle n Scheiben auf Stab A (1).

Ihre Herausforderung besteht darin, eine Lösung für den Turm von Hanoi zu überprüfen. Sie müssen sicherstellen, dass:

  1. Am Ende befinden sich alle n Scheiben auf Stab C (3).
  2. Für eine bestimmte Disc in einem bestimmten Zustand befindet sich keine kleinere Disc darunter.
  3. Keine offensichtlichen Fehler wie der Versuch, Scheiben von einer leeren Stange zu nehmen oder Scheiben auf nicht vorhandene Stangen zu bewegen.

(Die Lösung muss nicht optimal sein.)

Eingang

Ihr Programm erhält zwei Eingaben:

  1. Die Anzahl der Discs n (eine ganze Zahl)
  2. Die ausgeführten Züge, die aus einer Reihe von Tupeln bestehen: (Turm, von dem die derzeit oberste Scheibe genommen wird), (Turm, zu dem diese Scheibe genommen wird), wobei sich jedes Tupel auf einen Zug bezieht. Sie können wählen, wie sie dargestellt werden. Zum Beispiel so etwas wie die folgenden Darstellungsweisen der Lösung für n = 2, die ich oben in ASCII gezeichnet habe. (Ich werde den ersten in den Testfällen verwenden, weil es für die Augen einfach ist):

    A-> B; A-> C; B-> C

    [("A", "B"), ("A", "C"), ("B", "C")]

    [(1,2), (1,3), (2,3)]

    "ABACBC"

    [1,2,1,3,2,3]

Ausgabe

  • Wahrheit, wenn die Bedingungen, die unter "Herausforderung" zu finden sind, gelten.

  • Falsch, wenn nicht.

Testfälle:

Wahr:

n=1, "A->C"

n=1, "A->B ; B->C"

n=2, "A->B ; A->C ; B->C"

n=2, "A->C ; C->B ; A->C ; B->C"

n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"

Falsch:

3. Vorschlag von @MartinEnder, 7. Vorschlag von @Joffan

n=1, "A->B"

n=1, "C->A"

n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=2, "A->B ; A->C ; C->B"

n=2, "A->C ; A->B ; C->B ; B->A"

n=2, "A->C ; A->C"

n=3, "A->B ; A->D; A->C ; D->C ; A->C"

n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"

n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"

n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"

Dies ist Code-Golf , die kürzeste Lösung gewinnt. Es gelten Standardregeln und Regelungslücken. Keine Batterien enthalten.


Ist es auch in Ordnung , wenn die zweite Eingabe Ihrer Methode dargestellt werden kann, wobei jedoch Zahlen anstelle von Buchstaben (dh A=1, B=2, C=3, etc.)?
R. Kap

1
Darf ich die Eingaben auf Null setzen?
Rohan Jhunjhunwala

1
Ist es in Ordnung, wenn ein Fehler ausgelöst wird, wenn eine Platte von einem leeren oder nicht vorhandenen Stab entnommen wird?
R. Kap

1
Können wir davon ausgehen, dass es keine Non-Moves wie geben wird A->A?
Martin Ender

2
@Kobi du musst moving discs to nonexistant rods.ja natürlich D
nachsehen

Antworten:


7

Retina , 84 80 Bytes

-5 Bytes dank Martin Ender

~
 ~$'
$
ABC
{`^(.)(.*)( ~+)\1
$3$2$1
}`^(\W+)(\w)(.*)(?<=\1~+|\w)\2
$3$1$2
^AB 

Probieren Sie es online! (plus 5 Bytes für zeilenweise Tests)

Der Code simuliert ein vollständiges Spiel.

  • Die Eingabe erfolgt als ACABCBACBABCAC~~~.
    ~~~bedeutet drei Scheiben.
  • Die ersten vier Zeilen wandeln die Eingabe in das Spielformat: ACABCBACBABCAC ~~~ ~~ ~ABC.
    Am Anfang hat die A-Stange alle 3 Scheiben und die B- und C-Stangen sind leer.
  • Als nächstes haben wir eine Schleife von zwei Schritten:
    • Nehmen Sie den ersten Buchstaben in der Zeile, der den nächsten Quellstab angibt. Finden Sie diese Stange und nehmen Sie die letzte Scheibe ein. Entfernen Sie den Buchstaben und schieben Sie die Scheibe in die Ecke (heben Sie sie auf).
      In out Beispiel nach dem ersten Schritt wird der Text wie folgt aussehen: ~CABCBACBABCAC ~~~ ~~ABC.
    • In der zweiten Stufe finden wir die Zielstange und bewegen die Scheibe dorthin. Wir bestätigen die Stange leer ist, oder hat eine größere Scheibe an der Spitze: ABCBACBABCAC ~~~ ~~AB ~C.
  • Zum Schluss bestätigen wir, dass die Stäbe A und B leer sind - dies bedeutet, dass sich alle Scheiben in C befinden (es gibt ein zusätzliches Leerzeichen in der letzten Zeile).

Wow, das ist beeindruckend
Rohan Jhunjhunwala

17

Retina , 167 165 157 150 123 Bytes

Das sieht total nach einer Herausforderung aus, die mit einem einzigen regulären Ausdruck gelöst werden sollte ... (Trotz der Überschrift "Retina" ist dies nur ein regulärer Ausdruck in Vanilla .NET, der mit gültigen Eingaben übereinstimmt).

^(?=\D*((?=(?<3>1+))1)+)((?=A(?<1-3>.+)|B(?<1-4>.+)|C(?<1-5>.+)).(?=A.*(?!\3)(\1)|B.*(?!\4)(\1)|C.*(?!\5)(\1)).)+(?!\3|\4)1

Eingabeformat ist die Liste der Anweisungen des Formulars AB, gefolgt von nunärem Verwenden der Ziffer 1. Es gibt keine Trennzeichen. Die Ausgabe ist 1gültig und 0ungültig.

Probieren Sie es online! (Die ersten beiden Zeichen ermöglichen eine durch Zeilenvorschub getrennte Testsuite.)

Alternative Lösung, gleiche Byteanzahl:

^(?=\D*((?=(?<3>1+))1)+)((?=A(?<1-3>.+)|B(?<1-4>.+)|C(?<1-5>.+)).(?=A.*(?!\3)(\1)|B.*(?!\4)(\1)|C.*(?!\5)(\1)).)+(?<-5>1)+$

Dies kann möglicherweise durch die Verwendung verkürzt werden 1, 11und 111statt A, Bund Caber ich werde später in diesem Blick haben. Es könnte auch kürzer sein, das Programm in mehrere Phasen aufzuteilen, aber wo liegt die Herausforderung dabei? ;)

Erläuterung

Diese Lösung nutzt die Bilanzkreise von .NET in hohem Maße. Eine vollständige Erklärung finden Sie in meinem Beitrag zum Stapelüberlauf. Das Wesentliche ist jedoch, dass es sich bei Erfassungsgruppen in .NET um Stapel handelt, bei denen jede neue Erfassung eine andere Teilzeichenfolge überträgt und bei denen es auch möglich ist, erneut von einem solchen Stapel zu springen. Auf diese Weise können Sie verschiedene Mengen in einer Zeichenfolge zählen. In diesem Fall können wir die drei Stäbe direkt als drei verschiedene Erfassungsgruppen implementieren, wobei jede Disc durch eine Erfassung dargestellt wird.

Um die Scheiben zwischen den Stäben hin und her zu bewegen, verwenden wir eine seltsame Besonderheit der (?<A-B>...)Syntax. Normalerweise wird dabei ein Capture vom Stapel gezogen Bund Adie Zeichenfolge zwischen diesem Capture und dem Anfang dieser Gruppe auf den Stapel gelegt . So (?<A>a).(?<B-A>c)abgestimmt gegen abcverlassen würde Aleer und Bmit b(im Gegensatz zu c). Aufgrund von .NET-Lookbehinds mit variabler Länge ist es jedoch möglich, dass sich die Captures von (?<A>...)und (?<B-A>...)überlappen. Aus welchem ​​Grund auch immer, wenn dies der Fall ist, wird der Schnittpunkt der beiden Gruppen aufgeschoben B. Ich habe dieses Verhalten im Abschnitt "Erweitert" über Bilanzkreise in dieser Antwort detailliert beschrieben .

Auf zum Regex. Rods A, Bund Centsprechen den Gruppen 3, 4und 5in dem regulären Ausdruck. Beginnen wir mit der Initialisierung von rod A:

^                 # Ensure that we start at the beginning of the input.
(?=               # Lookahead so that we don't actually move the cursor.
  \D*             # Skip all the instructions by matching non-digit characters.
  (               # For each 1 at the end of the input...
    (?=(?<3>1+))  # ...push the remainder of the string (including that 1)
                  # onto stack 3.
  1)+
)

Wenn zB die Eingabe mit endet 111, enthält Gruppe 3 / Stab Ajetzt die Liste der Captures [111, 11, 1](die obere befindet sich rechts).

Das nächste Bit des Codes hat die folgende Struktur:

(
  (?=A...|B...|C...).
  (?=A...|B...|C...).
)+

Jede Iteration dieser Schleife verarbeitet einen Befehl. Die erste Abwechslung zieht eine Scheibe von der gegebenen Stange (auf eine temporäre Gruppe), die zweite Abwechslung legt diese Scheibe auf die andere gegebene Stange. Wir werden gleich sehen, wie das funktioniert und wie wir sicherstellen, dass der Umzug gültig ist.

Nehmen Sie zuerst eine Disc von der Source-Stange:

(?=
  A(?<1-3>.+)
|
  B(?<1-4>.+)
|
  C(?<1-5>.+)
)

Dies verwendet das seltsame Gruppenschnittverhalten, das ich oben beschrieben habe. Beachten Sie, dass Gruppe 3, 4und 5immer halten Strings 1s am Ende der Zeichenfolge , deren Länge entspricht die Größe der Scheibe. Wir verwenden nun, (?<1-N>.+)um die obere Scheibe vom Stapel zu nehmen Nund den Schnittpunkt dieser Teilzeichenfolge mit der Übereinstimmung .+auf den Stapel zu schieben 1. Da .+immer zwangsläufig das gesamte Capture abgesprungen ist N, wissen wir, dass sich dadurch einfach das Capture verschiebt.

Als nächstes legen wir diese Scheibe vom Stapel 1auf den Stapel, der dem zweiten Stab entspricht:

(?=
  A.*(?!\3)(\1)
|
  B.*(?!\4)(\1)
|
  C.*(?!\5)(\1)
)

Beachten Sie, dass wir den Stapel nicht bereinigen müssen, sondern 1die CD einfach dort lassen können, da eine neue darauf gelegt wird, bevor der Stapel erneut verwendet wird. Das heißt, wir können die (?<A-B>...)Syntax umgehen und den String einfach mit kopieren (\1). Um sicherzustellen, dass der Zug gültig ist, verwenden wir den negativen Lookahead (?!\N). Dies stellt sicher, dass es von der Position aus, an der wir die aktuelle Disc zuordnen möchten, unmöglich ist, die bereits gestapelte Disc zuzuordnen N. Dies kann nur passieren, wenn entweder a) \Nniemals übereinstimmt, weil der Stapel vollständig leer ist, oder b) the disc on top of stackN is larger than the one we're trying to match with\ 1`.

Schließlich muss nur noch sichergestellt werden, dass a) alle Anweisungen und b) die Stangen übereinstimmen Aund Bleer sind, sodass alle Discs verschoben wurden C.

(?!\3|\4)1

Wir überprüfen einfach, ob weder eine Übereinstimmung \3noch \4eine Übereinstimmung möglich ist (was nur der Fall ist, wenn beide leer sind, da jede tatsächliche Disc übereinstimmen würde ) und dass wir dann eine Übereinstimmung erzielen können, 1sodass wir keine Anweisungen ausgelassen haben.


14

Java "nur" 311 272 263 261 260 259 256 Bytes

Gespeichert 39 unzählige Bytes aufgrund @Frozn eine ältere Debug - Funktion sowie einige clevere Golf Tricks zu bemerken.

Golf Version

int i(int n,int[]m){int j=0,k=0,i=n;Stack<Integer>t,s[]=new Stack[3];for(;j<3;)s[j++]=new Stack();for(;i-->0;)s[0].push(i);for(;k<m.length;k+=2)if((t=s[m[k+1]]).size()>0&&s[m[k]].peek()>t.peek())return 0;else t.push(s[m[k]].pop());return s[2].size()<n?0:1;}

ungolfed mit Erklärung und hübschen gedruckten Stapeln bei jedem Schritt

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package codegolf;

/**
 *
 * @author rohan
 */
import java.util.Arrays;
import java.util.Stack;
public class CodeGolf {
    //golfed version
    int i(int n,int[]m){int j=0,k=0,i=n;Stack<Integer>[] s=new Stack[3];for(;j<3;j++)s[j]=new Stack();for(;i-->0;)s[0].push(i);for(;k<m.length;System.out.println(Arrays.toString(s)),k+=2)if(!s[m[k+1]].isEmpty()&&s[m[k]].peek()>s[m[k+1]].peek())return 0;else s[m[k+1]].push(s[m[k]].pop());return s[2].size()==n?1:0;}
    /** Ungolfed
        * 0 as falsy 1 as truthy
        * @param n the number of disks
        * @param m represents the zero indexed stacks in the form of [from,to,from,to]
        * @return 0 or 1 if the puzzle got solved, bad moves result in an exception
        */
    int h(int n, int[] m) {
        //declarations
        int j = 0, k = 0, i = n;
        //create the poles
        Stack<Integer>[] s = new Stack[3];
        for (; j < 3; j++) {
            s[j] = new Stack();
        }
        //set up the first tower using the "downto operator
        for (; i-- > 0;) {
            s[0].push(i);
        }
    //go through and perform all the moves
        for (; k < m.length; System.out.println(Arrays.toString(s)), k += 2) {
            if (!s[m[k + 1]].isEmpty() && s[m[k]].peek() > s[m[k + 1]].peek()) {
                return 0;//bad move
            } else {
                s[m[k + 1]].push(s[m[k]].pop());
            }
        }
        return s[2].size() == n ? 1 : 0;// check if all the disks are done
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
    //test case
        System.out.println( new CodeGolf().h(3,new int[]{0,2,0,1,2,1,0,2,1,0,1,2,0,2})==1?"Good!":"Bad!");
    }

}

Die ungolfed-Version hat eine Funktion, mit der gedruckt wird, wie die Stapel bei jedem Schritt aussehen ...

[[2, 1], [], [0]]
[[2], [1], [0]]
[[2], [1, 0], []]
[[], [1, 0], [2]]
[[0], [1], [2]]
[[0], [], [2, 1]]
[[], [], [2, 1, 0]]
Good!

Was macht System.out.println(Arrays.toString(s))das?
Frozn

Es wird die Stapel schön drucken. Gefällt
Rohan Jhunjhunwala

Whoops @Frozn das war ein Debug-Feature jetzt entfernen
Rohan Jhunjhunwala

Ich weiß, nur fragen , warum es da ist :) Sie können auch ersetzen &&mit &.
Frozn

@Frozn Das kann ich leider nicht ersetzen, da ich mich auf das Kurzschlussverhalten verlassen habe, um nicht zu versuchen, auf einen leeren Stapel zu schauen. Vielen Dank für die 39-Byte-Reduzierung
Rohan Jhunjhunwala

9

Python 2, 186 167 158 135 127 115 110 102 Bytes

n,m=input()
x=[range(n),[],[]]
for a,b in m:p=x[a].pop();e=x[b];e and 1/(p>e[-1]);e+=p,
if x[0]+x[1]:_

Übernimmt Eingaben in STDIN im folgenden Format:

(1,[(0,1),(1,2)])

Das heißt, ein Python-Tupel der Anzahl der Disks und eine Python-Liste der Tupel von (from_rod,to_rod). Wie in Python sind die umgebenden Klammern optional. Die Stäbe sind mit einem Index von Null versehen.

Zum Beispiel dieser Testfall:

n=2; "A->B ; A->C ; B->C"

würde gegeben sein als:

(2,[(0,1),(0,2),(1,2)])

Wenn die Lösung gültig ist, gibt nichts aus und tritt mit einem Exit - Code von 0. Wenn es ungültig ist, werfen eine Ausnahme und wird mit einem Exit - Code 1 einen Überwurf , IndexErrorwenn auf eine nonexistant Stange zu bewegen oder versuchen , eine Scheibe aus einem zu übernehmen Stange, auf der sich keine Discs befinden, a ZeroDivisionErrorwenn eine Disc auf einer kleineren Disc liegt oder a NameErrorwenn am Ende der ersten oder zweiten Stange noch Discs vorhanden sind.

13 Bytes gespart dank @KarlKastor!

8 Bytes gespart dank @xnor!


1
Die Überprüfung, ob jeder Stapel sortiert ist, scheint zu kompliziert. Können Sie nicht einfach überprüfen, ob die verschobene Platte größer ist als die oberste Platte des Stapels, auf den sie verschoben wurde?
XNOR

@xnor Danke, das sollte funktionieren. Füge es jetzt hinzu.
Kupfer

5

Python 2.7, 173 158 138 130 127 123 Bytes:

r=range;a,b=input();U=[r(a,0,-1),[],[]]
for K,J in b:U[J]+=[U[K].pop()]if U[J]<[1]or U[K]<U[J]else Y
print U[-1]==r(a,0,-1)

Übernimmt die Eingabe über die Standardeingabe in dem Format, (<Number of Discs>,<Moves>)in dem <Moves>sie als Array angegeben wird, das Tupel für jeden Zug enthält, die jeweils ein Paar durch Kommas getrennte Ganzzahlen enthalten. Zum Beispiel der Testfall:

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C" 

in der Post gegeben wäre gegeben als:

(3,[(0,2),(0,1),(2,1),(0,2),(1,0),(1,2),(0,2)]) 

zu meinem Programm. Gibt ein aus, IndexErrorwenn die 3. Bedingung nicht erfüllt ist, ein, NameErrorwenn die 2. Bedingung nicht erfüllt ist und Falsewenn die 1. Bedingung nicht erfüllt ist. Ansonsten Ausgänge True.


zwei Dinge: Variable Ywird nie in Ihrem Code definieren (denke ich , dass J sein soll) und U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]kürzer von 3 Zeichen , dass diestmt1 if cond else stmt2
jermenkoo

@jermenkoo Nun, ich benutze diese YVariable, um den Wert zu erhöhen, NameErrorwenn die 2. Bedingung nicht erfüllt ist. Wenn ich etwas ändern Yzu J, dann ist das NameErrornicht angehoben werden. Aus diesem Grund kann ich das auch nicht machen, U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]da dies die NameError ganze Zeit eine erhöhen würde , nicht nur wenn die 2. Bedingung nicht erfüllt ist.
R. Kap

alles klar danke für deine erklärung
Jermenkoo

5

VBA, 234 217 213 196 Bytes

Function H(N,S)
ReDim A(N)
While P<Len(S)
P=P+2:F=1*Mid(S,P-1,1):T=1*Mid(S,P,1)
E=E+(T>2):L=L+T-F
For i=1 To N
If A(i)=F Then A(i)=T:Exit For
E=E+(A(i)=T)+(i=N)
Next
Wend
H=L+9*E=2*N
End Function

Das Eingabeformat für Züge ist eine Zeichenfolge mit einer geraden Anzahl von Ziffern (012). Der Aufruf erfolgt in der Tabelle, = H ([Anzahl der Datenträger], [Zeichenfolge verschieben])

Die Anordnung A hält die Stabposition der verschiedenen Scheiben. Ein Zug aktualisiert einfach das erste Auftreten der Stangennummer "Von" in die Stangennummer "Bis". Wenn Sie zuerst auf eine "To" -Rutenscheibe oder keine "From" -Rutenscheibe stoßen, ist dies ein ungültiger Zug. Der gesamte "Stabwert" von A wird in L gehalten, was bei 2N enden muss. Fehler werden in E negativ gezählt.

Wie bei anderen Lösungen ist das "Verschieben" einer Disc von einem Turm in den gleichen Turm nicht verboten. Ich könnte es für weitere 6 Bytes verbieten.

Ergebnisse

Funktionsergebnis in der ersten Spalte (der letzte Fall n = 3 ist meine Hinzufügung unter Verwendung eines zusätzlichen Stabes).

TRUE    1   02
TRUE    1   0112
TRUE    2   010212
TRUE    2   02210212
TRUE    2   020121101202
TRUE    3   02012102101202
TRUE    4   010212012021010212102012010212

FALSE   1   01
FALSE   1   20
FALSE   2   02012102101202
FALSE   2   010221
FALSE   2   02012110
FALSE   2   0202
FALSE   3   0202012102101202
FALSE   3   0201210112101202
FALSE   3   02012102101221
FALSE   3   0103023212
FALSE   4   0102120120210102121020120102
FALSE   4   01010102121212

2

PHP, 141 Bytes

<?php $a=$argv;for($t=[$f=range($a[++$i],1),[],[]];($r=array_pop($t[$a[++$i]]))&&$r<(end($t[$a[++$i]])?:$r+1);)$t[$a[$i]][]=$r;echo$t[2]==$f;

Befehlszeilenskript, verwendet die Eingabe als Höhe und dann eine Reihe von Array-Indizes (0 indiziert), z. B. 1 0 2 oder 2 0 1 0 2 1 2 für die kürzesten Testfälle mit 1 oder 2 Höhen.
Echos 1 über wahre Fälle und nichts über falsche.
Gibt 2 Hinweise und 1 Warnung, muss also in einer Umgebung ausgeführt werden, die diese zum Schweigen bringt.


1

JavaScript (ES6), 108

n=>s=>!s.some(([x,y])=>s[y][s[y].push(v=s[x].pop())-2]<v|!v,s=[[...Array(s=n)].map(_=>s--),[],[]])&s[2][n-1]

Eingabeformat: Funktion mit 2 Argumenten

  • arg 1, numerisch, Anzahl der Ringe
  • arg 2, Array von Strings, jeder String 2 Zeichen '0', '1', '2'

Ausgabe: 1, wenn ok, 0, wenn ungültig, Ausnahme, wenn kein Stab vorhanden ist

Weniger golfen und erklärt

n=>a=>(
  // rods status, rod 0 full with an array n..1, rod 1 & 2 empty arrays
  s = [ [...Array(t=n)].map(_=>t--), [], [] ],
  // for each step in solution, evaluate function and stop if returns true
  err = a.some( ([x,y]) => {
    v = s[x].pop(); // pull disc from source rod
    // exception is s[x] is not defined
    if (!v) return 1; // error source rod is empty
    l = s[y].push(v); // push disc on dest rod, get number of discs in l
    // exception is s[y] is not defined
    if(s[y][l-2] < v) return 1; // error if undelying disc is smaller
  }),
  err ? 0 // return 0 if invalid move
  : s[2][n-1]; // il all moves valid, ok if the rod 2 has all the discs
)

Test Hinweis: Die erste Zeile der Testfunktion wird benötigt, um das in der Frage angegebene Eingabeformat in die von meiner Funktion erwartete Eingabe zu konvertieren

F=
n=>s=>!s.some(([x,y])=>s[y][s[y].push(v=s[x].pop())-2]<v|!v,s=[[...Array(s=n)].map(_=>s--),[],[]])&s[2][n-1]

Out=x=>O.textContent+=x+'\n'

Test=s=>s.split`\n`.map(r=>[+(r=r.match(/\d+|.->./g)).shift(),r.map(x=>(parseInt(x[0],36)-10)+''+(parseInt(x[3],36)-10))])
.forEach(([n,s],i)=>{
  var r
  try {
    r = F(+n)(s);
  } 
  catch (e) {
    r = 'Error invalid rod';
  }
  Out(++i+' n:'+n+' '+s+' -> '+r)
})

Out('OK')
Test(`n=1, "A->C"
n=1, "A->B ; B->C"
n=2, "A->B ; A->C ; B->C"
n=2, "A->C ; C->B ; A->C ; B->C"
n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"`)

Out('\nFail')
Test( `n=1, "A->B"
n=1, "C->A"
n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=2, "A->B ; A->C ; C->B"
n=2, "A->C ; A->B ; C->B ; B->A"
n=2, "A->C ; A->C"
n=3, "A->B ; A->D; A->C ; D->C ; A->C"
n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"
n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"`)
<pre id=O></pre>

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.