解决(Rubiks)Pocket Cube


16

你的任务

..将执行Brian Fantana显然无法完成的任务,并解决2x2x2 Rubik's Cube。

袖珍立方体-锚

布局

- -   A B   - -   - -
- -   C D   - -   - -

E F   G H   I J   K L
M N   O P   Q R   S T

- -   U V   - -   - -
- -   W X   - -   - -

并将通过stdin或命令行(您的选择-请在您的答案中指定)以以下格式提供给您:

ABCDEFGHIJKLMNOPQRSTUVWX

请注意,AD组成U面(上),EFMN组成L面(左),GHOP组成F面(前),IJQR组成R面(右),KLST组成B面(背面)和UX组成D面(背面)。

将有六个代表每个颜色的唯一字符,但是它们可能会有所不同,因此请准备将每个颜色使用6个ascii字符的任意组合。

技术指标

  • 您的代码应仅使用右(R),上(U)和前(F)面输出解决方案,并应使用标准符号:R,R',R2,U,U',U2,F,F ',F2。您可以在这里找到更多信息。对于2x2多维数据集,对RUF子集的限制是标准的(提示:将左下左后角视为固定的工作基础)。
  • 您的代码必须能够解决Pocket Cube的所有可能排列。
  • 每个解决方案都需要不到30秒的时间才能完成。
  • 每个解决方案应少于30个动作。
  • 对于总是提供少于20个动作的答案的解决方案,将给予-20%的奖金(请在您的答案中做广告,这样我可以对其进行彻底检查)
  • 对于始终提供最佳解决方案的代码,将给予-50%的奖励。-同样,请在您的答案中做广告
  • 解决方案不得在同一面上包含两个连续的动作,因为它们可以轻松地组合为一个动作。
  • 解决方案可以选择包含一个空格- 在每次移动之间。
  • 如有必要,整个解决方案序列可以包含在一对括号,引号,花括号,方括号或尖号中,但不允许其他多余的输出。
  • 请提供您的代码的简短注释版本或您的代码的完整说明。
  • 不使用外部文件。这包括针对此类问题的Internet,数据表和库/程序包。
  • 以字节数为单位的最短代码获胜。
  • 优胜者选择了星期三(2014年7月30日)。

20
我们有2×2和3×34×4 ,但我还在等待我的机会闪亮1x1的挑战。我有一个完美的算法!
门把手

这里的一个〜500字符求解器在K,产生甚至最优(=最短)溶液:speedsolving.com/forum/...
Jakube

30秒应该足以用Dijkstra对其进行暴力:只有3674160个位置。
彼得·泰勒

2
1.我假设输出中的空白没有限制。2.为了客观,您应该为少于20个动作的解决方案定义奖励,而不是将其保留为“自由支配”。
Level River St

@steveverrill修复了它。还添加了空白规范。谢谢!
凯尔·麦考密克

Answers:


11

Python 2.7:544字节-50%= 272字节**

import sys;o=''.join;r=range;a=sys.argv[1];a=o([(' ',x)[x in a[12]+a[19]+a[22]] for x in a]);v={a:''};w={' '*4+(a[12]*2+' '*4+a[19]*2)*2+a[22]*4:''}
m=lambda a,k:o([a[([0x55a5498531bb9ac58d10a98a4788e0,0xbdab49ca307b9ac2916a4a0e608c02,0xbd9109ca233beac5a92233a842b420][k]>>5*i)%32] for i in r(24)])
def z(d,h):
 t={}
 for s in d[0]:
  if s in d[1]:print d[h][s]+d[1-h][s];exit()
  n=[d[0][s],'']
  for k in r(3):
   for j in r(3):s=m(s,k);t[s]=n[h]+'RUF'[k]+" 2'"[(j,2-j)[h]]+n[1-h]
   s=m(s,k)
 d[0]=t;return d
while 1:v,w=z([v,w],0);w,v=z([w,v],1)

Stackexchange用多个空格替换制表符。所以技术上这个版本有549字节。只需用制表符替换第6-10行中的前两个空格即可。

我的程序背后的想法:我的第一个想法是喘不过气来。但这花了太长时间。2分钟左右进行一次艰难的(最佳11步)争夺。因此,我决定从双方着手解决这个问题。我用两套。我依次生成所有距离加扰的距离1,2,3,...的状态,并将它们保存在set1中,同时将所有距离1,2,3,...到解状态的状态保存并保存它们在set2中。第一次在两个集合中都存在状态时,我们找到了解决方案。

为此,我需要未知立方体的颜色。字符13、20和23定义左,后和下颜色。但是这3种颜色足以代表立方体。我只需用空格替换其他3种颜色,就可以将求解状态表示为'____ll____bbll____dddd'。

哦,为了缩短排列,我使用了/codegolf//a/34651/29577的想法

非高尔夫版本:

import sys

#define permutations for R,U,F
permutation = [[0,7,2,15,4,5,6,21,16,8,3,11,12,13,14,23,17,9,1,19,20,18,22,10],
            [2,0,3,1,6,7,8,9,10,11,4,5,12,13,14,15,16,17,18,19,20,21,22,23],
            [0,1,13,5,4,20,14,6,2,9,10,11,12,21,15,7,3,17,18,19,16,8,22,23]]

def applyMove(state, move):
    return ''.join([state[i] for i in permutation[move]])

scramble = sys.argv[1]
#remove up,front,rigth colors
scramble = ''.join([(' ', x)[x in scramble[12]+scramble[19]+scramble[22]] for x in scramble])
solved = ' '*4+scramble[12]*2+' '*4+scramble[19]*2+scramble[12]*2+' '*4+scramble[19]*2+scramble[22]*4

dict1 = {scramble: ''} #stores states with dist 0,1,2,... from the scramble
dict2 = {solved: ''} #stores states with dist 0,1,2,... from the solved state

moveName = 'RUF'
turnName = " 2'"

for i in range(6):
    tmp = {}
    for state in dict1:
        if state in dict2:
            #solution found
            print dict1[state] + dict2[state]
            exit()
        moveString = dict1[state]
        #do all 9 moves
        for move in range(3):
            for turn in range(3):
                state = applyMove(state, move)
                tmp[state] = moveString + moveName[move] + turnName[turn]
            state = applyMove(state, move)
    dict1 = tmp
    tmp = {}
    for state in dict2:
        if state in dict1:
            #solution found
            print dict1[state] + dict2[state]
            exit()
        moveString = dict2[state]
        #do all 9 moves
        for move in range(3):
            for turn in range(3):
                state = applyMove(state, move)
                tmp[state] = moveName[move] + turnName[2 - turn] + moveString
            state = applyMove(state, move)
    dict2 = tmp

我对结果感到非常满意,因为我是Python的新手。这是我的第一个python程序。

编辑:半年后:427-50%= 213.5

在Python和高尔夫方面获得了更多的经验。因此,我修改了原始代码,可以节省100个以上的字符。

import sys;o=''.join;a=sys.argv[1];d=[{o((' ',x)[x in a[12]+a[19]+a[22]]for x in a):[]},{' '*4+(a[12]*2+' '*4+a[19]*2)*2+a[22]*4:[]}]
for h in[0,1]*6:
 for s,x in d[h].items():
  for y in range(12):
   d[h][s]=x+[y-[1,-1,1,3][h*y%4]];
   if s in d[1-h]:print o('RUF'[x/4]+" 2'"[x%4]for x in d[0][s]+d[1][s][::-1]);exit()
   s=o(s[ord(c)-97]for c in'acahabcdnpbfegefhugiovjgqkciljdeklflmmmnnvoopxphrqdjrrbsstttuuqsviwwwkxx'[y/4::3])

我基本上使用完全相同的方法。最大的变化是,我不再定义函数了。代替

def z(d,h):
 for s in d[0]:
  if s in d[1]:...
while 1:v,w=z([v,w],0);w,v=z([w,v],1)

我可以

for h in[0,1]*6:
 for s in d[h]:
  if s in d[1-h]:...

我也略微改变了移动lamda。首先缩短,然后直接集成代码,因为函数调用仅出现一次。

我为每个状态保留一个0到11之间的数字列表来表示移动,而不是包含移动的字符串。数字在最后转换。

另外,我将两个for循环'for k in r(3):for j in r(3):合并为一个for y in r(12)。因此,我也必须做一些动作U4, R4, F4。当然,这种举动不会出现在最短的解决方案中,因此" 2'"[x%4]可以起作用。(如果x % 4 == 3,将存在索引超出范围的异常)

它也快了一点,因为我早些时候在第二组中寻找条目。11个移动解决方案大约需要0.5秒。


2
赞成使用双向bfs-我最喜欢的搜索算法(IDA *旁边)。如果时间允许,我将在几个小时内对其进行最佳测试。另外,我没有意识到您并不需​​要U / R / F颜色来解决难题。做得很好!
凯尔·麦考密克

通过了我的20个测试案例的正确性和最佳性。
凯尔·麦考密克

非常好..帮助我实现了比24更快的速度!js中的单向bfs
RE60K 2016年

实际上'____ll____bbll____dddd'应该是'____ll____bbll____bbdddd”
RE60K 2016年

7

C,366-50%最佳奖励= 183

char c[99],t[3][26]={"ZGONFZCPTEZBHUMZ","ZIQPHZRUGAZJWOCZ","ZACB@ZJHFDZKIGEZ"};r=20;f(int m,int n){int e,i,j;for(i=4;i--;){for(j=15;j--;)c[t[n][j+1]]=c[t[n][j]];c[m]="FRU"[n],c[m+1]="4'2 "[i],c[m+2]=0;for(e=0,j=68;j<76;j++) e+= (c[j]!=c[j+8]) + (c[j]!=c[j^1]);i&&e&&e<45-m*2&m<r?f(m+2,(n+1)%3),f(m+2,(n+2)%3):e||(puts(c),r=m);}}main(){scanf("%s",c+64);f(0,2),f(0,1),f(0,0);}

使用递归,程序搜索一棵最多可移动11个深度的树(最佳解的最大长度取决于 http://en.wikipedia.org/wiki/Pocket_Cube和下面提到的页面解决方案),并在找到解决方案时进行搜索它打印它(最多22个字符,由函数参数跟踪)m。)所使用的顺序是一种字典顺序,其中在搜索任何以R或F开头的路由之前,搜索所有以U,U2,U'开头的路由。因此,它不一定先找到最佳解决方案。

打印解决方案时,r等于m其设置以确保之后仅打印相同或更短的解决方案。推杆会r=m-2额外花费2个字符,但要确保只打印找到的每种长度(最小到最佳长度)的解决方案。如果只希望显示最佳解决方案,则必须将到目前为止找到的最佳解决方案存储到变量中,并在程序末尾打印最佳解决方案(这将花费大约15个字符)。

输入c[]从索引64开始读入数组。为了在移动台中使用字母字符,这是必需的。每个问题使用@直通符号W代替A到X,因为必须从偶数开始才能使测试解决方案起作用。c['Z']也用于临时存储,因为要执行4倍旋转,总共需要5个分配。由于的第一部分c[]尚未使用,因此可用于存储解决方案(与所有C字符串一样,该解决方案以零字节终止)。

for(i..)经历由所指定的脸部的四分之一转的序列n

第一个for(j..)根据table执行实际交换t[]

要测试立方体是否已求解,只需检查四个侧面。即使除去了U和D标签,也可以区分URF和DFR,因为其中一个沿顺时针方向读取XRF,而另一个沿XFR读取。如果将两部分互换,以使U出现在背面,反之亦然,则F颜色将出现在右侧,反之亦然。

第二个for(j..)计数四个侧面上的不匹配数。例如,对于正面,它比较G&O,H&P和G&H(两次)。如果e== 0,则解出多维数据集。如果e<9或e<13,则可能分别在下一步或第二步中求解多维数据集。否则,绝对不可能解决这一步数的立方体。为了节省时间,此启发式方法用于修剪搜索树,并避免在深度10或11的许多分支上浪费时间,而这将是不成功的。用公式表示,它变为e<45-m*2

非高尔夫代码

char c[99],t[3][26]={"ZGONFZCPTEZBHUMZ","ZIQPHZRUGAZJWOCZ","ZACB@ZJHFDZKIGEZ"};
r=20;                                                       //All moves are output as 2 characters. The index of the last move of the longest solution (11 moves) shall be 20.

f(int m,int n){                                             //perform a cycle through four 1/4 turns of the face specified in n. The index of the move reported in the solution is m.
  int e,i,j;                                                //e is for counting mismatches. i loops through the four 1/4 turns. j performs other functions.
  for(i=4;i--;){

    for(j=15;j--;)c[t[n][j+1]]=c[t[n][j]];                  //A 1/4 turn is performed as three 4-sticker rotations of the type z=a;a=b;b=c;c=d;d=z using the data in the movetable t[][]

    c[m]="FRU"[n],c[m+1]="4'2 "[i],c[m+2]=0;                //Write to the output in c[] the face to be turned and the number of 1/4 turns. Terminate with a zero byte to overwrite any longer solution that may have been found before. 

    for(e=0,j=68;j<76;j++)e+=(c[j]!=c[j+8])+(c[j]!=c[j^1]); //Compare each sticker of the top row of the side faces (64+4 through 64+11) with the stickers below and beside it. Count the number of mismatches.

    i && e && e<45-m*2 & m<r?                               //if the number of 1/4turns is not 4 AND the cube is not solved AND the heuristic (as described in the text) is good AND a shorter solution has not already been found,
      f(m+2,(n+1)%3), f(m+2,(n+2)%3):                       //deepen the search to another faceturn of the other two faces. 
      e||(puts(c),r=m);                                     //otherwise, if a solution has been found, print the solution and reduce the value of r to the new max solution length.
  } 
}

main(){
  scanf("%s",c+64);                                         //scan in the current cube state to c[] at index 64.
  f(0,2),f(0,1),f(0,0);                                     //call f() three times to search for solutions beginning with U R and F.
}

性能

该程序已通过http://www.jaapsch.net/puzzles/cube2.htm上的模式1到13进行了测试

以下结果给出了在我的机器上寻找所有最佳解决方案的时间(对于有好奇心的人。)而且对于更复杂的位置,上面提到的2字节修改给出了时间,该修改仅找到一个最佳解决方案。为此,给出寻找第一个解决方案的时间,并终止程序。给出的解决方案(通常与通过反转链接页面上的生成器获得的解决方案不同)已通过在线多维数据集模拟器进行了验证。

U 4 (1 move) horizontal flags (not mirror symmetric)
1 solution 1 sec

U2 (1 move) 4 horizontal flags (mirror symmetric)
1 solution 1 sec

F2 R2 F2 (3 moves) 4 vertical flags  
UUUULRBFRLFBLRBFRLFBDDDD 2 solutions 1 sec

U2 F2 R2 U2 (4 moves) Supertwist; 6 flags
DDUURRBFRRFBLLBFLLFBUUDD 3 solutions 1 sec

U F2 U2 R2 U (5 moves) 4 vertical flags, 2 checkerboards
UDDULBRFRFLBLBRFRFLBUDDU 2 solutions 1 sec

R2 F2 R2 U2 (4 moves) 4 checkerboards
UUUURLFBLRBFLRBFRLFBDDDD 4 solutions 1 sec

R U2 R' F2 R U' R2 U F2 U' (10 moves) Cube in cube
FFFUDDRFRULLLDRRUULBBBDB 18 solutions 26 sec; 1 solution U F2U'R2U R'F2R U2R' 1,13 sec 

R F U' R2 U F' R U F2 R2 (10 moves) Cube in cube 2
DDDUFFLFRBRRLFLLBBRBUUDU 8 solutions 28 sec; 1 solution R F U'R2U F'R U F2R2 12,21 sec 

U R F2 U R F2 R U F' R (10 moves)3-Cycle
UFFULDRFRULBLLFRURBBDBDD 45 solutions 26 sec; 1 solution U R'F U'F'R'F2U R F2 8,14 sec 

U R U' R2 U' R' F' U F2 R F' (11 moves) Column turn
UUUDLLFRFRBBLLFRFRBBDUDD many solutions 29 sec; 1 solution U R U'F U2R F'R'F'U2F' 3,27 sec 

F' U R' F2 U' R F U R2 U R' (11 moves)Corner swap
UUUURLFBLRBFLLFFRRBBDDDD 29 sec 24 solutions; 1 solution R U'F R U'R2U'F'R'U F2 12,28 sec

U F2 U' (3 moves) Zig-zag 
UDUDLLFRFFLBLBRRFRBBUUDD 1 solution 1 sec 

U' F2 U2 R2 U' F2 U2 R2 U' (9 moves) 2 Checkerboards, 4 L
DUUDLLFBRRBFLRFFRLBBUDDU 8 solutions 13 sec; 1 solution U F2U2R2U R2U2F2U' 1,5 sec

听起来不错。我很想在这里看到一场激烈的比赛。
凯尔·麦考密克

@KyleMcCormick我的程序终于完成并且运行良好,但是我看到您厌倦了等待并接受了其他答案。这比前两天我的帖子有一个错误(人脸转向错误的方式)要好得多。而且,将启发式应用到2个级别可以提高速度。它仍然输出几种解决方案,但是保证最后一种解决方案是最佳的(有关文本中可能的输出更改的更多信息。)它比其他提交的要短得多。如果您对输出格式有任何疑问,请告诉我。
级圣河

通过基本高尔夫获得358个字节
MD XF
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.