GolfScript, 39/83 байт
# 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`*
Швидкість проти розміру
Версія з оптимізацією розміру випадковим чином вибирає обертання за годинниковою стрілкою до досягнення потрібної перестановки. Цього достатньо, оскільки обертання проти годинникової стрілки еквівалентно трьом послідовним обертанням однієї площі за годинниковою стрілкою.
Оптимізована швидкість версія робить те саме, за винятком наступних:
Якщо число 1 знаходиться у лівому верхньому куті, воно більше не обертає верхній лівий квадрат.
Якщо число 9 знаходиться в правому нижньому куті, воно більше не обертає нижній правий квадрат.
Етапи заміни позицій 7 і 8 жорстко кодуються, тому є два положення, які дозволяють циклу розірватися.
Окрім зміни алгоритму, версія, що оптимізує швидкість, досягає обертання прямолінійно, тоді як версія, орієнтована на розмір, використовує вбудований сортування GolfScript шляхом картографування. Він також жорстко кодує кінцевий стан (для порівняння) замість сортування стану за кожною ітерацією.
Оптимізована для швидкості версія вимагає меншої кількості ітерацій, і кожна ітерація набагато швидша сама по собі.
Орієнтири
Я використовував наступний код для рандомізації позицій чисел та проведення пробних прогонів, коментуючи рядок, що відповідає тестуваній версії:
[{[
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: '\+
Вихід показує мінімальну та максимальну кількість кроків, необхідних для впорядкування чисел, середню та медіану всіх пробіжок, а також пройдений час у секундах:
$ 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
На моїй машині (Intel Core i7-3770) середній час виконання версії з оптимізацією розміру становив 3,58 хвилини. Середній час виконання оптимізованої для швидкості версії становив 0,20 секунди. Таким чином, оптимізована швидкість версія приблизно в 1075 разів швидша.
Оптимізована швидкість версія дає обертання в 114 разів менше. Виконання кожного обертання в 9,4 рази повільніше, що головним чином пов’язано з тим, як оновлюється стан.
I / O
Вихід складається з 3-розрядних чисел. MSB встановлюється для обертання проти годинникової стрілки, середній біт встановлюється для нижніх квадратів, а LSB встановлюється для правильних квадратів. Таким чином, 0 (4) - верхній лівий квадрат, 1 (5) верхній правий, 2 (6) нижній лівий і 3 (7) нижній правий.
Оптимізована швидкість версія друкує всі обертання в одному рядку. Версія з оптимізацією розміру друкує по одному обертанню на рядок, а потім кінцеве положення чисел.
Для оптимізованої швидкості версії вхід повинен отримати масив, що містить числа від 1 до 9 при оцінці. Для оптимізованої за розміром версії вхід повинен бути рядком без остаточного нового рядка; це не оцінюється.
Приклад виконання:
$ echo -n '253169748' | golfscript rotation-size.gs
3
0
123456789
$ golfscript rotation-speed.gs <<< '[5 4 7 1 2 9 3 8 6]'
2210300121312212222212211121122211122221211111122211211222112230764
Оптимізований за розміром код
{ #
. # 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.
Оновлення стану досягається наступним чином:
Поворот 2 дає додавання цілого числа 3 після додавання 1. Якщо стан "123456789", розрізання стану дає "456789".
Прямо перед виконанням "$" найвищими елементами стеку є:
[ 1 2 3 4 5 6 7 8 9 ] { [ 4 5 6 7 8 9 ] ? "1420344440" = }
"$" Виконує блок один раз для сортування кожного елемента масиву після натискання на сам елемент.
Індекс 1 у "[4 5 6 7 8 9]" дорівнює -1 (немає), тому останній елемент "1420344440" висувається. Це дає 48, ASCII код, що відповідає символу 0. Для 2 і 3 також висувається 48.
Цілі числа, натиснуті на 4, 5, 6, 7, 8 і 9, складають 49, 52, 50, 48, 51 і 52.
Після сортування перший елемент стану буде одним із елементів, що дають 48; останній буде одним із тих, що дають 52. Вбудований сорт взагалі нестабільний, але я емпірично перевірив, що він стабільний у цьому конкретному випадку.
Результат - «[1 2 3 7 4 6 8 5 9]», що відповідає обертанню нижнього лівого квадрата за годинниковою стрілкою.
Код з оптимізацією швидкості
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".
Зауважте, що обертання 3, 0, 7, 6 і 4 змінюють місцями в позиціях 7 і 8, не змінюючи позицій решти семи елементів.
...and return as output a sequence of moves representing the moves you must take to return the board back to its original
Чи означає це "назад до1 2 3\n4 5 6\n7 8 9
"? Я не впевнений, як це читати.