GolfScript, 39/83 byte
# 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`*
Velocità vs dimensioni
La versione ottimizzata per dimensioni sceglie casualmente le rotazioni in senso orario fino a raggiungere la permutazione desiderata. Questo è sufficiente, poiché una rotazione in senso antiorario equivale a tre rotazioni consecutive in senso orario dello stesso quadrato.
La versione ottimizzata per la velocità fa lo stesso, ad eccezione di quanto segue:
Se il numero 1 si trova nell'angolo in alto a sinistra, non ruota più il quadrato in alto a sinistra.
Se il numero 9 si trova nell'angolo in basso a destra, non ruota più il quadrato in basso a destra.
I passaggi per scambiare le posizioni 7 e 8 sono hardcoded, quindi ci sono due posizioni che permettono al loop di rompersi.
Oltre a modificare l'algoritmo, la versione ottimizzata per la velocità ottiene la rotazione in modo semplice, mentre la versione ottimizzata per dimensioni utilizza l'ordinamento incorporato di GolfScript mediante mappatura. Inoltre codifica lo stato finale (per il confronto) invece di ordinare lo stato in ogni iterazione.
La versione ottimizzata per la velocità richiede meno iterazioni e ogni iterazione è molto più veloce da sola.
Punti di riferimenti
Ho usato il seguente codice per randomizzare le posizioni dei numeri ed eseguire esecuzioni di test, decommentando la riga corrispondente alla versione da testare:
[{[
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: '\+
L'output mostra il numero minimo e massimo di passaggi necessari per ordinare i numeri, la media e la mediana di tutte le esecuzioni, nonché il tempo trascorso in secondi:
$ 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
Sulla mia macchina (Intel Core i7-3770), il tempo medio di esecuzione della versione con ottimizzazione delle dimensioni era di 3,58 minuti. Il tempo medio di esecuzione della versione ottimizzata per la velocità è stato di 0,20 secondi. Pertanto, la versione ottimizzata per la velocità è circa 1075 volte più veloce.
La versione ottimizzata per la velocità produce rotazioni 114 volte inferiori. L'esecuzione di ciascuna rotazione è 9,4 volte più lenta, principalmente a causa dell'aggiornamento dello stato.
I / O
L'output è composto da numeri a 3 bit. L'MSB è impostato per le rotazioni in senso antiorario, il bit centrale è impostato per i quadrati inferiori e l'LSB è impostato per i quadrati giusti. Pertanto, 0 (4) è il quadrato in alto a sinistra, 1 (5) quello in alto a destra, 2 (6) in basso a sinistra e 3 (7) in basso a destra.
La versione ottimizzata per la velocità stampa tutte le rotazioni su una sola riga. La versione ottimizzata per le dimensioni stampa una rotazione per riga, seguita dalla posizione finale dei numeri.
Per la versione ottimizzata per la velocità, l'input deve produrre un array contenente i numeri da 1 a 9 quando valutato. Per la versione con ottimizzazione delle dimensioni, l'input deve essere una stringa senza newline finale; non viene valutato.
Esempi di esecuzione:
$ echo -n '253169748' | golfscript rotation-size.gs
3
0
123456789
$ golfscript rotation-speed.gs <<< '[5 4 7 1 2 9 3 8 6]'
2210300121312212222212211121122211122221211111122211211222112230764
Codice ottimizzato per dimensioni
{ #
. # 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.
L'aggiornamento dello stato si ottiene nel modo seguente:
La rotazione 2 produce l'intero 3 dopo aver aggiunto 1. Se lo stato è "123456789", se si taglia lo stato si ottiene "456789".
Prima di eseguire "$", gli elementi più in alto dello stack sono:
[ 1 2 3 4 5 6 7 8 9 ] { [ 4 5 6 7 8 9 ] ? "1420344440" = }
"$" Esegue il blocco una volta per ogni elemento dell'array da ordinare, dopo aver spinto l'elemento stesso.
L'indice di 1 in “[4 5 6 7 8 9]” è -1 (non presente), quindi viene spinto l'ultimo elemento di "1420344440". Questo produce 48, il codice ASCII corrispondente al carattere 0. Per 2 e 3, anche 48 viene spinto.
I numeri interi inseriti per 4, 5, 6, 7, 8 e 9 sono 49, 52, 50, 48, 51 e 52.
Dopo l'ordinamento, il primo elemento dello stato sarà uno degli elementi che generano 48; l'ultimo sarà uno di quelli che producono 52. Il tipo incorporato è instabile in generale, ma ho verificato empiricamente che è stabile in questo caso particolare.
Il risultato è “[1 2 3 7 4 6 8 5 9]”, che corrisponde a una rotazione in senso orario del quadrato in basso a sinistra.
Codice ottimizzato per la velocità
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".
Osservare che le rotazioni 3, 0, 7, 6 e 4 scambiano gli elementi nelle posizioni 7 e 8, senza alterare le posizioni dei rimanenti sette elementi.
...and return as output a sequence of moves representing the moves you must take to return the board back to its original
Questo significa "torna a1 2 3\n4 5 6\n7 8 9
"? Non sono sicuro di come leggerlo.