(ルービック)ポケットキューブを解く


16

あなたのタスク

..ブライアンファンタナが明らかにできなかったことを行い、2x2x2ルービックキューブを解くことです。

ポケットキューブ-アンカーマン

レイアウト

- -   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つの固有の文字がありますが、それらは異なる場合があるため、各色に使用する6つのASCII文字の任意の組み合わせを準備します。

仕様書

  • コードは、Right(R)、Upper(U)、およびFront(F)フェースのみを使用してソリューションを出力し、標準表記を使用する必要があります:R、R '、R2、U、U'、U2、F、F '、F2。詳細はこちらをご覧ください。RUFサブセットの制限は、2x2キューブの標準です(ヒント:左下隅を固定ベースとして使用します)。
  • コードは、ポケットキューブのすべての可能な順列を解決できる必要があります。
  • 各ソリューションが完了するまでに30秒未満かかります。
  • 各ソリューションは30移動未満でなければなりません。
  • 常に20移動未満の回答を提供するソリューションには、-20%のボーナスが与えられます(回答で広告を掲載して、徹底的にチェックできるようにしてください)
  • 常に最適なソリューションを提供するコードには、-50%のボーナスが付与されます。-繰り返しますが、あなたの答えで宣伝してください
  • ソリューションは1つの動きに簡単に結合できるため、同じ顔に2つの連続した動きを含めることはできません。
  • ソリューションには、オプションで、各移動の間に単一のスペース(単一のスペースのみ)を含めることができます。
  • 必要に応じて、ソリューションシーケンス全体を1組の括弧、引用符、ブレース、ブラケット、またはカレットに含めることができますが、他の無関係な出力は許可されません。
  • コードの短いコメント版またはコードの完全な説明を提供してください。
  • 外部ファイルを使用しません。これには、インターネット、データテーブル、およびこの種の問題のために作成されたライブラリ/パッケージが含まれます。
  • バイト数による最短コードが優先されます。
  • 勝者は水曜日(2014年7月30日)を選択しました。

20
私たちは、2×2、と持っている3x3の、および4x4のを、私はまだ輝きに私のチャンスのために1x1の挑戦を待っています。私は完璧なアルゴリズムを持っています!
ドアノブ

ここでも、最適な(=最短)解を生成するKで〜500文字のソルバーは、です:speedsolving.com/forum/...
Jakube

ダイクストラを使用してブルートフォースするには30秒で十分です。位置は3674160のみです。
ピーターテイラー14

2
1.出力の空白には制限がないと仮定します。2.客観的にするために、20移動未満のソリューションのボーナスを「任意」のままにするのではなく、定義する必要があります。
レベルリバーセント14

@steveverrillそれを修正しました。空白の仕様も追加されました。ありがとう!
カイルマコーミック14

回答:


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移動最適)スクランブルの場合、約2分。そこで、私は両側から問題にアプローチすることにしました。2つのセットを使用します。スクランブルまでの距離が1,2,3、...のすべての状態を順番に生成してset1に保存し、同時に距離が1,2,3、...のすべての状態を解決済み状態に保存しますset2で 最初に状態が両方のセットにあるとき、解決策が見つかりました。

このためには、解決されたキューブの色が必要ですが、これは不明です。文字13、20、および23は、左、背面、および下の色を定義します。しかし、これらの3色は立方体を表すのに十分です。他の3色を空白で置き換えるだけで、解決済みの状態を「____ll____bbll____dddd」として表すことができます。

ああ、順列を短縮するために、https://codegolf.stackexchange.com/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プログラムの1つです。

編集:半年後: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]:...

また、移動ラムダを少し変更しました。関数呼び出しは一度しか表示されないため、最初にコードを短縮し、次にコードを直接統合しました。

各状態について、動きを含む文字列ではなく、動きを表すために0から11までの数字のリストを保持します。数値は最後に変換されます。

また、2つのforループ'for k in r(3):for j in r(3):を1 つに結合しましたfor y in r(12)。したがって、私も動きをしなければなりませんU4, R4, F4。もちろん、このような動きは最短の解決策には現れないため、" 2'"[x%4]機能します。(の場合x % 4 == 3、範囲外のインデックスの例外があります)

また、2番目のセットのエントリを先に検索するため、少し速くなります。11移動ソリューションの場合、約0.5秒。


2
双方向bfsの使用に賛成-私のお気に入りの検索アルゴリズム(IDA *の隣)。時間が許せば、数時間で最適性をテストします。また、パズルを解くのにU / R / F色が本当に必要ないことも知りませんでした。よくできました!
カイルマコーミック14

正確性と最適性のために私の20のテストケースに合格しました。
カイルマコーミック14

非常に素晴らしい.. 24よりも速い実装を助けてくれました!jsの単一方向bfs
RE60K

実際には「____ll____bbll____ddddは」「____ll____bbll____bbdddd」でなければなりません
RE60K

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文字がかかりますが、見つかった各長さの(最適なものまで)1つのソリューションのみが印刷されるようにします。最適なソリューションのみを表示する場合は、これまでに見つかった最適なソリューションを変数に保存し、プログラムの最後に最適なソリューションを印刷する必要があります(これには約15文字のコストがかかります)。

入力はc[]、インデックス64以降の配列に読み込まれます。これは、移動テーブルでアルファベット文字を使用するために必要です。ソリューションのテストを機能させるには偶数から開始する必要があるため、質問ごとに記号@A〜X Wが使用されます。c['Z']4倍回転を実行するには合計5つの割り当てが必要なため、一時ストレージにも使用されます。の最初の部分c[]は使用されていないため、ソリューションを保存するために使用できます(すべてのC文字列と同様に、ゼロバイトで終了します)。

for(i..)は、で指定された顔の4クォーターターンのシーケンスを通過しますn

最初for(j..)は、表に従って実際のスワッピングを実行しますt[]

キューブが解決されたかどうかをテストするには、4つの側面のみをチェックする必要があります。URFとDFRのピースは、UステッカーとDステッカーを取り外しても区別できます。これは、1つのピースが時計回り方向にXRFを読み取り、もう1つのピースがXFRを読み取るためです。Uが下の面に表示されるように2つの部分を交換すると、Fの色が右の面に表示され、その逆も同様です。

2番目for(j..)は、4つの側面の不一致の数をカウントします。たとえば、前面の場合、GとO、HとP、およびGとH(2回)を比較します。e== 0の場合、立方体が解かれます。e<9またはe<13の場合、次の1つの移動または2つの移動でキューブをそれぞれ解決できる可能性があります。そうでなければ、この数の移動でキューブを解決することは絶対に不可能です。時間を節約するために、このヒューリスティックを使用して検索ツリーを整理し、深さ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でテストされました

次の結果は、私のマシンですべての最適なソリューションを見つけるためのタイミングを示しています(好奇心のある人向け)。より複雑な位置についても、最適なソリューションを1つだけ見つける上記の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

いいですね。ここで近い競争が見たいです。
カイルマコーミック14

@KyleMcCormick私のプログラムはようやく終了し、順調に実行されていますが、待っているのにうんざりし、他の答えを受け入れました。2日前にバグがあった(顔が間違った方向を向いている)投稿よりもはるかに優れています。また、2つのレベルにヒューリスティックを適用すると、速度が向上しました。それでもいくつかのソリューションが出力されますが、最後のソリューションは最適であることが保証されています(テキストの出力変更の可能性についての詳細)。他のサブミッションよりもはるかに短いです。出力形式に問題がある場合はお知らせください。
レベルリバーセント14

基本的なゴルフで358バイト
MD XF
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.