Розв’яжіть кишеньковий кубик (Рубікс)


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 символів ascii, яка буде використовуватися для кожного кольору.

Технічні умови

  • Ваш код повинен виводити рішення, використовуючи лише праву (R), верхню (U) та передню (F) грані, і повинен використовувати стандартні позначення: R, R ', R2, U, U', U2, F, F ', F2. Більше інформації ви можете знайти тут . Обмеження на підмножину RUF є стандартним для куба 2х2 (Підказка: трактуйте нижній-задній кут як фіксовану основу для роботи).
  • Ваш код повинен бути здатний вирішувати всі можливі перестановки кишенькового куба.
  • Кожен розчин повинен зайняти менше 30 секунд.
  • Кожен розчин повинен бути менше 30 ходів.
  • Бонус у розмірі -20% буде надано за рішення, які завжди дають відповіді менше 20 ходів (будь ласка, рекламуйте це у своїй відповіді, щоб я міг ретельно перевірити це)
  • Бонус -50% буде наданий за код, який завжди забезпечує оптимальне рішення. - Знову, будь ласка, рекламуйте у своїй відповіді
  • Рішення не повинні містити двох послідовних рухів на одній грані, оскільки їх можна легко поєднати в один хід.
  • Рішення можуть необов'язково містити один пробіл - і лише один простір - між кожним ходом.
  • Вся послідовність рішення, якщо необхідно, може міститись у дужках, лапках, дужках чи символах, але не допускається жоден інший сторонній вихід.
  • Надайте або коротко коментовану версію коду, або ретельне пояснення свого коду.
  • Немає використання зовнішніх файлів. Сюди входять Інтернет, таблиці даних та бібліотеки / пакети, створені для подібних проблем.
  • Виграє найкоротший код за кількістю байтів.
  • Переможця обрали середу (30 липня 2014 р.).

20
У нас є 2х2, і 3х3 , і 4х4 , але я все ще чекаю виклику 1x1, щоб отримати шанс світити. У мене ідеальний алгоритм!
Дверна ручка

Ось вирішувач ~ 500 символів у K, який генерує навіть оптимальне (= найкоротше) рішення: speedsolving.com/forum/…
Jakube

30 секунд повинно вистачити, щоб жорстоко примусити його за допомогою Дейкстри: позицій лише 3674160.
Пітер Тейлор

2
1. Я припускаю, що немає обмежень щодо пробілів у виході. 2. Щоб бути об'єктивним, вам слід визначити бонус за рішення, менші за 20 ходів, замість того, щоб залишати його як «дискреційне».
Рівень р. Св.

@steveverrill Виправлено. Також додано специфікацію пробілів. Спасибі!
Кайл МакКормік

Відповіді:


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, ... до вирішеного стану і зберігаю їх у наборі2. Перший раз, коли стан знаходиться в обох множинах, ми знайшли рішення.

Для цього мені потрібні кольори розв’язаного куба, які невідомі. Символи 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]:...

Також я трохи змінив ходу ламди. Спочатку скорочують, а потім інтегрують код безпосередньо, оскільки виклик функції з’являється лише один раз.

Я зберігаю для кожного стану список чисел від 0 до 11, щоб представляти ходи, а не рядок, що містить ходи. Числа перетворюються в самому кінці.

Також я поєднав дві фор-петлі 'for k in r(3):for j in r(3):в одну for y in r(12). Тому я також повинен робити рухи U4, R4, F4. Звичайно, такий крок не виявляється в найкоротшому рішенні, тому " 2'"[x%4]працює. (Якщо x % 4 == 3б не було винятком індексу поза діапазоном)

Це також трохи швидше, оскільки я шукаю запис у другому наборі раніше. Близько 0,5 секунди для 11-ти ходового рішення.


2
Запропоновано використовувати двосторонній bfs - мій улюблений алгоритм пошуку (поруч із IDA *). Якщо час дозволяє, я перевірю його на кілька годин для оптимальності. Крім того, я не усвідомлював, що для вирішення головоломки вам не потрібні кольори U / R / F. Чудово зроблено!
Кайл МакКормік

Провели 20 моїх тестових випадків на правильність та оптимальність.
Кайл Маккормік

дуже приємно .. допомогли мені реалізувати швидше, ніж 24!
однонаправлений bfs

фактично '____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). Використовуваний порядок - це своєрідний порядок у словнику, де всі маршрути, що починаються з U, U2, U ', шукаються перед тим, як шукати будь-які маршрути, що починаються з R або F. Таким чином, не обов’язково спочатку знаходити оптимальне рішення.

Коли розчин роздруковується, rвін робиться рівним, mщо гарантує, що після цього будуть надруковані лише рівні або більш короткі розчини. Введення r=m-2коштує додатково 2 символи, але забезпечує друкується лише одне рішення кожної знайденої довжини (до оптимальної). Якщо ви хочете, щоб воно показало ТОЛЬКО оптимальне рішення, найкраще знайдене рішення досі має бути збережене в змінній, а оптимальне рішення надруковано в кінці програми (це коштувало б приблизно 15 символів).

вхід зчитується в масив c[]від індексу 64 і далі. Це необхідно для використання символів алфавіту в переміщенні. Символи @через Wвикористовуються замість від A до X для запитання, оскільки для початку тесту на рішення рішення потрібно починати з парного числа. c['Z']також використовується для тимчасового зберігання, тому що для здійснення 4-кратного обертання потрібно всього 5 завдань. Оскільки перша частина c[]не використовується, вона може зберігати рішення (яке закінчується нульовим байтом, як і всі рядки С).

for(i..)проходить через послідовність у 4 чверті обертання обличчя, визначене n.

Перший for(j..)здійснює фактичну заміну згідно з табл t[].

Щоб перевірити, чи вирішено куб, необхідно лише перевірити чотири бічні грані. Шматки URF та DFR можна розрізнити навіть за вилученими наклейками U і D, оскільки одна деталь читає XRF за годинниковою стрілкою, а інша XFR. Якщо два шматки будуть замінені так, що U показує на нижній частині обличчя, і навпаки, колір F відобразиться на правій грані та навпаки.

Друга for(j..)підраховує кількість невідповідностей на чотирьох бічних гранях. Наприклад, для передньої грані вона порівнює G&O, H&P та G&H (двічі.) Якщо e== 0, куб вирішується. Якщо e<9 або e<13, можливо, вирішити куб можна наступним ходом або 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.
}

Продуктивність

Програма була протестована за шаблонами від 1 до 13 на веб- сайті http://www.jaapsch.net/puzzles/cube2.htm

Результати, наведені нижче, дають час на моїй машині, щоб знайти ВСЕ оптимальні рішення (для допитливих.) Також для більш складних позицій час заданий для 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 дні тому, в якому була помилка (обличчя повертається неправильно.) Крім того, застосування евристичного на 2 рівні покращило швидкість. Він все ще виводить кілька рішень, але останнє рішення гарантовано є оптимальним (детальніше про можливі зміни в тексті тексту). Це набагато коротше, ніж інші подання. Якщо у вас є якісь проблеми з вихідним форматом, дайте мені знати.
Рівень річки Св.

358 байт через основні гольфи.
MD XF
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.