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倍,这主要是由于状态的更新方式所致。
输入输出
输出由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加1后得出整数3。如果状态为“ 123456789”,则对状态进行切片将得出“ 456789”。
在执行“ $”之前,堆栈的最高元素是:
[ 1 2 3 4 5 6 7 8 9 ] { [ 4 5 6 7 8 9 ] ? "1420344440" = }
在推入元素本身之后,“ $”会对要排序的数组的每个元素执行一次块。
“ [4 5 6 7 8 9]”中的索引1为-1(不存在),因此将压入最后一个元素“ 1420344440”。这将产生48,即与字符0相对应的ASCII码。对于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
”?我不确定如何阅读。