Auf einigen alten Nokia-Handys gab es eine Variante des fünfzehn Puzzles Namen Rotation. In dieser Variante haben Sie nicht jeweils eine Kachel verschoben, sondern jeweils vier Kacheln in eine Richtung gedreht.
In diesem Spiel würden Sie mit einem Brett wie diesem beginnen:
4 9 2
3 5 7
8 1 6
Und wenn Sie den unteren linken Block zweimal im Uhrzeigersinn und den oberen linken Block einmal im Uhrzeigersinn drehen, erhalten Sie Folgendes:
4 9 2
8 3 7
1 5 6
4 9 2
1 8 7
3 5 6
1 4 2
8 9 7
3 5 6
und das 1
Plättchen wäre in der oberen linken Ecke, wo es sein soll. Nach ein paar weiteren Zügen würden Sie am Ende Folgendes haben:
1 2 3
4 5 6
7 8 9
Das ist die "ursprüngliche" Konfiguration.
Ihre Aufgabe ist es, ein Programm zu erstellen, das als Eingabe ein 3x3-Raster mit Zahlen von 1 bis 9 (in jedem von Ihnen gewählten Format) verwendet und als Ausgabe eine Folge von Zügen zurückgibt, die die Züge darstellt, die Sie ausführen müssen, um das Brett wieder in seinen ursprünglichen Zustand zu versetzen Konfiguration (wieder in jedem von Ihnen gewählten Format). Die erlaubten Züge sind definiert als der [obere / untere] - [linke / rechte] Block von 4 Kacheln [im / gegen den Uhrzeigersinn].
Ihr Programm muss in der Lage sein, alle möglichen 3x3-Gitter zu lösen (alle Permutationen sind lösbar).
Der kürzeste Code dafür gewinnt.
quelle
...and return as output a sequence of moves representing the moves you must take to return the board back to its original
Bedeutet das "zurück zu1 2 3\n4 5 6\n7 8 9
"? Ich bin mir nicht sicher, wie ich das lesen soll.Antworten:
GolfScript, 39/83 Bytes
Geschwindigkeit gegen Größe
Die größenoptimierte Version wählt nach dem Zufallsprinzip Rotationen im Uhrzeigersinn aus, bis die gewünschte Permutation erreicht ist. Dies ist ausreichend, da eine Drehung gegen den Uhrzeigersinn drei aufeinanderfolgenden Drehungen im Uhrzeigersinn desselben Quadrats entspricht.
Die geschwindigkeitsoptimierte Version macht dasselbe, mit Ausnahme der folgenden:
Wenn sich die Zahl 1 in der oberen linken Ecke befindet, wird das obere linke Quadrat nicht mehr gedreht.
Wenn sich die Zahl 9 in der unteren rechten Ecke befindet, wird das untere rechte Quadrat nicht mehr gedreht.
Die Schritte zum Vertauschen der Positionen 7 und 8 sind fest codiert, sodass die Schleife an zwei Positionen unterbrochen werden kann.
Abgesehen von der Änderung des Algorithmus erreicht die geschwindigkeitsoptimierte Version die Rotation auf einfache Weise, während die größenoptimierte Version die in GolfScript integrierte Sortierung durch Mapping verwendet. Außerdem wird der Endzustand (zum Vergleich) hartcodiert, anstatt den Zustand in jeder Iteration zu sortieren.
Die geschwindigkeitsoptimierte Version erfordert weniger Iterationen und jede Iteration ist für sich viel schneller.
Benchmarks
Ich habe den folgenden Code verwendet, um die Positionen der Zahlen nach dem Zufallsprinzip zu ordnen und Testläufe durchzuführen, wobei die Zeile, die der zu testenden Version entspricht, aus dem Kommentar entfernt wurde:
Die Ausgabe zeigt die minimale und maximale Anzahl der Schritte an, die zur Bestellung der Zahlen erforderlich waren, den Durchschnitt und den Median aller Läufe sowie die verstrichene Zeit in Sekunden:
Auf meinem Computer (Intel Core i7-3770) betrug die durchschnittliche Ausführungszeit der größenoptimierten Version 3,58 Minuten. Die mittlere Ausführungszeit der geschwindigkeitsoptimierten Version betrug 0,20 Sekunden. Damit ist die geschwindigkeitsoptimierte Version rund 1075-mal schneller.
Die drehzahloptimierte Version liefert 114-mal weniger Umdrehungen. Die Ausführung jeder Umdrehung ist 9,4-mal langsamer, was hauptsächlich darauf zurückzuführen ist, wie der Status aktualisiert wird.
I / O
Die Ausgabe besteht aus 3-Bit-Zahlen. Das MSB ist für Rotationen gegen den Uhrzeigersinn gesetzt, das mittlere Bit ist für untere Quadrate gesetzt und das LSB ist für rechte Quadrate gesetzt. Somit ist 0 (4) das obere linke Quadrat, 1 (5) das obere rechte, 2 (6) das untere linke und 3 (7) das untere rechte.
Die geschwindigkeitsoptimierte Version druckt alle Umdrehungen in einer Zeile. Die größenoptimierte Version druckt eine Umdrehung pro Zeile, gefolgt von der endgültigen Position der Zahlen.
Bei der geschwindigkeitsoptimierten Version muss die Eingabe ein Array ergeben, das bei der Auswertung die Zahlen von 1 bis 9 enthält. Für die größenoptimierte Version muss die Eingabe eine Zeichenfolge ohne letzte Zeile sein. es wird nicht ausgewertet.
Beispiel läuft:
Größenoptimierter Code
Die Aktualisierung des Status erfolgt auf folgende Weise:
Drehung 2 ergibt die ganze Zahl 3 nach dem Addieren von 1. Wenn der Status "123456789" ist, ergibt das Schneiden des Status "456789".
Kurz vor dem Ausführen von "$" sind die obersten Elemente des Stapels:
"$" Führt den Block einmal für jedes Element des Arrays aus, das sortiert werden soll, nachdem das Element selbst gedrückt wurde.
Der Index von 1 in "[4 5 6 7 8 9]" ist -1 (nicht vorhanden), daher wird das letzte Element von "1420344440" verschoben. Dies ergibt 48, wobei der ASCII-Code dem Zeichen 0 entspricht. Für 2 und 3 wird auch 48 gedrückt.
Die für 4, 5, 6, 7, 8 und 9 geschobenen ganzen Zahlen sind 49, 52, 50, 48, 51 und 52.
Nach dem Sortieren ist das erste Element des Zustands eines der Elemente, die 48 ergeben. Das letzte ist eines von denen, die 52 ergeben. Die eingebaute Sortierung ist im Allgemeinen instabil, aber ich habe empirisch überprüft, dass sie in diesem speziellen Fall stabil ist.
Das Ergebnis ist "[1 2 3 7 4 6 8 5 9]", was einer Drehung des unteren linken Quadrats im Uhrzeigersinn entspricht.
Geschwindigkeitsoptimierter Code
Beachten Sie, dass die Rotationen 3, 0, 7, 6 und 4 die Elemente in den Positionen 7 und 8 vertauschen, ohne die Positionen der verbleibenden sieben Elemente zu ändern.
quelle
Python mit Numpy - 158
Die Eingabe muss das folgende Format haben:
Jede Ausgabezeile ist eine Bewegung, die in Zeichenfolgen wie
trw
oderblc
und wie folgt codiert ist :t
: obenb
: Unterseitel
: linksr
: richtigc
: im Uhrzeigersinnw
: gegen den Uhrzeigersinn (Widdershins)Dieses Programm führt zufällige Bewegungen durch, bis die Zielkonfiguration erreicht ist. Unter der Annahme, dass jeder Zug eine unabhängige Wahrscheinlichkeit von 1/9 hat! um die Zielkonfiguration zu treffen¹, wird die Anzahl der Umdrehungen vor einer Lösung exponentiell mit einem Mittelwert (dh der durchschnittlichen Anzahl von Zügen) von 9 verteilt! ≈ 3,6 · 10⁵. Dies entspricht einem kurzen Experiment (20 Läufe).
¹ 9! Dies ist die Gesamtzahl der Konfigurationen.
quelle
C ++ - Lösung mit den wenigsten Zügen - Breite zuerst (1847 Zeichen)
Nach einigem Nachdenken denke ich, dass ich das viel effizienter und vernünftiger gemacht habe. Diese Lösung ist, obwohl sie diesen Golf sicherlich nicht gewinnt, die einzige, die versucht, die kürzeste Anzahl von Umdrehungen zu finden, die das Brett lösen. Bisher löst es jedes zufällige Brett, das ich darauf geworfen habe, in neun oder weniger Zügen. Es schneidet auch deutlich besser ab als mein letztes und geht hoffentlich auf Dennis 'Kommentare unten ein.
Gegenüber der vorherigen Lösung bestand die größte Änderung darin, die Schlüsselhistorie aus dem Board-Status (BS) in eine neue Klasse zu verschieben, in der die Historie in einer bestimmten Tiefe (DKH) gespeichert wird. Jedes Mal, wenn die Anwendung einen Zug ausführt, wird der Verlauf in dieser Tiefe und in allen Tiefen überprüft, um festzustellen, ob er jemals ausgewertet wurde. In diesem Fall wird er nicht erneut zur Warteschlange hinzugefügt. Dies scheint den Speicher in der Warteschlange erheblich zu reduzieren (indem der gesamte Verlauf aus dem Board-Status selbst entfernt wird) und reduziert daher so gut wie alle dummen Bereinigungen, die ich durchführen musste, um zu verhindern, dass der Code keinen Speicher mehr hat. Außerdem läuft es viel schneller, da viel weniger in die Warteschlange kopiert werden muss.
Nun ist es eine einfache erste Suche in den verschiedenen Boardzuständen. Außerdem möchte ich, wie sich herausstellt, den Schlüsselsatz (der derzeit als Satz von Zahlen in der Basis 9 gespeichert ist, von denen jede von BS :: key als Basis 9-Darstellung der Karte berechnet wird) in einen Bitsatz umwandeln mit 9! Bits scheinen unnötig zu sein; obwohl ich herausgefunden habe, wie man einen Schlüssel im "Fakultätszahlensystem" berechnet, der verwendet werden könnte, um das zu testende / umschaltende Bit im Bitset zu berechnen.
Die neueste Lösung ist also:
quelle
int[]
to ändernconst int[]
und das Flag setzen-fpermissive
.CJam - 39
Ein weiterer Zufallslöser :)
Er nimmt eine Zeichenfolge wie 492357816 und gibt eine (lange) Folge von Ziffern von 0 bis 3 aus, die jeweils eine Drehung eines Blocks im Uhrzeigersinn darstellen: 0 = links oben, 1 = rechts oben, 2 = unten -Links, 3 = rechts unten.
Kurze Erklärung:
4mr
generiert eine Zufallszahl von 0 bis 3_1>+
erhöht die Zahl, wenn sie größer als 1 ist (so erhalten wir 0, 1, 3 oder 4 - diem<
Startindizes der 4 Blöcke), dreht die Zeichenfolge nach links (z. B. 492357816 ->) 923578164, nicht die Blockdrehung), um den Block in die erste Position zu drehen,[Z0Y4X]\f=
wird die Blockdrehung ausgeführt, die die ersten 5 Zeichen betrifft, z. B. 12345 -> 41352;X = 1, Y = 2, Z = 3, also ist [Z0Y4X] tatsächlich [3 0 2 4 1], und dies sind die auf 0 basierenden Indizes der gedrehten Kacheln, die
5>
den Rest der Zeichenfolgem>
kopieren und die (modifizierte) Zeichenfolge zurückdrehen Das Recht__$>
prüft, ob die Zeichenfolge sortiert ist (es ist die Stoppbedingung).quelle
Mathematica, 104 Zeichen
Wir können die Aufgabe in der Sprache der Permutationsgruppen interpretieren. Die vier Umdrehungen sind nur vier Permutationen, die die symmetrische Gruppe S 9 erzeugen , und die Aufgabe besteht nur darin, eine Permutation als Produkt der Generatoren zu schreiben. Mathematica verfügt dazu über eine integrierte Funktion.
Beispiel:
Eingang:
Ausgabe:
1
: oben links im Uhrzeigersinn2
: rechts oben im uhrzeigersinn3
: rechts unten im uhrzeigersinn4
: links unten im uhrzeigersinn-1
: links oben gegen den Uhrzeigersinn-2
: oben rechts gegen den Uhrzeigersinn-3
: rechts unten gegen den Uhrzeigersinn-4
: links unten gegen den Uhrzeigersinnquelle