Pedalando com o Rubik


43

Enquanto torcia ociosamente o cubo de Rubik , meu filho percebeu que ele continuava voltando ao estado resolvido. Tenho certeza que ele pensou que isso era algum tipo de magia vodu no começo, mas expliquei que, se você continuar repetindo a mesma sequência de movimentos, ele sempre retornará ao seu estado original. Eventualmente.

É claro que, quando criança, ele teve que experimentar por conta própria e escolheu uma sequência "aleatória" que achou difícil. Ele perdeu o rumo depois de dez repetições, e me perguntou quantas vezes ele teria que repeti-lo. Sem saber a sequência que ele estava usando, eu disse a ele que não sabia, mas que poderíamos escrever um programa para descobrir.

É aqui que você entra. Claro, eu poderia apenas preparar algo, mas ele gostaria de digitar nele mesmo. No entanto, ele ainda não é um datilógrafo muito rápido, então preciso do programa mais curto possível .

Objetivo

Dada uma sequência de voltas, produza o menor número de vezes que deve ser executada para retornar o cubo ao seu estado original. Isso é código de golfe, então o mínimo de bytes vence. Você pode escrever um programa ou função e todos os outros padrões usuais se aplicam.

Entrada

Entrada é uma sequência de movimentos, tomados como uma sequência, lista ou outro formato adequado ao seu idioma. Sinta-se livre para usar um separador (ou não) entre os movimentos, se estiver em forma de string.

Existem seis movimentos "básicos" que devem ser levados em consideração, juntamente com seus inversos:

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

Os inversos são representados pela adição de uma marca de prime 'após a letra. Isso indica que você gira a face no sentido anti-horário, F'gira a face frontal no sentido anti-horário e F F'o retorna ao estado original imediatamente.

Para os interessados, esse desafio está usando um conjunto limitado de Notação Singmaster . Ruwix tem algumas animações agradável se você gostaria de vê-lo em ação.

Resultado

A saída é simplesmente o número mínimo de vezes que a sequência de entrada deve ser executada.

Exemplos

Input                Output

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

Aqui está um solucionador (bastante ingênuo) para comparar suas respostas, escrito em Java. Também aceita 2movimentos duplos (portanto, o quarto caso é 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;
        }
    }
}

"sentido horário" significa "sentido horário quando você está de frente para ele", presumo?
Msh210

@ msh210 Correto.
Geobits 03/02

7
Em um ponto da pediatria, acho que você deve deixar explícito que deseja o menor número suficiente. Caso contrário, eu poderia apenas a saída do tamanho do grupo e citar o teorema de Lagrange ...
Peter Taylor

2
@PeterTaylor Pedantry aceito.
Geobits 03/02

4
I pode oferecer uma recompensa de 500 pontos para uma solução em Shuffle. Ainda não tenho certeza.
precisa saber é o seguinte

Respostas:


16

Pitão, 66 63 bytes

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

Experimente on-line: Demonstration ou Test Suite . Observe que o programa é meio lento e o compilador on-line não pode calcular a resposta RU2D'BD'. Mas tenha certeza de que ele pode ser calculado no meu laptop em cerca de 12 segundos.

O programa (acidentalmente) também aceita 2movimentos duplos.

Explicação completa:

Analisar embaralhar:

Primeiro, lidarei com as marcas primas 'nas strings de entrada. Simplesmente substituo-os por 3e decodifique em comprimento de execução essa sequência. Como o formato de decodificação de Pyth exige o número na frente do caractere, eu inverto a string antes. _r_Xz\'\39. Então depois eu inverto isso de volta.

Descreva o estado do cubo resolvido:

=Z"UDLRFBatribui a string com todos os 6 movimentos para Z.

Podemos descrever um estado do cubo descrevendo a localização de cada peça do cubo. Por exemplo, podemos dizer que a borda, que deveria estar em UL (Acima-Esquerda), está atualmente em FR (Frente-Direita). Para isso eu preciso para gerar todas as peças do cubo resolvido: f!s}RTcZ2yZ. yZgera todos os subconjuntos possíveis de "UDLRFB". Obviamente, isso também gera o subconjunto "UDLRFB"e o subconjunto "UD". O primeiro não faz sentido, uma vez que não há peça visível dos 6 lados, e o segundo não faz sentido, já que não há peça de aresta visível do topo e do fundo . Portanto, eu remover todos os subconjuntos, que contêm a subsequência "UD", "LR"ou "FB". Isso me dá as seguintes 27 partes:

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

Isso também inclui a cadeia vazia e todas as seis cadeias de caracteres de 1 letra. Poderíamos interpretá-los como a peça no meio do cubo e as 6 peças centrais. Obviamente eles não são necessários (já que não se movem), mas eu os guardarei.

Fazendo alguns movimentos:

Vou fazer algumas traduções de string para executar uma mudança. Para visualizar a idéia, observe a peça de canto URF. O que acontece quando eu faço um Rmovimento? O adesivo no Urosto se move para o Brosto, o adesivo Fse move para o Urosto e o adesivo no Rrosto permanece no Rrosto. Podemos dizer que a peça URFse move para a posição BRU. Esse padrão é verdadeiro para todas as peças do lado direito. Cada adesivo que está nas Frosto se move para o Urosto quando um Rmovimento é realizado, cada etiqueta que está no Urosto se move para o Brosto, cada etiqueta nos Bmove para De cada etiqueta sobre Dmove-se paraF. Podemos decodificar as mudanças de um Rmovimento como FUBD.

O código a seguir gera todos os 6 códigos necessários:

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

E executamos uma mudança Hpara o estado do cubo da Gseguinte maneira:

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)

Conte o número de repetições:

O resto é praticamente trivial. Simplesmente executo a corrida de entrada para o cubo resolvido repetidamente até chegar a uma posição que visitei 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

13

GAP, 792 783 782 749 650 Bytes

Isso parece estar funcionando. Se mexer com alguma coisa, me avise.

Agradeço a @Lynn por sugerir que eu decomponha alguns dos movimentos primitivos.

Obrigado a @ Neil por sugerir que, em vez de Inverse(X)eu usá-lo X^3.

Exemplo 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;

Aqui está o código não destruído, com um pouco de explicação

  # 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;

Cada movimento é uma quarta raiz da identidade, portanto seu Inverso é desnecessário.
Neil

Você provavelmente pode substituir 45por 5suas permutações e salvar três bytes.
Lynn

Um resultado de Benson que encontrei no Singmaster, 1981, diz: “Deixe A = RL⁻¹F²B²RL⁻¹, depois AUA = D.” De fato, A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;é mais curto do que sua definição para D(mas não posso testá-lo ...)
Lynn

O GAP realmente não permite que você escreva ^-1para inversos, aliás?
Lynn

Sim, eu totalmente espaçado usando ^ -1. O que eu suponho é praticamente a mesma coisa que @Neil estava dizendo, exceto com ^ 3 (o que é realmente o mais curto). Além disso, sim, eu poderia decompor movimentos em outros movimentos e conseguir salvar vários bytes ao fazê-lo, seria apenas uma questão de encontrar a decomposição mais curta.
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

Explicações

O Cubo de Rubik é composto por 20 cubículos móveis (8 cantos, 12 arestas). Cada cubo pode receber um número:

cantos :

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

bordas :

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

Observe que quando o cubo é torcido, os cubos geralmente não estão mais em suas posições iniciais. Por exemplo, quando Rterminar, o cubo 1se moverá UFRpara uma nova posição UBR.

Em tal notação, uma curva de 90 graus pode ser descrita por 8 movimentos de cubos. Por exemplo, Ré descrito por

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

Como cada cubo possui uma posição inicial única, cada posição possui um cubo inicial exclusivo. Ou seja, a regra UFR->UBRé justa 1->2(significa que Rleva o cubo na posição inicial do cubo 1para a posição inicial do cubo 2). Assim, Rpode ser simplificado ainda mais para um ciclo

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

Para resolver completamente um cubo de Rubik, também precisamos alinhar os cubos às suas orientações iniciais correspondentes. As faces de um cubo são pintadas em cores diferentes, o esquema que costumo usar para resolver cubos é

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

Ao analisar as orientações dos cantos, outras cores além de amarelo ou branco são ignoradas e amarelo e branco são considerados da mesma cor.

Suponha que o cubo 1esteja em sua posição inicial UFR, a faceta amarela pode estar alinhada com três faces diferentes. Usamos um número inteiro para representar esses casos,

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

Suponha que o cubie 1esteja ativado DFL, suas três orientações possíveis são

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

Ao analisar as orientações das bordas, vermelho e laranja são ignorados e amarelo e branco são ignorados apenas se a borda tiver uma faceta verde ou azul.

Suponha que o cubo 10esteja em sua posição inicial UR, a faceta verde pode estar alinhada com duas faces diferentes. Suas duas orientações possíveis são

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

Suponha que o cubie 10esteja ativado DF, suas duas orientações possíveis são

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

Uma matriz é usada para armazenar o estado de um cubo. O estado inicial de um cubo é

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

o que significa que todos os cubos estão na posição inicial com a orientação correta.

Depois R, o estado do cubo torna-se

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

o que significa que o cubo 5agora está na posição 1( UFR) com orientação 2, o cubo 1agora está na posição 2( UBR) com orientação 1, o cubo 3ainda está na posição 3( UBL) com orientação 0e assim por diante.


Casos de teste

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

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)

Amostras de execuções:

*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

A principal observação aqui é que é mais simples modelar o cubo de Rubik como uma grade de pontos 5 × 5 × 5 em vez de uma grade 3 × 3 × 3 de cubos orientados. Cubos de canto tornam-se cubos de 2 × 2 × 2 pontos, cubos de borda tornam-se quadrados de 2 × 2 × 1 pontos e movimentos rotacionam fatias de 5 × 5 × 2 pontos.


Isso é realmente inteligente! Eu acho que substituindo c:"'"porc:_ salva dois bytes.
Lynn

Obrigado! Eu estava procurando por uma seqüência 1260 para os casos de teste, mas não podia ser incomodado olhando-o :)
Geobits

@ Lynn, isso não funciona porque _ também corresponde à lista vazia.
Anders Kaseorg

Isso é ótimo, mas parece muito semelhante a esta resposta a outra pergunta codegolf.stackexchange.com/a/44775/15599 . Se você foi inspirado por isso, deve reconhecê-lo.
Level River St

@steveverrill, uau, isso parece impressionantemente semelhante, mas não, eu não tinha visto. Minha resposta é meu próprio trabalho independente. (Eu reconheço, é claro, que Jan Dvorak veio com a maioria das mesmas ideias antes de mim.)
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}

Semelhante a resposta de Anders Kaseorg e inspirado por Jan Dvorak resposta a uma pergunta anterior.

No entanto, ao contrário dessas respostas, não preciso de 125 cubos. Eu uso o cubo de 27 cubos de rubik, mas com dimensões retangulares. No estado resolvido, os cantos estão em +/-1,+/-4,+/-16.

Eu gero uma matriz de 64 cubos, cada um com um centro escolhido x=[-1,0,1,2], y=[-4,0,4,8], z=[-16-0,16,32]. Os cubos com coordenadas 2, 8 e 32 são desnecessários, mas como não causam danos, são deixados por motivos de golfe. O fato de o comprimento, a largura e a profundidade dos cubículos serem diferentes: (1,4,16) significa que é fácil detectar se eles estão no lugar certo, mas com orientação incorreta.

Cada cubo é rastreado conforme é movido pelas faces facetadas. Se a coordenada de um cubo no eixo correspondente à face (multiplicada por e=-1U, F, R ou e=1D, B, L) for positiva, ela será girada trocando as coordenadas nos outros 2 eixos e aplicando uma mudança de sinal apropriada para uma das coordenadas. Isso é controlado multiplicando por e*d.

A sequência de entrada é digitalizada na ordem inversa. Isso não faz diferença, desde que as rotações "normais" sejam realizadas no sentido anti-horário, em vez de no sentido horário. A razão para isso é que, se um 'símbolo for encontrado, o valor de dpode ser alterado de 1 para -1 para causar a rotação da face a seguir na direção oposta.

Ungolfed in program program

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

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

A entrada é retirada do stdin.

A sequência de torções especificada é executada repetidamente em um cubo virtual até retornar ao estado resolvido. O estado do cubo é armazenado como um vetor de orientação e vetor de permutação, ambos de comprimento 20.

As orientações são um tanto arbitrariamente definidas: um cubo de borda é orientado corretamente se puder ser movido para o lugar sem chamar um quarto de volta R ou L. A orientação dos cubos de canto é considerada em relação às faces F e B.


Uso da amostra

$ echo FRBL|python rubiks-cycle.py
315

$ echo RULURFLF|python rubiks-cycle.py
1260

Conjunto de demonstração e teste on-line .


3
Boa escolha do nome da função e argumentos!
Neil

3

Clojure, 359 bytes

Este pode ser o meu segundo codegolf mais longo. Percebendo que eu poderia soltar zeros à direita de vetores Apara Fme deixar muito 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 golfe:

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

Isso simplesmente implementa rotações 3D de subconjuntos selecionados de 5 x 5 x 5cubo. Originalmente eu ia usar 3 x 3 x 3e demorei um pouco para perceber por que não estava obtendo resultados corretos. Bons casos de teste! Alguns bytes extras para a primeira codificação "RUR'U'"como "RURRRUUU".


3

Cubicamente , 9 6 bytes

¶-7)8%

Experimente online! (Não funciona até Dennis atualizar o intérprete TIO Cubically)

Explicação:

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

Esse idioma dominará todos desafios do >: D


3
Todos esses esolangs novos. Na minha época, -7significava subtrair sete não adicionar uma raiva sacode walker
caird coinheringaahing

@cairdcoinheringaahing De fato. : P Adicionadas explicações sobre isso.
MD XF

1

Limpo , 255 bytes

Derivada separadamente da resposta quase idêntica de Haskell como resposta a esta pergunta, que foi fechada como duplicata quando estava quase concluída, então publiquei a resposta aqui.

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

Experimente online!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.