GolfScript, 39/83 Bytes
# Optimized for size:
{.4rand.p.2/+>`{?1420344440`=}+$..$>}do
# Optimized for speed:
6,(7++:t;~{.(1=.@7=9=+4\-rand+..2/+@.@>:s^[3s=0s=2s=4s=1s=]+s|.)9<\t>|}do.$>30764`*
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:
[{[
0:c;10,1>{;2 32?rand}$
#{c):c;.4rand.2/+>`{?1420344440`=}+$..$>}do
#6,(7++:t;{.(1=.@7=9=+4\-rand+..2/+@.@>:s^[3s=0s=2s=4s=1s=]+s|.)9<\t>|}do.$>30764`*
],c+}\~*]
$.0='Min: '\+puts .-1='Max: '\+puts ..{+}*\,/'Avg: '\+puts .,2/='Med: '\+
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:
$ TIME='\n%e s' time golfscript rotation-test-size.gs <<< 100
Min: 4652
Max: 2187030
Avg: 346668
Med: 216888
21500.10 s
$
$ TIME='\n%e s' time golfscript rotation-test-speed.gs <<< 1000
Min: 26
Max: 23963
Avg: 3036
Med: 2150
202.62 s
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:
$ echo -n '253169748' | golfscript rotation-size.gs
3
0
123456789
$ golfscript rotation-speed.gs <<< '[5 4 7 1 2 9 3 8 6]'
2210300121312212222212211121122211122221211111122211211222112230764
Größenoptimierter Code
{ #
. # Duplicate the state.
4rand # Push a randomly chosen integers between 0 and 3.
.p # Print that integer.
.2/+ # Add 1 to it if it is grater than one. Possible results: 0, 1, 3, 4
>` # Slice the state at the above index.
{ # Push a code block doing the following:
? # Get the index of the element of the iteration in the sliced state.
1420344440` # Push the string "14020344440".
= # Retrieve the element at the position of the computed index.
}+ # Concatenate the code block with the sliced state.
$ # Sort the state according to the above code block. See below.
..$> # Push two copies of the state, sort the second and compare the arrays.
}do # If the state is not sorted, repeat the loop.
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:
[ 1 2 3 4 5 6 7 8 9 ] { [ 4 5 6 7 8 9 ] ? "1420344440" = }
"$" 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
6,(7++:t; # Save [ 1 2 3 4 5 7 ] in variable “t” and discard it.
~ # Interpret the input string.
{ #
:s # Duplicate the current state.
(1= # Unshift the first element and push 1 if it is equal to 1 and 0 otherwise.
.@ # Duplicate the boolean and rotate the unshifted array on top of it.
7=9= # Push 1 if the eighth element of “s” is equal to 9 and 0 otherwise.
+4\- # Add the booleans and subtract their sum from 4.
rand # Push a randomly chosen integers between 0 and the result from above.
+. # Add this integer to the first boolean and duplicate it for the output.
.2/+ # Add 1 to the result if it is grater than one. Possible results: 0, 1, 3, 4
@. # Rotate the state on top of the stack and duplicate it.
@>:s # Slice the state at the integer from above and save the result in “s”.
^ # Compute the symmetric difference of state and sliced state.
[ # Apply a clockwise rotation to the sliced array:
3s= # The fourth element becomes the first.
0s= # The first element becomes the second.
2s= # The third element remains the same.
4s= # The fifth element becomes the fourth.
1s= # The second element becomes the fifth.
] # Collect the results into an array.
+ # Concatenate with array of elements preceding the slice.
s| # Perform set union to add the remaining elements of “s”.
. # Duplicate the updated state.
)9< # Pop the last element; push 0 if it is equal to 9 and 1 otherwise.
\t # Swap the popped state on top and push [ 1 2 3 4 5 7 ].
> # Push 0 if the state begins with [ 1 2 3 4 5 6 ] and 1 otherwise.
| # Take the logical OR of the booleans.
}do # If the resulting boolean is 1, repeat the loop.
.$ # Duplicate the state and sort it.
>30764`* # If the state was not sorted, 7 and 8 are swapped, so push "30764".
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.
...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.