Pecahkan Kubus Saku (Rubiks)

16

Tugas Anda

.. adalah melakukan apa yang rupanya Brian Fantana tidak bisa lakukan, dan menyelesaikan Kubus Rubik 2x2x2.

kubus saku - pembawa berita

Tata Letak

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

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

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

Dan akan diberikan kepada Anda melalui stdin atau baris perintah (pilihan Anda - sebutkan dalam jawaban Anda) dalam format:

ABCDEFGHIJKLMNOPQRSTUVWX

Perhatikan bahwa AD membentuk wajah-U (atas), EFMN membentuk wajah-L (kiri), GHOP membentuk wajah-F (depan), IJQR membentuk wajah-R (kanan), KLST membuat B-face (belakang), dan UX membentuk D-face (down).

Akan ada enam karakter unik yang mewakili setiap warna, tetapi mereka dapat bervariasi, jadi persiapkan kombinasi 6 karakter ascii yang akan digunakan untuk setiap warna.

Spesifikasi

  • Kode Anda harus menampilkan solusi dengan hanya menggunakan sisi Kanan (R), Atas (U), dan Depan (F), dan harus menggunakan notasi standar: R, R ', R2, U, U', U2, U2, F, F ', F2. Anda dapat menemukan info lebih lanjut di sini . Pembatasan pada subset RUF adalah standar untuk kubus 2x2 (Petunjuk: perlakukan sudut kiri-bawah sebagai basis tetap untuk bekerja).
  • Kode Anda harus mampu menyelesaikan semua permutasi yang mungkin dari kubus saku.
  • Setiap solusi harus selesai kurang dari 30 detik.
  • Setiap solusi harus kurang dari 30 gerakan.
  • Bonus -20% akan diberikan untuk solusi yang selalu memberikan jawaban kurang dari 20 gerakan (harap iklankan dalam jawaban Anda sehingga saya dapat melakukan pemeriksaan menyeluruh untuk itu)
  • Bonus -50% akan diberikan untuk kode yang selalu memberikan solusi optimal. - Sekali lagi, harap beriklan di jawaban Anda
  • Solusi tidak boleh mengandung dua gerakan berturut-turut pada wajah yang sama, karena mereka dapat dengan mudah digabungkan menjadi satu gerakan.
  • Solusi secara opsional dapat berisi satu ruang - dan hanya satu ruang - di antara setiap gerakan.
  • Urutan solusi keseluruhan, jika perlu, dapat terkandung dalam sepasang tanda kurung, tanda kutip, kawat gigi, tanda kurung, atau tanda sisipan, tetapi tidak ada output asing lainnya yang diizinkan.
  • Harap berikan versi kode Anda yang berkomentar singkat atau penjelasan menyeluruh tentang kode Anda.
  • Tidak ada penggunaan file eksternal. Ini termasuk internet, tabel data, dan perpustakaan / paket yang dibuat untuk masalah semacam ini.
  • Kode terpendek dengan jumlah byte menang.
  • Pemenang dipilih Rabu (30 Juli 2014).
Kyle McCormick
sumber
20
Kami memiliki 2x2, dan 3x3 , dan 4x4 , tapi saya masih menunggu tantangan 1x1 agar kesempatan saya untuk bersinar. Saya memiliki algoritma yang sempurna!
Gagang Pintu
Inilah pemecah ~ 500 karakter dalam K, yang menghasilkan bahkan solusi optimal (= terpendek): speedolving.com/forum/…
Jakube
30 detik harus cukup untuk memaksa dengan menggunakan Dijkstra: hanya ada 3674160 posisi.
Peter Taylor
2
1. Saya berasumsi tidak ada batasan spasi putih pada output 2. Agar objektif, Anda harus menentukan bonus untuk solusi yang kurang dari 20 gerakan alih-alih meninggalkannya sebagai "diskresioner."
Level River St
@steveverrill Memperbaikinya. Juga menambahkan spesifikasi spasi putih. Terima kasih!
Kyle McCormick

Jawaban:

11

Python 2.7: 544 byte -50% = 272 byte **

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 mengganti tab dengan beberapa spasi putih. Jadi teknis versi ini memiliki 549 byte. Cukup ganti dua spasi pertama di baris 6-10 dengan tabulator.

Ide di balik program saya: Ide pertama saya adalah pencarian pertama yang menarik. Tapi ini terlalu lama. Sekitar 2 menit untuk perebutan keras (11 gerakan optimal). Jadi saya memutuskan untuk mendekati masalah dari kedua belah pihak. Saya menggunakan dua set. Saya menghasilkan semua negara secara berurutan dengan jarak 1,2,3, ... untuk mengacak dan menyimpannya di set1, dan pada saat yang sama semua negara dengan jarak 1,2,3, ... ke keadaan terpecahkan dan menyimpannya di set2. Pertama kali keadaan dalam kedua set, kami menemukan solusinya.

Untuk ini saya perlu warna kubus yang dipecahkan, yang tidak diketahui. Karakter 13, 20 dan 23 menentukan warna kiri, belakang dan bawah. Tetapi 3 warna ini cukup untuk mewakili kubus. Saya hanya mengganti 3 warna lainnya dengan spasi putih dan saya dapat mewakili kondisi terpecahkan saya sebagai '____ll____bbll____dddd'.

Oh, dan untuk memperpendek permutasi saya menggunakan ide dari /codegolf//a/34651/29577

Versi tidak disatukan:

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

Saya cukup senang dengan hasilnya, karena saya cukup baru di Python. Ini adalah salah satu program python pertama saya.

sunting: setengah tahun kemudian: 427 - 50% = 213.5

Punya sedikit lebih banyak pengalaman dalam Python dan golf. Jadi saya merevisi kode asli saya dan dapat menyimpan lebih dari 100 karakter.

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])

Saya pada dasarnya menggunakan pendekatan yang sama persis. Perubahan terbesar adalah, bahwa saya tidak mendefinisikan fungsi lagi. Dari pada

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)

dapat saya lakukan

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

Saya juga mengubah langkah lamda sedikit. Pertama mempersingkat, dan kemudian mengintegrasikan kode secara langsung, karena panggilan fungsi hanya muncul sekali.

Saya menyimpan untuk setiap negara daftar angka antara 0 dan 11, untuk mewakili gerakan, bukan string yang berisi gerakan. Jumlahnya dikonversi pada bagian paling akhir.

Saya juga menggabungkan dua for-loop 'for k in r(3):for j in r(3):menjadi satu for y in r(12). Karena itu saya juga harus melakukan gerakan U4, R4, F4. Tentu saja langkah seperti itu tidak muncul dalam solusi terpendek, begitu " 2'"[x%4]berhasil. (Jika x % 4 == 3, akan ada indeks di luar rentang pengecualian)

Ini juga sedikit lebih cepat, karena saya mencari entri di set kedua sebelumnya. Sekitar 0,5 detik untuk solusi 11 langkah.

Jakube
sumber
2
Terpilih untuk menggunakan bfs dua arah - algoritma pencarian favorit saya (di sebelah IDA *). Jika waktu memungkinkan, saya akan mengujinya dalam beberapa jam untuk optimalitas. Juga, saya tidak menyadari bahwa Anda tidak benar-benar membutuhkan warna U / R / F untuk menyelesaikan puzzle. Bagus sekali!
Kyle McCormick
Lulus untuk 20 kasus uji saya untuk kebenaran & optimalitas.
Kyle McCormick
sangat bagus .. membantu saya untuk mengimplementasikan yang lebih cepat dari 24! bfs directional tunggal dalam js
RE60K
sebenarnya '____ll____bbll____dddd' harus '____ll____bbll____bbdddd'
RE60K
7

C, 366 - 50% bonus optimal = 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);}

Menggunakan rekursi, program mencari melalui pohon hingga 11 bergerak dalam (panjang maksimal soluton optimal menurut http://en.wikipedia.org/wiki/Pocket_Cube dan halaman yang disebutkan di bawah) dan ketika menemukan solusi itu mencetaknya (hingga 22 karakter, dilacak oleh argumen fungsim .) Urutan yang digunakan adalah semacam urutan kamus, di mana semua rute mulai U, U2, U 'dicari sebelum rute mana pun mulai R atau F dicari. Dengan demikian belum tentu menemukan solusi optimal terlebih dahulu.

Ketika solusi dicetak, rdibuat sama dengan myang memastikan bahwa hanya solusi yang sama atau lebih pendek akan dicetak setelahnya. Menempatkan r=m-2biaya tambahan 2 karakter tetapi memastikan hanya satu solusi dari setiap panjang yang ditemukan (turun ke optimal) dicetak. Jika Anda ingin HANYA menunjukkan solusi optimal, solusi terbaik yang ditemukan sejauh ini harus disimpan ke variabel, dan solusi optimal dicetak di akhir program (ini akan memakan biaya sekitar 15 karakter tambahan.)

input dibaca ke dalam array c[]dari indeks 64 dan seterusnya. Ini diperlukan untuk menggunakan karakter alfabet dalam gerakan. Simbol @melalui Wdigunakan alih-alih A sampai X per pertanyaan, karena itu perlu untuk memulai pada bilangan genap agar tes untuk solusi berfungsi. c['Z']juga digunakan untuk penyimpanan sementara, karena untuk melakukan rotasi 4 kali lipat total 5 tugas diperlukan. Karena bagian pertama dari c[]tidak digunakan, tersedia untuk menyimpan solusi (yang diakhiri dengan byte nol, seperti semua string C.)

for(i..)melewati urutan 4 quarterturns dari wajah yang ditentukan oleh n.

Yang pertama for(j..)melakukan swapping yang sebenarnya sesuai dengan tabel t[].

Untuk menguji apakah kubus itu terpecahkan, Anda hanya perlu memeriksa keempat sisi sisi. Potongan-potongan URF dan DFR dapat dibedakan bahkan dengan stiker U dan D dihapus, karena satu potong membaca XRF dalam arah searah jarum jam dan XFR lainnya. Jika dua bagian dipertukarkan sehingga U menunjukkan pada wajah bawah dan sebaliknya, warna F akan ditampilkan pada wajah kanan dan sebaliknya.

Yang kedua for(j..)menghitung jumlah ketidakcocokan di empat sisi wajah. Misalnya untuk wajah depan, ia membandingkan G & O, H & P, dan G & H (dua kali.) Jika e== 0, kubus diselesaikan. Jika e<9 atau e<13, dimungkinkan untuk menyelesaikan kubus dalam satu gerakan berikutnya atau 2 gerakan masing-masing. Kalau tidak pasti tidak mungkin untuk memecahkan kubus dalam jumlah gerakan ini. Untuk menghemat waktu, heuristik ini digunakan untuk memangkas pohon pencarian dan menghindari pemborosan waktu pada banyak cabang dengan kedalaman 10 atau 11 yang tidak akan berhasil. Dinyatakan sebagai formula, ini menjadi e<45-m*2.

Kode Tidak Terkunci

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.
}

Performa

Program ini diuji dengan pola 1 hingga 13 di http://www.jaapsch.net/puzzles/cube2.htm

Hasil sebagai berikut memberikan pengaturan waktu pada mesin saya untuk menemukan SEMUA solusi optimal (untuk orang yang berpikiran ingin tahu.) Juga untuk posisi yang lebih kompleks, pengaturan waktu diberikan untuk modifikasi 2-byte yang disebutkan di atas yang hanya menemukan satu solusi optimal. Untuk penentuan waktu ini diberikan baik untuk menemukan solusi pertama dan untuk program untuk mengakhiri. Solusi yang diberikan (yang umumnya berbeda dengan solusi yang diperoleh dengan membalik generator pada halaman tertaut) telah diverifikasi dengan simulator kubus online.

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
Level River St
sumber
Kedengarannya bagus. Saya ingin melihat persaingan yang ketat di sini.
Kyle McCormick
@KyleMcCormick Program saya akhirnya selesai dan berjalan dengan baik tetapi saya melihat Anda bosan menunggu dan menerima jawaban lainnya. Ini jauh lebih baik daripada posting saya 2 hari yang lalu yang memiliki bug (wajah berbelok ke arah yang salah.) Juga, menerapkan heuristik ke 2 level telah meningkatkan kecepatan. Ini masih menampilkan beberapa solusi, tetapi solusi terakhir dijamin akan optimal (lebih lanjut tentang kemungkinan perubahan output dalam teks.) Ini jauh lebih pendek daripada pengiriman lainnya. Jika Anda memiliki masalah pada format output, beri tahu saya.
Level River St
358 byte melalui golf dasar.
MD XF