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 2
movimentos 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;
}
}
}
fonte
Respostas:
Pitão,
6663 bytesExperimente 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
2
movimentos duplos.Explicação completa:
Analisar embaralhar:
Primeiro, lidarei com as marcas primas
'
nas strings de entrada. Simplesmente substituo-os por3
e 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"UDLRFB
atribui a string com todos os 6 movimentos paraZ
.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
.yZ
gera 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: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 umR
movimento? O adesivo noU
rosto se move para oB
rosto, o adesivoF
se move para oU
rosto e o adesivo noR
rosto permanece noR
rosto. Podemos dizer que a peçaURF
se move para a posiçãoBRU
. Esse padrão é verdadeiro para todas as peças do lado direito. Cada adesivo que está nasF
rosto se move para oU
rosto quando umR
movimento é realizado, cada etiqueta que está noU
rosto se move para oB
rosto, cada etiqueta nosB
move paraD
e cada etiqueta sobreD
move-se paraF
. Podemos decodificar as mudanças de umR
movimento comoFUBD
.O código a seguir gera todos os 6 códigos necessários:
E executamos uma mudança
H
para o estado do cubo daG
seguinte maneira: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.
fonte
GAP,
792 783 782749650 BytesIsso 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á-loX^3
.Exemplo de uso:
f("R");
Aqui está o código não destruído, com um pouco de explicação
fonte
45
por5
suas permutações e salvar três bytes.A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;
é mais curto do que sua definição paraD
(mas não posso testá-lo ...)^-1
para inversos, aliás?Mathematica,
413401 bytesExplicações
O Cubo de Rubik é composto por 20 cubículos móveis (8 cantos, 12 arestas). Cada cubo pode receber um número:
cantos :
bordas :
Observe que quando o cubo é torcido, os cubos geralmente não estão mais em suas posições iniciais. Por exemplo, quando
R
terminar, o cubo1
se moveráUFR
para uma nova posiçãoUBR
.Em tal notação, uma curva de 90 graus pode ser descrita por 8 movimentos de cubos. Por exemplo,
R
é descrito porComo cada cubo possui uma posição inicial única, cada posição possui um cubo inicial exclusivo. Ou seja, a regra
UFR->UBR
é justa1->2
(significa queR
leva o cubo na posição inicial do cubo1
para a posição inicial do cubo2
). Assim,R
pode ser simplificado ainda mais para um cicloPara 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 é
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
1
esteja em sua posição inicialUFR
, a faceta amarela pode estar alinhada com três faces diferentes. Usamos um número inteiro para representar esses casos,Suponha que o cubie
1
esteja ativadoDFL
, suas três orientações possíveis sãoAo 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
10
esteja em sua posição inicialUR
, a faceta verde pode estar alinhada com duas faces diferentes. Suas duas orientações possíveis sãoSuponha que o cubie
10
esteja ativadoDF
, suas duas orientações possíveis sãoUma matriz é usada para armazenar o estado de um cubo. O estado inicial de um cubo é
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-seo que significa que o cubo
5
agora está na posição1
(UFR
) com orientação2
, o cubo1
agora está na posição2
(UBR
) com orientação1
, o cubo3
ainda está na posição3
(UBL
) com orientação0
e assim por diante.Casos de teste
fonte
Haskell, 252 bytes
Amostras de execuções:
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.
fonte
c:"'"
porc:_
salva dois bytes._
também corresponde à lista vazia.Ruby, 225 bytes
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=-1
U, F, R oue=1
D, 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 pore*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 ded
pode ser alterado de 1 para -1 para causar a rotação da face a seguir na direção oposta.Ungolfed in program program
fonte
Python 2, 343 bytes
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
Conjunto de demonstração e teste on-line .
fonte
Clojure, 359 bytes
Este pode ser o meu segundo codegolf mais longo. Percebendo que eu poderia soltar zeros à direita de vetores
A
paraF
me deixar muito feliz: DMenos golfe:
Isso simplesmente implementa rotações 3D de subconjuntos selecionados de
5 x 5 x 5
cubo. Originalmente eu ia usar3 x 3 x 3
e 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"
.fonte
Cubicamente ,
96 bytesExperimente online! (Não funciona até Dennis atualizar o intérprete TIO Cubically)
Explicação:
Esse idioma dominará todos os desafios do cubo de rubiks >: D
fonte
-7
significava subtrair sete não adicionar uma raiva sacode walkerLimpo , 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.
Experimente online!
fonte