Велоспорт с Рубиком

43

В то время как лениво крутя кубик моего Рубика , мой сын заметил, что он продолжает возвращаться в решенное состояние. Я почти уверен, что сначала он подумал, что это какая-то магия вуду, но я объяснил, что если вы продолжите повторять одну и ту же последовательность движений, она всегда вернется в исходное состояние. В итоге.

Конечно, будучи ребенком, он должен был попробовать это сам и выбрал «случайную» последовательность, которую он считал хитрой. Он потерял трек после десяти повторений или около того, и спросил меня, сколько раз ему придется повторить это. Не зная последовательности, которую он использовал, я сказал ему, что не знаю, но мы могли бы написать программу, чтобы узнать.

Это то место, куда вы приходите. Конечно, я мог бы просто что-то взбить, но он хотел бы напечатать это сам. Хотя он еще не очень быстрая машинистка, поэтому мне нужна самая короткая из возможных программ .

Задача

При заданной последовательности поворотов выведите наименьшее количество раз, которое необходимо выполнить, чтобы вернуть куб в исходное состояние. Это код гольф, поэтому выигрывает минимум байтов. Вы можете написать программу или функцию, и все остальные обычные значения по умолчанию применяются.

вход

Ввод - это последовательность шагов, взятая в виде строки, списка или другого формата, подходящего для вашего языка. Не стесняйтесь использовать разделитель (или нет) между ходами, если в форме строки.

Есть шесть «основных» ходов, которые должны быть приняты во внимание, вместе с их обратными:

R - Turn the right face clockwise
L - Turn the left face clockwise
U - Turn the up (top) face clockwise
D - Turn the down (bottom) face clockwise
F - Turn the front face clockwise
B - Turn the back face clockwise

Обратное представлено добавлением простого знака 'после буквы. Это означает, что вы поворачиваете эту грань против часовой стрелки, поэтому F'поворачиваете лицевую грань против часовой стрелки и сразу F F'же возвращаете ее в исходное состояние.

Для заинтересованных в этой задаче используется ограниченный набор нотаций Singmaster . Ruwix имеет несколько хороших анимаций, если вы хотите увидеть его в действии.

Выход

Выход - это просто минимальное количество раз, которое должна быть выполнена последовательность ввода.

Примеры

Input                Output

FF'               ->      1
R                 ->      4
RUR'U'            ->      6
LLUUFFUURRUU      ->     12
LUFFRDRBF         ->     56
LF                ->    105
UFFR'DBBRL'       ->    120
FRBL              ->    315

Вот (довольно наивный) решатель для сравнения ваших ответов, написанных на Java. Он также принимает 2двойные ходы (поэтому четвертый случай эквивалентен L2U2F2U2R2U2).

import java.util.ArrayList;
import java.util.List;

public class CycleCounter{

    public static void main(String[] args){
        int[] cube = new int[54];
        for(int i=0;i<54;i++)
            cube[i] = i;

        String test = args.length > 0 ? args[0] : "RUR'U'";
        List<Rotation> steps = parse(test);
        System.out.println(steps.toString());

        int count = 0;
        do{
            for(Rotation step : steps)
                cube = step.getRotated(cube);
            count++;
        }while(!isSorted(cube));

        System.out.println("Cycle length for " + test + " is " + count);        
    }

    static List<Rotation> parse(String in){
        List<Rotation> steps = new ArrayList<Rotation>();
        for(char c : in.toUpperCase().toCharArray())
            switch(c){
                case 'R':steps.add(Rotation.R);break;
                case 'L':steps.add(Rotation.L);break;
                case 'U':steps.add(Rotation.U);break;
                case 'D':steps.add(Rotation.D);break;
                case 'F':steps.add(Rotation.F);break;
                case 'B':steps.add(Rotation.B);break;
                case '\'':
                    steps.add(steps.get(steps.size()-1));
                case '2':
                    steps.add(steps.get(steps.size()-1));
                    break;
            }
        return steps;
    }

    static boolean isSorted(int[] in){for(int i=0;i<in.length-1;i++)if(in[i]>in[i+1])return false;return true;}

    enum Rotation{
        R(new int[]{-1,-1,42,-1,-1,39,-1,-1,36, -1,-1,2,-1,-1,5,-1,-1,8, 20,23,26,19,-1,25,18,21,24, -1,-1,11,-1,-1,14,-1,-1,17, 35,-1,-1,32,-1,-1,29,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1}),
        L(new int[]{9,-1,-1,12,-1,-1,15,-1,-1, 27,-1,-1,30,-1,-1,33,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 44,-1,-1,41,-1,-1,38,-1,-1, -1,-1,6,-1,-1,3,-1,-1,0, 47,50,53,46,-1,52,45,48,51}),
        U(new int[]{2,5,8,1,-1,7,0,3,6, 45,46,47,-1,-1,-1,-1,-1,-1, 9,10,11,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 18,19,20,-1,-1,-1,-1,-1,-1, 36,37,38,-1,-1,-1,-1,-1,-1}),
        D(new int[]{-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,24,25,26, -1,-1,-1,-1,-1,-1,42,43,44, 29,32,35,28,-1,34,27,30,33, -1,-1,-1,-1,-1,-1,51,52,53, -1,-1,-1,-1,-1,-1,15,16,17}),
        F(new int[]{-1,-1,-1,-1,-1,-1,18,21,24, 11,14,17,10,-1,16,9,12,15, 29,-1,-1,28,-1,-1,27,-1,-1, 47,50,53,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,8,-1,-1,7,-1,-1,6}),
        B(new int[]{51,48,45,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,0,-1,-1,1,-1,-1,2, -1,-1,-1,-1,-1,-1,26,23,20, 38,41,44,37,-1,43,36,39,42, 33,-1,-1,34,-1,-1,35,-1,-1});

        private final int[] moves;
        Rotation(int[] moves){
            this.moves = moves;
        }

        public int[] getRotated(int[] cube){
            int[] newCube = new int[54];
            for(int i=0;i<54;i++)
                if(moves[i]<0)
                    newCube[i] = cube[i];
                else
                    newCube[moves[i]] = cube[i];
            return newCube;
        }
    }
}
Geobits
источник
«по часовой стрелке» означает «по часовой стрелке»
msh210
@ msh210 Правильно.
Geobits
7
Что касается педантизма, я думаю, вы должны четко указать, что вам нужно наименьшее число, которого достаточно. В противном случае я мог бы просто вывести размер группы и привести теорему Лагранжа ...
Питер Тейлор
2
@PeterTaylor Pedantry принята.
Geobits
4
Я могу предложить вознаграждение в 500 баллов за решение в Shuffle. Пока не уверен.
lirtosiast

Ответы:

16

Pyth, 66 63 байта

l.uum.rW}Hdd@_sm_B.iFP.>c3Zk3xZHG_r_Xz\'\39Nf!s}RTcZ2y=Z"UDLRFB

Попробуйте онлайн: демонстрация или тестовый набор . Обратите внимание, что программа работает довольно медленно, и онлайн-компилятор не может вычислить ответ RU2D'BD'. Но будьте уверены, что он сможет вычислить его на моем ноутбуке примерно за 12 секунд.

Программа (случайно) также принимает 2для двойных ходов.

Полное объяснение:

Разбор схватки:

Сначала я разберусь с простыми метками 'во входных строках. Я просто заменяю их на « 3run-length» и декодирую эту строку. Поскольку формат декодирования Pyth требует числа перед символом, я заранее переворачиваю строку. _r_Xz\'\39, Так что потом я возвращаю его обратно.

Опишите решенное состояние куба:

=Z"UDLRFBназначает строку со всеми 6 ходами Z.

Мы можем описать состояние куба, описав местоположение каждой части куба. Например, мы можем сказать, что край, который должен быть в UL (вверх-влево), в настоящее время находится в FR (передний-правый). Для этого мне нужно создать все части решаемой кубы: f!s}RTcZ2yZ. yZгенерирует все возможные подмножества "UDLRFB". Это, очевидно, также генерирует подмножество "UDLRFB"и подмножество "UD". Первый не имеет никакого смысла, так как нет никакого фрагмента, который виден со всех 6 сторон, а второй не имеет никакого смысла, так как нет краевого фрагмента, который виден сверху и снизу. , Поэтому я удаляю все подмножества, которые содержат подпоследовательность "UD", "LR"или "FB". Это дает мне следующие 27 штук:

'', 'U', 'D', 'L', 'R', 'F', 'B', 'UL', 'UR', 'UF', 'UB', 'DL', 'DR', 'DF', 'DB', 
'LF', 'LB', 'RF', 'RB', 'ULF', 'ULB', 'URF', 'URB', 'DLF', 'DLB', 'DRF', 'DRB'

Это также включает пустую строку и все шесть однобуквенных строк. Мы могли бы интерпретировать их как часть в середине куба и 6 центральных частей. Очевидно, они не обязательны (так как они не двигаются), но я их оставлю.

Делаем несколько ходов:

Я сделаю несколько переводов строк, чтобы выполнить движение. Чтобы визуализировать идею, взгляните на угол в URF. Что с ним происходит, когда я делаю Rход? Наклейка на Uлице перемещается к Bлицу, наклейка Fперемещается на Uлицо, а наклейка на Rлице остается на Rлице. Можно сказать, что фигура при URFперемещении на свою позицию BRU. Эта модель верна для всех фигур на правой стороне. Каждая наклейка на Fлице перемещается к Uлицу при выполнении Rперемещения, каждая наклейка на Uлице перемещается к Bлицу, каждая наклейка Bперемещается в Dи каждая наклейка Dперемещается вF, Мы можем расшифровать изменения Rхода как FUBD.

Следующий код генерирует все 6 необходимых кодов:

_sm_B.iFP.>c3Zk3
['BRFL', 'LFRB', 'DBUF', 'FUBD', 'RDLU', 'ULDR']
    ^       ^       ^       ^       ^       ^
 U move  D move  L move  R move  F move  B move

И мы выполняем переход Hв состояние куба Gследующим образом:

m.rW}Hdd@...xZHG
m              G   map each piece d in G to:
 .rW   d              perform a rotated translation to d, but only if:
    }Hd                  H appears in d (d is currently on the face H)
            xZH           get the index of H in Z
        @...              and choose the code in the list of 6 (see above)

Подсчитайте количество повторений:

Остальное в значительной степени тривиально. Я просто выполняю вводную схватку с решенным кубом снова и снова, пока не достигну позиции, которую посещал ранее.

l.uu<apply move H to G><parsed scramble>N<solved state>
u...N   performs all moves of the scramble to the state N
.u...   do this until cycle detected, this returns all intermediate states
l       print the length
Jakube
источник
13

GAP, 792 783 782 749 650 байт

Кажется, это работает. Если что-то напутает, дайте мне знать.

Спасибо @Lynn за предложение разложить некоторые примитивные движения.

Спасибо @Neil за предложение, что Inverse(X)я использую X^3.

Пример использования: f("R");

R:=(3,39,21,48)(6,42,24,51)(9,45,27,54)(10,12,18,16)(13,11,15,17);L:=(1,46,19,37)(4,49,22,40)(7,52,25,43)(30,36,34,28)(29,33,35,31);U:=(1,10,27,28)(2,11,26,29)(3,12,25,30)(37,43,45,39)(40,44,42,38);A:=R*L^3*F*F*B*B*R*L^3;D:=A*U*A;;F:=(1,3,9,7)(2,6,8,4)(10,48,36,43)(13,47,33,44)(16,46,30,45);B:=(27,25,19,21)(26,22,20,24)(39,28,52,18)(38,31,53,15)(37,34,54,12);d:=NewDictionary((),true);AddDictionary(d,'R',R);AddDictionary(d,'L',L);AddDictionary(d,'U',U);AddDictionary(d,'D',D);AddDictionary(d,'F',F);AddDictionary(d,'B',B);f:=function(s) local i,p,b,t;p:=();
for c in s do if c='\'' then t:=t^2;else t:=LookupDictionary(d,c);fi;p:=p*t;od;return Order(p);end;

Вот незагрязненный код с небольшим объяснением

  # Here we define the primitive moves
R:=(3,39,21,48)(6,42,24,51)(9,45,27,54)(10,12,18,16)(13,11,15,17);
L:=(1,46,19,37)(4,49,22,40)(7,52,25,43)(30,36,34,28)(29,33,35,31);
U:=(1,10,27,28)(2,11,26,29)(3,12,25,30)(37,43,45,39)(40,44,42,38);
#D:=(7,34,21,16)(8,35,20,17)(9,36,19,18)(48,46,52,54)(47,49,53,51);
F:=(1,3,9,7)(2,6,8,4)(10,48,36,43)(13,47,33,44)(16,46,30,45);
B:=(27,25,19,21)(26,22,20,24)(39,28,52,18)(38,31,53,15)(37,34,54,12);

# Here we define D in terms of other primitive moves, saving on bytes
# Thanks @Lynn
# This is actually doable with a maximum of 3 of the primitive moves
# if a short enough sequence can be found.
D:=U^(R*L^3*F*F*B*B*R*L^3);

# create dictionary and add moves to it with appropriate char labels
d:=NewDictionary((),true);
AddDictionary(d,'R',R);
AddDictionary(d,'L',L);
AddDictionary(d,'U',U);
AddDictionary(d,'D',D);
AddDictionary(d,'F',F);
AddDictionary(d,'B',B);

f:=function(s)
    local c,p,t;

    # p will become the actual permutation passed to the function
    p:=();

    for c in s do
        if c='\'' then
            # The last generator we mutiplied (that we still have in t)
            # should have been its inverse. Compensate by preparing to
            # multiply it two more times to get t^3=t^-1. Thanks @Neil.
            t:=t^2;
        else
            t:=LookupDictionary(d,c);
        fi;
        p:=p*t;
    od;

    return Order(p);

end;
Liam
источник
Каждое движение является четвертым корнем идентичности, поэтому ваш Инверс не нужен.
Нил
Вы, вероятно, можете заменить 45на 5в своих перестановках и сохранить три байта.
Линн
Результат Бенсона, который я нашел в «Сингмастере» в 1981 году, гласит: «Пусть A = RL⁻¹F²B²RL⁻¹, затем AUA = D.» Действительно, A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;оно короче, чем ваше определение для D(но я не могу это проверить ...)
Линн
^-1Кстати, GAP не позволяет вам писать для инверсий?
Линн
Да, я полностью использовал ^ -1. Я полагаю, что это то же самое, что говорил @Neil, за исключением случая с ^ 3 (который на самом деле самый короткий). Кроме того, да, я мог бы разбить ходы на другие ходы, и я мог бы сэкономить несколько байтов, сделав это, это было бы просто вопросом нахождения кратчайшего разложения.
Лиам
10

Mathematica, 413 401 байт

Evaluate[f/@Characters@"RFLBUD"]=LetterNumber@"ABFEJNRMDAEHIMQPCDHGLPTOBCGFKOSNADCBILKJEFGHQRST"~ArrayReshape~{6,2,4};
r[c_,l_]:=(b=Permute[c,Cycles@f@l];MapThread[(b[[#,2]]=Mod[b[[#,2]]+{"F","B","L","R"}~Count~l{-1,1,-1,1},#2])&,{f@l,{3,2}}];b);
p@s_:=Length[c={#,0}&~Array~20;NestWhileList[Fold[r,#,Join@@StringCases[s,x_~~t:""|"'":>Table[x,3-2Boole[t==""]]]]&,c,(Length@{##}<2||c!=Last@{##})&,All]]-1

Пояснения

Кубик Рубика состоит из 20 подвижных кубиков (8 углов, 12 ребер). Каждому кубику может быть присвоен номер:

углы :

N   starting position
1     UFR
2     UBR
3     UBL
4     UFL
5     DFR
6     DBR
7     DBL
8     DFL

края :

N   starting position
9     UF
10    UR
11    UB
12    UL
13    FR
14    BR
15    BL
16    FL
17    DF
18    DR
19    DB
20    DL

Обратите внимание, что когда кубик закручен, кубы больше не находятся на своих начальных позициях. Например, когда Rвсе готово, куби 1перемещается UFRв новую позицию UBR.

В таких обозначениях поворот на 90 градусов можно описать 8 движениями кубиков. Например, Rописывается

from  to
UFR   UBR
UBR   DBR
DBR   DFR
DFR   UFR
UR    BR
BR    DR
DR    FR
FR    UR

Поскольку у каждого кубика есть уникальная стартовая позиция, у каждой позиции есть уникальный стартовый кубик. То есть правило UFR->UBRсправедливо 1->2(означает, что Rкуби переводится в исходное положение куби 1в исходное положение кубики 2). Таким образом, в Rдальнейшем можно упростить цикл

Cycles[{{1,2,6,5}, {10,14,18,13}}]

Чтобы полностью решить кубик Рубика, нам также необходимо выровнять кубики по их соответствующим начальным ориентациям. Грани куба окрашены в разные цвета, схема, которую я часто использую при решении кубов:

face color
U    yellow
D    white
F    red
B    orange
R    green
L    blue

Когда мы анализируем ориентацию углов, цвета, отличные от желтого или белого, игнорируются, а желтый и белый считаются одним и тем же цветом.

Предположим, куби 1находится в исходном положении UFR, желтая грань может быть выровнена по трем различным граням. Мы используем целое число для представления этих случаев,

0  yellow on U  (correct)
1  yellow on R  (120 degree clockwise)
2  yellow on F  (120 degree counterclockwise)

Пусть Cubie 1на DFL, его три возможных ориентации

0  yellow on D  (correct)
1  yellow on L  (120 degree clockwise)
2  yellow on F  (120 degree counterclockwise)

Когда мы анализируем ориентацию ребер, красный и оранжевый игнорируются, а желтый и белый игнорируются, только если у ребра есть зеленая или синяя грань.

Предположим, куби 10находится в исходном положении UR, зеленая грань может быть выровнена по двум разным граням. Его две возможные ориентации

0  green on R  (correct)
1  green on U  (180 degree)

Пусть Cubie 10на DF, его две возможные ориентации

0  green on D  (correct)
1  green on F  (180 degree)

Массив используется для хранения состояния куба. Начальное состояние куба

{{1,0},{2,0},{3,0},{4,0},{5,0},{6,0},{7,0},{8,0},{9,0},{10,0},{11,0},{12,0},{13,0},{14,0},{15,0},{16,0},{17,0},{18,0},{19,0},{20,0}}

это означает, что все кубики находятся в исходном положении с правильной ориентацией.

После того R, как состояние куба становится

{{5,2},{1,1},{3,0},{4,0},{6,1},{2,2},{7,0},{8,0},{9,0},{13,1},{11,0},{12,0},{18,1},{10,1},{15,0},{16,0},{17,0},{14,1},{19,0},{20,0}}

это означает, что 5теперь cubie находится в position 1( UFR) с ориентацией 2, cubie 1теперь находится в position 2( UBR) с ориентацией 1, cubie 3все еще находится в position 3( UBL) с ориентацией 0и так далее.


Контрольные примеры

p["FF'"]            (* 1   *)
p["R"]              (* 4   *)
p["RUR'U'"]         (* 6   *)
p["LLUUFFUURRUU"]   (* 12  *)
p["LUFFRDRBF"]      (* 56  *)
p["LF"]             (* 105 *)
p["UFFR'DBBRL'"]    (* 120 *)
p["FRBL"]           (* 315 *)
njpipeorgan
источник
7

Haskell, 252 байта

r=[-2..2]
s=mapM id[r,r,r]
t m p@[x,y,z]=case m of"R"|x>0->[x,z,-y];"L"|x<0->[x,-z,y];"U"|y>0->[-z,y,x];"D"|y<0->[z,y,-x];"F"|z>0->[y,-x,z];"B"|z<0->[-y,x,z];c:"'"->t[c]$t[c]$t[c]p;_->p
f m=length$s:fst(span(/=s)$tail$iterate(flip(foldl$flip$map.t)m)s)

Образцы прогонов:

*Main> f ["F","F'"]
1
*Main> f ["R"]
4
*Main> f ["R","U","R'","U'"]
6
*Main> f ["L","L","U","U","F","F","U","U","R","R","U","U"]
12
*Main> f ["L","U","F","F","R","D","R","B","F"]
56
*Main> f ["L","F"]
105
*Main> f ["U","F","F","R'","D","B","B","R","L'"]
120
*Main> f ["F","R","B","L"]
315
*Main> f ["R","U","U","D'","B","D'"]  -- maximum possible order
1260

Ключевое наблюдение здесь заключается в том, что кубик Рубика проще моделировать как сетку точек 5 × 5 × 5, а не как сетку ориентированных кубиков 3 × 3 × 3. Угловые кубики становятся кубами с размерами 2 × 2 × 2, краевые кубики становятся квадратами с размерами 2 × 2 × 1, а движения вращаются срезами по 5 × 5 × 2 точки.

Андерс Касеорг
источник
Это действительно умно! Я думаю, что замена c:"'"на c:_экономит два байта.
Линн
Благодарность! Я искал последовательность 1260 для тестовых случаев, но не потрудился найти ее :)
Geobits
@ Линн, это не работает, потому что _также соответствует пустому списку.
Андерс Касеорг
Это здорово, но, похоже, очень похоже на этот ответ на другой вопрос codegolf.stackexchange.com/a/44775/15599 . Если вы были вдохновлены этим, вы должны признать это.
Уровень Река St
@steveverrill, вау, это выглядит впечатляюще похоже, но нет, я этого не видел. Мой ответ - моя собственная независимая работа. (Конечно, я признаю, что Ян Дворжак придумал большинство таких же идей раньше, чем я.)
Андерс Касорг
7

Рубин, 225 байт

->s{n=0
a=[]
b=[]
64.times{|i|a<<j=[(i&48)-16,(i&12)-4,i%4-1];b<<j*1}
d=1
(n+=1
s.reverse.chars{|c|m="UFRDBL".index(c)
m ?(e=m/3*2-1
b.each{|j|j[m%=3]*e>0&&(j[m-2],j[m-1]=j[m-1]*e*d,-j[m-2]*e*d)}
d=1):d=-1})until n>0&&a==b
n}

Подобный ответ Андерс Kaseorg и вдохновленный Ян Дворжак ответа на предыдущий вопрос.

Однако, в отличие от этих ответов, мне не нужно 125 кубиков. Я использую кубик Рубика из 27 кубиков, но прямоугольных размеров. В решенном состоянии углы находятся на +/-1,+/-4,+/-16.

Я генерирую массив из 64 кубов, каждый с выбранным центром x=[-1,0,1,2], y=[-4,0,4,8], z=[-16-0,16,32]. Кубики с координатами 2, 8 и 32 не нужны, но они не причиняют вреда, поэтому их оставляют по соображениям игры в гольф. Тот факт, что длина, ширина и глубина кубов различны: (1,4,16) означает, что легко определить, находятся ли они в нужном месте, но имеют неправильную ориентацию.

Каждый кубик отслеживается, так как он перемещается по поворотам. Если координата куба на оси, соответствующей грани (умноженная на e=-1для U, F, R или e=1для D, B, L), положительна, то она будет повернута путем замены координат в двух других осях и применения соответствующее изменение знака одной из координат. Это контролируется умножением на e*d.

Входная последовательность сканируется в обратном порядке. Это не имеет значения, пока «нормальные» вращения выполняются против часовой стрелки, а не по часовой стрелке. Причина этого заключается в том, что если 'символ найден, значение dможно изменить с 1 на -1, чтобы вызвать поворот следующей грани в противоположном направлении.

Неуправляемый в тестовой программе

f=->s{n=0                                      #number of repeats=0
  a=[]                                         #empty array for solved position
  b=[]                                         #empty array for current position
  64.times{|i|
    a<<j=[(i&48)-16,(i&12)-4,i%4-1]            #generate 64 cubies and append them to the solved array
    b<<j*1                                     #duplicate them and append to active array
  }
  d=1                                          #default rotation direction anticlockwise (we scan the moves in reverse)                              
  (                                            #start of UNTIL loop
    n+=1                                       #increment repeat counter
    s.reverse.chars{|c|                        #reverse list of moves and iterate through it
      m="UFRDBL".index(c)                      #assign move letter to m (for ' or any other symbol m is false)
      m ?                                      #if a letter
        (e=m/3*2-1                             #e=-1 for UFR, 1 for DBL
        b.each{|j|                             #for each cubie 
          j[m%=3]*e>0&&                        #m%=3 picks an axis. If the cubie is on the moving face of the cube
         (j[m-2],j[m-1]=j[m-1]*e*d,-j[m-2]*e*d)#rotate it: exchange the coordinates in the other 2 axes and invert the sign of one of them according to direction
        }                                      #as per the values of e and d. 
        d=1                                    #set d=1 (in case it was -1 at the start of the b.each loop)
      ):
      d=-1                                     #ELSE the input must be a ', so set d=-1 to reverse rotation of next letter
    }
   )until n>0&&a==b                            #end of UNTIL loop. continue until back at start position a==b
n}                                             #return n

p f["FF'"]               #      1
p f["R"]                 #      4
p f["RUR'U'"]            #      6
p f["LLUUFFUURRUU"]      #     12
p f["LUFFRDRBF"]         #     56
p f["LF"]                #    105
p f["UFFR'DBBRL'"]       #    120
p f["FRBL"]              #    315
Уровень реки St
источник
7

Python 2, 343 байта

def M(o,v,e):
 k=1
 for m in e:
  for c in'ouf|/[bPcU`Dkqbx-Y:(+=P4cyrh=I;-(:R6'[m::6]:i=~ord(c)%8*k;j=(ord(c)/8-4)*k;o[i],o[j]=o[j]-m/2,o[i]+m/2;v[i],v[j]=v[j],v[i];k=-k
V=range(20)
o,v,e=[0]*20,V[:],[]
for c in raw_input():i='FBRLUD'.find(c);e+=i<0and e[-1:]*2or[i]
M(o,v,e);n=1
while any(o[i]%(2+i/12)for i in V)or v>V:M(o,v,e);n+=1
print n

Ввод взят из стандартного ввода.

Данная последовательность поворотов выполняется многократно на виртуальном кубе, пока не вернется в разрешенное состояние. Состояние куба сохраняется как вектор ориентации и вектор перестановки длиной 20.

Ориентации несколько произвольно определены: ребро куба ориентировано правильно, если его можно переместить на место, не вызывая четверть оборота R или L. Ориентация угловых кубов рассматривается относительно граней F и B.


Образец использования

$ echo FRBL|python rubiks-cycle.py
315

$ echo RULURFLF|python rubiks-cycle.py
1260

Демонстрация и тестирование онлайн .

Примо
источник
3
Хороший выбор имени функции и аргументов!
Нил
3

Clojure, 359 байтов

Это может быть мой второй самый длинный Codegolf. Понимая , я мог бы упасть конечные нули из векторов Aдля Fменя очень счастливым: D

#(let[I(clojure.string/replace % #"(.)'""$1$1$1")D(range -2 3)S(for[x D y D z D][x y z])A[0 1]B[0 0 1]C[1]D[-1]E[0 -1]F[0 0 -1]](loop[P S[[n R]& Q](cycle(map{\F[A[B A D]]\B[E[F A C]]\L[D[C B E]]\R[C[C F A]]\U[B[E C B]]\D[F[A D B]]}I))c 0](if(=(> c 0)(= P S))(/ c(count I))(recur(for[p P](if(>(apply +(map * n p))0)(for[r R](apply +(map * r p)))p))Q(inc c)))))

Менее гольф:

(def f #(let [I (clojure.string/replace % #"(.)'""$1$1$1")
              D [-2 -1 0 1 2]
              S (for[x D y D z D][x y z])
              L   {\F [[ 0  1  0][[0  0  1][ 0 1  0][-1  0 0]]]
                   \B [[ 0 -1  0][[0  0 -1][ 0 1  0][ 1  0 0]]]
                   \L [[-1  0  0][[1  0  0][ 0 0  1][ 0 -1 0]]]
                   \R [[ 1  0  0][[1  0  0][ 0 0 -1][ 0  1 0]]]
                   \U [[ 0  0  1][[0 -1  0][ 1 0  0][ 0  0 1]]]
                   \D [[ 0  0 -1][[0  1  0][-1 0  0][ 0  0 1]]]}]
          (loop [P S c 0 [[n R] & Q] (cycle(map L I))]
            (if (and (> c 0) (= P S))
              (/ c (count I))
              (recur (for[p P](if(pos?(apply +(map * n p)))
                                (for[r R](apply +(map * r p)))
                                p))
                     (inc c)
                     Q)))))

Это просто реализует трехмерные вращения выбранных подмножеств 5 x 5 x 5куба. Первоначально я собирался использовать, 3 x 3 x 3и мне потребовалось некоторое время, чтобы понять, почему я не получил правильные результаты. Хорошие тесты! Некоторые дополнительные байты для кодирования кулака "RUR'U'"как "RURRRUUU".

NikoNyrh
источник
3

Кубы , 9 6 байт

¶-7)8%

Попробуйте онлайн! (Не работает до тех пор, пока Деннис не обновит кубический переводчик TIO)

Объяснение:

¶-7)8%
¶       read a string, insert into code
 -7     add 1 to notepad (subtracts the 7th face "sum" from notepad, defaulted to -1)
   )8   jump back to start of code if cube unsolved
     %  print notepad

Этот язык будет доминировать над всеми >: D

MD XF
источник
3
Все эти новомодные эзоланги. Назад в мой день -7означало вычесть семь, а не добавить один сердито трясет ходока
caird coinheringaahing
@cairdcoinheringaahing Действительно. : P Добавил некоторые объяснения вокруг этого.
MD XF
1

Чисто , 255 байт

Полученный отдельно от почти идентичного ответа на Haskell в качестве ответа на этот вопрос, который был закрыт как дубликат, когда он был почти закончен, поэтому я разместил ответ здесь.

import StdEnv,StdLib
a=[-2..2];b=diag3 a a a
?m=iter(size m*2-1)\p=:(x,y,z)=case m.[0]of'F'|z>0=(y,~x,z);'U'|y>0=(~z,y,x);'R'|x>0=(x,z,~y);'B'|z<0=(~y,x,z);'D'|y<0=(z,y,~x);'L'|x<0=(x,~z,y);_=p
$l=length(takeWhile((<>)b)(tl(iterate(map(sseq(map?l)))b)))+1

Попробуйте онлайн!

Οurous
источник