Escreva o programa mais curto que resolva o cubo de Rubik (3 * 3 * 3) dentro de um período de tempo e movimentos razoável (digamos, no máximo 5 segundos em sua máquina e menos de 1000 movimentos).
A entrada está no formato:
UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR
(essa entrada específica representa o cubo resolvido).
As primeiras 12 seqüências de caracteres de 2 caracteres são as arestas nas posições UF, UR, ... BL (U = para cima, F = frente, R = direita, B = atrás, L = esquerda, D = baixo), depois as próximas 8 Seqüências de caracteres de 3 caracteres são os cantos nas posições UFR, URB, ... DBR.
A saída deve fornecer uma sequência de movimentos neste formato:
D+ L2 U+ F+ D+ L+ D+ F+ U- F+
Onde D1 ou D + representa girar a face D (para baixo) no sentido horário 90 graus, L2 está girando a face L 180 graus, U3 ou U- representa girar a face U no sentido anti-horário 90 graus.
As letras não diferenciam maiúsculas de minúsculas e os espaços são opcionais.
Por exemplo, a saída acima está correta para a seguinte entrada:
RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU
Para mais detalhes, consulte o concurso de cubos de Tomas Rokicki , exceto que a pontuação será feita diretamente pelo tamanho do arquivo, como um problema normal de golfe no código. Um testador online também está incluído.
Para referência, a solução mais curta já escrita é a última entrada na lista de vencedores do concurso de cubos
Para aqueles que lutam para visualizar o formato do layout:
0-1 2-3 4-5 6-7 8-9 10-11 12-13 14-15 16-17 18-19 20-21 22-23 24-25-26 27-28-29 30-31-32 33-34-35 36-37-38 39-40-41 42-43-44 45-46-47
UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR
Front:
+-------+-------+-------+
/ / / /|
/ 30 / 4 / 27 / |
+-------+-------+-------+ |
/ / / /|28+
/ 6 / / 2 / | /|
+-------+-------+-------+ |/ |
/ / / /|3 + |
/ 33 / 0 / 24 / | /|21+
+-------+-------+-------+ |/ | /|
| | | |26+ |/ |
| 35 | 1 | 25 | /| + |
| | | |/ | /|47+
+-------+-------+-------+ |/ | /
| | | |17+ |/
| 18 | | 16 | /|11+
| | | |/ | /
+-------+-------+-------+ |/
| | | |37+
| 40 | 9 | 38 | /
| | | |/
+-------+-------+-------+
Hidden faces:
+-------+-------+-------+
/| | | |
/ | 31 | 5 | 29 |
+ | | | |
/|32+-------+-------+-------+
/ | /| | | |
+ |/ | 22 | | 20 |
/|7 + | | | |
/ | /|23+-------+-------+-------+
+ |/ | /| | | |
|34+ |/ | 44 | 13 | 46 |
| /| + | | | |
|/ | /|43+-------+-------+-------+
+ |/ | / / / /
|19+ |/ 42 / 12 / 45 /
| /|15+-------+-------+-------+
|/ | / / / /
+ |/ 14 / / 10 /
|41+-------+-------+-------+
| / / / /
|/ 39 / 8 / 36 /
+-------+-------+-------+
fonte
Respostas:
C ++ - 1123
Como ninguém postou nenhuma resposta até agora, decidi simplificar e usar a minha solução de 2004. Ainda está muito atrás do mais curto que mencionei na pergunta.
Não é aleatório, mas também não é direto. Ele resolve as bordas primeiro e depois os cantos. Em cada etapa, ele tenta várias combinações de até 4 algoritmos e giros simples de faces (sequencialmente, não aleatoriamente), até encontrar uma melhoria no número de peças resolvidas e depois repetir até ser resolvido. Ele usa 2 algoritmos para arestas e 2 para cantos, traduzidos para todas as posições do cubo.
Exemplo de saída para
RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU
:L2F3B2F3B1U3F1B3R2F3B1U3F1B3D2F2L3D2L1U2B1L1R3U2R1L3B1U2R1U2L1F1B3U2B1F3L1U2L3R1D3L1R3B2L3R1D3L1R3L3R1D3L1R3B2L3R1D3L1R3B3F1D3B1F3R2B3F1D3B1F3U2F3L3R1B3L1R3U2L3R1B3L1R3F1D2F1L1R3D2R1L3F1D2F3L2U1B1F3L2F1B3U1L2R3L1F3R1L3U2R3L1F3R1L3U1F2U1L1R3F2R1L3U1F2U3L3U3L1U3L3U2L1R1U1R3U1R1U2R3F3U3F1U3F3U2F1B1U1B3U1B1U2B3L1B3R3B1L3B3R1B1B3D3B1D3B3D2B1F1D1F3D1F1D2F3R1F3L3F1R3F3L1F1R3B3R1B3R3B2R1L1B1L3B1L1B2L3R1D3L3D1R3D3L1D1B3D3B1D3B3D2B1F1D1F3D1F1D2F3U3R3U1R3U3R2U1D1R1D3R1D1R2D3
(234 movimentos, 0,3 s aqui)
fonte
Python 1166 bytes
Uma quantidade considerável de espaço em branco foi deixada para facilitar a leitura. Tamanho é medido depois de remover este espaço em branco, e alterando vários níveis de recuo para
Tab
,Tab
Space
,Tab
Tab
, etc. Eu também evitou qualquer golfe que afetou o desempenho muito drasticamente.Uso da amostra:
Esta é uma implementação do algoritmo de Thistlethwaite, usando uma pesquisa IDA * para resolver cada etapa. Como todas as tabelas heurísticas precisam ser calculadas em tempo real, vários compromissos foram feitos, geralmente dividindo uma heurística em duas ou mais partes de tamanho relativamente igual. Isso torna o cálculo das tabelas heurísticas muitas centenas de vezes mais rápido, enquanto diminui a fase de pesquisa, geralmente apenas um pouco, mas pode ser significativo dependendo do estado inicial do cubo.
Índice variável
T
- a tabela heurística principal.S
- um estado de cubo resolvido. Cada peça individual é armazenada como uma máscara de bits, representada como um personagem. Um vetor de orientação resolvido é definido como o vetor zero.I
- as várias reviravoltas, na ordem em que são eliminadas do espaço de pesquisa.G
- os grupos para permutações de torção, armazenados como pares a serem trocados. Cada byte na cadeia compactada codifica para um par. Cada torção precisa de seis swaps: três para o ciclo de borda e três para o ciclo de canto. A cadeia compactada contém apenas ascii imprimíveis (caracteres 32 a 126).M
- uma função que executa um movimento, dada por G.N
- converte uma permutação de quatro objetos em um número, para fins de codificação.H
- calcula o valor heurístico para o estado do cubo fornecido, usado para procurar a profundidade do movimento de T.P
- faça uma pesquisa em uma única profundidade de uma única fase do algoritmo.s
- o estado de permutação do cubo de entrada.o
- o vetor de orientação do cubo de entrada.atuação
Usando o conjunto de dados de Tomas Rokicki , esse script teve uma média de 16,02 voltas por solução (máximo de 35), com um tempo médio de 472ms (CPU i5-3330 a 3,0 Ghz, PyPy 1.9.0). O tempo mínimo de resolução foi de 233ms, com um máximo de 2,97s, desvio padrão de 0,488. Usando as diretrizes de pontuação do concurso (o espaço em branco não é contado, as palavras-chave e os identificadores contam como um byte, com um comprimento de 870), a pontuação geral seria de 13.549.
Nos últimos 46 casos (os estados aleatórios), a média foi de 30,83 voltas por resolução, com um tempo médio de 721ms.
Notas sobre o algoritmo de Thistlethwaite
Para o benefício de qualquer pessoa que queira tentar uma implementação do Algoritmo de Thistlethwaite , aqui está uma breve explicação.
O algoritmo trabalha com um princípio muito simples de redução de espaço da solução. Ou seja, reduza o cubo para um estado em que um subconjunto de torções não seja necessário para resolvê-lo, reduza-o para um espaço de solução menor e, em seguida, resolva o restante usando apenas as poucas torções restantes.
Thistlethwaite sugeriu originalmente
<L,R,F,B,U,D>
→<L,R,F,B,U2,D2>
→<L,R,F2,B2,U2,D2>
→<L2,R2,F2,B2,U2,D2>
. No entanto, dado o formato de entrada, acho que é mais fácil reduzir para<L,R,F2,B2,U,D>
(sem quarto de voltaF
ouB
) e depois<L2,R2,F2,B2,U,D>
antes de finalmente chegar ao estado de meia volta. Em vez de explicar exatamente por que isso ocorre, acho que ficará evidente após a definição dos critérios para cada estado.<L,R,F,B,U,D>
⇒<L,R,F2,B2,U,D>
Para eliminar
F
eB
girar em quartos de volta, apenas as bordas devem ser orientadas corretamente. Gilles Roux tem uma explicação muito boa em seu site sobre o que é a orientação 'correta' e 'incorreta', então deixarei a explicação para ele. Mas, basicamente, (e é por isso que este formato de entrada é tão propício para fazerF
eB
eliminação), um cubinho borda esteja orientado corretamente se ele corresponde a seguinte regex:[^RL][^UD]
. Uma orientação correta é tipicamente significada com a0
e incorreta com1
. BasicamenteU
eD
adesivos podem não aparecer noR
ouL
caras, ou sobre os bordos das eventuaisU
ouD
borda cubinhos, ou eles podem não ser movido no lugar sem a necessidade de umaF
ouB
torção de um quarto.<L,R,F2,B2,U,D>
⇒<L2,R2,F2,B2,U,D>
Dois critérios aqui. Em primeiro lugar, todos os cantos devem ser correctamente orientado, e em segundo lugar, cada um dos para cubinhos camada do meio (
FR
,FL
,BR
,BL
) tem de ser em algum lugar na camada do meio. Uma orientação de canto é definida com muita simplicidade, dado o formato de entrada: a posição do primeiroU
ouD
. Por exemplo,URB
tem orientação0
(orientada corretamente),LDF
tem orientação1
eLFU
tem orientação2
.<L2,R2,F2,B2,U,D>
⇒<L2,R2,F2,B2,U2,D2>
Os critérios aqui são os seguintes: cada rosto pode conter apenas adesivos de seu rosto ou do rosto diretamente oposto a ele. Por exemplo, no
U
rosto pode haver apenasU
eD
adesivos, noR
rosto pode haver apenasR
eL
adesivos, noF
rosto pode haver apenasF
eB
adesivos, etc. A maneira mais fácil de garantir isso é para verificar se cada aresta está em sua 'fatia' e cada peça de canto em sua 'órbita'. Além disso, é preciso prestar atenção à paridade dos cantos da borda. Embora, se você verificar apenas a paridade de canto, a paridade de borda também será garantida e vice-versa.Como as torções afetam a orientação
U
eD
torções não afetam nem a orientação da aresta nem a orientação do canto. As peças podem ser trocadas diretamente sem atualizar o vetor de orientação.R
eL
torções não afetam a orientação da aresta, mas afetam a orientação do canto. Dependendo de como você define seu ciclo, a mudança na orientação do canto será+1, +2, +1, +2
ou+2, +1, +2, +1
, todo o módulo3
. Observe que torçõesR2
eL2
não afetam a orientação do canto, como+1+2
é o módulo zero3
, como é+2+1
.F
eB
afeta as orientações da aresta e as dos cantos. As orientações da aresta se tornam+1, +1, +1, +1
(mod 2), e as orientações dos cantos são as mesmas que paraR
eL
. Observe queF2
eB2
não afeta as orientações da borda nem as orientações dos cantos.fonte
<L,R,F,B,U,D>
-><L2,R2,F2,B2,U,D>
-><I>
. Requer um máximo de 29 torções para resolver um cubo (em vez de 52 para o de Thistlethwaite), mas também exige tabelas de pesquisa muito grandes, o que seria impraticável para gerar 'on the fly'.Ruby, 742 caracteres
O código rubi acima ainda não foi totalmente jogado. Ainda há possibilidades de melhorar ainda mais o código (mas já é suficiente como iniciante).
Ele resolve a camada do cubo por camada, mas não usa algoritmo específico, mas executa sequências aleatórias de movimentos até que o cubo seja resolvido.
Devido à natureza probabilística, às vezes, pode demorar mais de 5 segundos para resolver o cubo e, em casos raros, são necessários mais de 1000 movimentos.
A saída de exemplo (para a entrada 'RU LF UB DR DL BL UL FU BD RF BR FD LDF LBD FUL RFD UFR RDB UBL RBU') é 757 movimentos:
É possível reduzir a contagem de movimentos consideravelmente se os mesmos movimentos forem agrupados. Portanto, pode-se substituir a saída como
fonte
FU FR RU BR DB LD LU LB LF RD DF BU FRU BUR FDR DLB DFL LUB FUL DBR
U1 U1 U1
em uma únicaU3
?