Ciclismo con Rubik's

43

Mientras giraba ociosamente el cubo de mi Rubik , mi hijo notó que seguía volviendo al estado resuelto. Estoy bastante seguro de que al principio pensó que esto era una especie de magia vudú, pero le expliqué que si sigue repitiendo la misma secuencia de movimientos, siempre volverá a su estado original. Finalmente.

Por supuesto, siendo un niño, tuvo que probarlo por sí mismo y eligió una secuencia "aleatoria" que pensó que sería difícil. Perdió la pista después de diez repeticiones más o menos, y me preguntó cuántas veces tendría que repetirla. Sin saber la secuencia que estaba usando, le dije que no sabía, pero que podíamos escribir un programa para averiguarlo.

Aquí es donde entras tú. Por supuesto, podría preparar algo, pero a él le gustaría escribirlo él mismo. Sin embargo, todavía no es un mecanógrafo muy rápido, así que necesito el programa más corto posible .

Objetivo

Dada una secuencia de giros, genera la menor cantidad de veces que se debe realizar para devolver el cubo a su estado original. Este es el código de golf, por lo que gana menos bytes. Puede escribir un programa o función, y se aplican todos los demás valores predeterminados habituales.

Entrada

La entrada es una secuencia de movimientos, tomada como una cadena, lista u otro formato adecuado para su idioma. Siéntase libre de usar un separador (o no) entre movimientos si está en forma de cadena.

Hay seis movimientos "básicos" que deben tenerse en cuenta, junto con sus inversas:

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

Las inversas se representan agregando una marca principal 'después de la letra. Esto indica que gira esa cara en sentido antihorario, por lo que F'gira la cara frontal en sentido antihorario y la F F'devolverá al estado original de inmediato.

Para los interesados, este desafío está utilizando un conjunto limitado de notación Singmaster . Ruwix tiene algunas animaciones agradables si desea verlo en acción.

Salida

La salida es simplemente el número mínimo de veces que se debe realizar la secuencia de entrada.

Ejemplos

Input                Output

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

Aquí hay un solucionador (bastante ingenuo) para comparar sus respuestas, escrito en Java. También acepta 2movimientos dobles (por lo que el cuarto caso es equivalente a 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
fuente
"en el sentido de las manecillas del reloj" significa "en el sentido de las manecillas del reloj"
msh210
@ msh210 Correcto.
Geobits
77
En un punto de pedantería, creo que debes hacer explícito que quieres el número más pequeño que sea suficiente. De lo contrario, podría simplemente mostrar el tamaño del grupo y citar el teorema de Lagrange ...
Peter Taylor
2
@PeterTaylor Pedantry aceptó.
Geobits
44
Me puede ofrecer una recompensa de 500 puntos para una solución en Aleatorio. No estoy seguro todavía.
lirtosiast

Respuestas:

16

Pyth, 66 63 bytes

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

Pruébelo en línea: Demostración o Test Suite . Observe que el programa es un poco lento y el compilador en línea no puede calcular la respuesta RU2D'BD'. Pero tenga la seguridad de que puede calcularlo en mi computadora portátil en aproximadamente 12 segundos.

El programa (accidentalmente) también acepta 2movimientos dobles.

Explicación completa:

Parse scramble:

Primero me ocuparé de las marcas principales 'en las cadenas de entrada. Simplemente los reemplazo 3y decodifico esta cadena con longitud de ejecución. Dado que el formato de decodificación de Pyth requiere el número delante del carácter, invierto la cadena de antemano. _r_Xz\'\39. Así que luego lo revierto.

Describa el estado del cubo resuelto:

=Z"UDLRFBasigna la cadena con los 6 movimientos a Z.

Podemos describir un estado de cubo describiendo la ubicación de cada pieza de cubo. Por ejemplo, podemos decir que el borde, que debería estar en UL (arriba a la izquierda) está actualmente en FR (frente a la derecha). Para esto necesito para generar todas las piezas del cubo resuelto: f!s}RTcZ2yZ. yZgenera todos los subconjuntos posibles de "UDLRFB". Obviamente, esto también genera el subconjunto "UDLRFB"y el subconjunto "UD". El primero no tiene ningún sentido, ya que no hay una pieza que sea visible desde los 6 lados, y el segundo no tiene ningún sentido, ya que no hay una pieza de borde, que es visible desde la parte superior e inferior. . Por lo tanto, elimino todos los subconjuntos, que contienen la subsecuencia "UD", "LR"o "FB". Esto me da las siguientes 27 piezas:

'', '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'

Esto también incluye la cadena vacía y las seis cadenas de 1 letra. Podríamos interpretarlos como la pieza en el medio del cubo y las 6 piezas centrales. Obviamente no son necesarios (ya que no se mueven), pero los guardaré.

Haciendo algunos movimientos:

Haré algunas traducciones de cadenas para realizar un movimiento. Para visualizar la idea, mira la pieza de la esquina URF. ¿Qué le sucede cuando hago un Rmovimiento? La pegatina en la Ucara se mueve hacia la Bcara, la pegatina se Fmueve hacia la Ucara y la pegatina en la Rcara permanece en la Rcara. Podemos decir que la pieza en se URFmueve a la posición BRU. Este patrón es cierto para todas las piezas en el lado derecho. Cada pegatina que está en la Fcara se mueve hacia la Ucara cuando Rse realiza un movimiento, cada pegatina que está en la Ucara se mueve hacia la Bcara, cada pegatina en los Bmovimientos hacia Dy cada pegatina en los Dmovimientos haciaF. Podemos decodificar los cambios de un Rmovimiento como FUBD.

El siguiente código genera los 6 códigos necesarios:

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

Y realizamos un movimiento Hal estado del cubo de la Gsiguiente manera:

m.rW}[email protected]
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)

Cuenta el número de repeticiones:

El resto es bastante trivial. Simplemente realizo la codificación de entrada al cubo resuelto una y otra vez hasta llegar a una posición que visité anteriormente.

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
fuente
13

GAP, 792 783 782 749 650 Bytes

Esto parece estar funcionando. Si se equivoca con algo, hágamelo saber.

Gracias a @Lynn por sugerir que descomponga algunos de los movimientos primitivos.

Gracias a @Neil por sugerir que en lugar de Inverse(X)usar X^3.

Ejemplo de uso: 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;

Aquí está el código no golfista con un poco de explicación.

  # 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
fuente
Cada movimiento es una cuarta raíz de la identidad, por lo que su Inverso es innecesario.
Neil
Probablemente pueda reemplazar 45con 5en sus permutaciones y guardar tres bytes.
Lynn
Un resultado de Benson que encontré en Singmaster, 1981 dice: "Sea A = RL⁻¹F²B²RL⁻¹, luego AUA = D". De hecho, A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;es más corto que su definición de D(pero no puedo probarlo ...)
Lynn
¿GAP realmente no te permite escribir ^-1para inversas, por cierto?
Lynn
Sí, totalmente espaciado al usar ^ -1. Lo que supongo es más o menos lo mismo que @Neil decía, excepto con ^ 3 en su lugar (que en realidad es el más corto). Además, sí, podría descomponer los movimientos en otros movimientos, y debería poder guardar varios bytes al hacerlo, solo sería cuestión de encontrar la descomposición más corta.
Liam
10

Mathematica, 413 401 bytes

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

Explicaciones

Un cubo de Rubik está compuesto por 20 cubos móviles (8 esquinas, 12 bordes). A cada cubito se le puede dar un número:

esquinas :

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

bordes :

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

Tenga en cuenta que cuando el cubo está torcido, los cubos generalmente ya no están en sus posiciones iniciales. Por ejemplo, cuando Rse hace, el cubito se 1mueve desde UFRuna nueva posición UBR.

En tal notación, un giro de 90 grados se puede describir con 8 movimientos de cubos. Por ejemplo, Rse describe por

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

Como cada cubito tiene una posición inicial única, cada posición tiene un cubo inicial único. Es decir, la regla UFR->UBRes justa 1->2(significa que Rlleva el cubito en la posición inicial del cubo 1a la posición inicial del cubo 2). Por lo tanto, Rse puede simplificar más a un ciclo

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

Para resolver completamente un cubo de Rubik, también necesitamos alinear los cubos con sus orientaciones iniciales correspondientes. Las caras de un cubo están pintadas en diferentes colores, el esquema que uso a menudo para resolver cubos es

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

Cuando analizamos las orientaciones de las esquinas, se ignoran los colores que no sean amarillo o blanco, y el amarillo y el blanco se consideran del mismo color.

Supongamos que el cubo 1está en su posición inicial UFR, la faceta amarilla puede estar alineada con tres caras diferentes. Usamos un número entero para representar estos casos,

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

Supongamos que cubie 1está activado DFL, sus tres orientaciones posibles son

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

Cuando analizamos las orientaciones de los bordes, se ignoran el rojo y el naranja, y el amarillo y el blanco se ignoran solo si el borde tiene una faceta verde o azul.

Supongamos que el cubo 10está en su posición inicial UR, la faceta verde puede estar alineada con dos caras diferentes. Sus dos orientaciones posibles son

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

Supongamos que cubie 10está activado DF, sus dos orientaciones posibles son

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

Una matriz se usa para almacenar el estado de un cubo. El estado inicial de un cubo es

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

lo que significa que cada cubito está en su posición inicial con la orientación correcta.

Después R, el estado del cubo se convierte en

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

lo que significa que el cubo 5ahora está en posición 1( UFR) con orientación 2, el cubo 1ahora está en posición 2( UBR) con orientación 1, el cubo 3todavía está en posición 3( UBL) con orientación 0, y así sucesivamente.


Casos de prueba

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
fuente
7

Haskell, 252 bytes

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)

Ejecuciones de muestra:

*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

La observación clave aquí es que es más simple modelar el cubo de Rubik como una cuadrícula de puntos de 5 × 5 × 5 en lugar de una cuadrícula de cubos orientados de 3 × 3 × 3. Los cubos de esquina se convierten en cubos de 2 × 2 × 2 puntos, los cubos de borde se convierten en cuadrados de 2 × 2 × 1 puntos y se mueven rotando rodajas de 5 × 5 × 2 puntos.

Anders Kaseorg
fuente
¡Esto es realmente inteligente! Creo que reemplazar c:"'"con c:_salva dos bytes.
Lynn
¡Gracias! Estaba buscando una secuencia de 1260 para los casos de prueba, pero no me
molesté en buscarla
@ Lynn, eso no funciona porque _también coincide con la lista vacía.
Anders Kaseorg
Esto es genial, pero parece muy similar a esta respuesta a otra pregunta codegolf.stackexchange.com/a/44775/15599 . Si te inspiraste con eso, deberías reconocerlo.
Level River St
@steveverrill, wow, eso se ve impresionantemente similar, pero no, no lo había visto. Mi respuesta es mi propio trabajo independiente. (Reconozco, por supuesto, que a Jan Dvorak se le ocurrieron la mayoría de las mismas ideas antes que yo).
Anders Kaseorg
7

Ruby, 225 bytes

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

Similar a la respuesta de Anders Kaseorg e inspirado por la respuesta de Jan Dvorak a una pregunta anterior.

Sin embargo, a diferencia de esas respuestas, no necesito 125 cubitos. Utilizo un cubo de rubik de 27 cubos, pero de dimensiones rectangulares. En el estado resuelto, las esquinas están en +/-1,+/-4,+/-16.

Genero una matriz de 64 cubos, cada uno con un centro elegido x=[-1,0,1,2], y=[-4,0,4,8], z=[-16-0,16,32]. Los cubos con coordenadas de 2, 8 y 32 son innecesarios, pero no causan daño, por lo que se dejan adentro por razones de golf. El hecho de que la longitud, el ancho y la profundidad de los cubos sean diferentes: (1,4,16) significa que es fácil detectar si están en el lugar correcto pero con una orientación incorrecta.

Cada cubito se rastrea a medida que lo mueven las facetas. Si la coordenada de un cubo en el eje correspondiente a la cara (multiplicada por e=-1U, F, R o e=1D, B, L) es positiva, se rotará intercambiando las coordenadas en los otros 2 ejes y aplicando un cambio de signo apropiado a una de las coordenadas. Esto se controla multiplicando por e*d.

La secuencia de entrada se escanea en orden inverso. Esto no hace ninguna diferencia, siempre que las rotaciones "normales" se realicen en sentido antihorario en lugar de hacerlo en sentido horario. La razón de esto es que si 'se encuentra un símbolo, el valor de dse puede cambiar de 1 a -1 para provocar la rotación de la siguiente cara en la dirección opuesta.

Sin golf en el programa de prueba

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
Level River St
fuente
7

Python 2, 343 bytes

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

La entrada se toma de stdin.

La secuencia de giros dada se realiza repetidamente en un cubo virtual hasta que regrese al estado resuelto. El estado del cubo se almacena como un vector de orientación y un vector de permutación, ambos de longitud 20.

Las orientaciones se definen de manera arbitraria: un cubo de arista está orientado correctamente si se puede mover a su lugar sin invocar un cuarto de vuelta R o L. La orientación de los cubos de esquina se considera relativa a las caras F y B.


Uso de muestra

$ echo FRBL|python rubiks-cycle.py
315

$ echo RULURFLF|python rubiks-cycle.py
1260

Demostración en línea y conjunto de pruebas .

primo
fuente
3
¡Buena elección de nombre de función y argumentos!
Neil
3

Clojure, 359 bytes

Este podría ser mi segundo codegolf más largo. Al darme cuenta de que podía eliminar los ceros finales de los vectores Apara Fhacerme muy feliz: 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)))))

Menos golfizado:

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

Esto simplemente implementa rotaciones 3D de subconjuntos seleccionados de 5 x 5 x 5cubos. Originalmente iba a usar 3 x 3 x 3y me tomó un tiempo darme cuenta de por qué no obtenía los resultados correctos. ¡Buenos casos de prueba! Algunos bytes adicionales para la codificación de puño "RUR'U'"como "RURRRUUU".

NikoNyrh
fuente
3

Cúbicamente , 9 6 bytes

¶-7)8%

Pruébalo en línea! (No funciona hasta que Dennis actualice el intérprete de TIO Cubically)

Explicación:

¶-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

Este lenguaje dominará todos los >: D

MD XF
fuente
3
Todos estos esolangs novedosos. De vuelta en mi día, -7significaba restar siete, no agregar un andador enojado
caird coinheringaahing
@cairdcoinheringaahing De hecho. : P Agregó alguna explicación al respecto.
MD XF
1

Limpio , 255 bytes

Derivado por separado de la respuesta casi idéntica de Haskell como respuesta a esta pregunta que se cerró como un duplicado cuando estaba casi terminada, así que publiqué la respuesta aquí.

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

Pruébalo en línea!

Οurous
fuente