Se você não sabe o que é a Torre de Hanói , explicarei brevemente: Existem três barras e alguns discos, cada um com um tamanho diferente. No começo, todos os discos estão na primeira torre, em ordem ordenada: o maior está na parte inferior, o menor no topo. O objetivo é levar todos os discos para a terceira barra. Parece fácil? Aqui está o problema: você não pode colocar um disco em cima de um disco menor que o outro disco; você só pode segurar um disco em sua mão de cada vez para movê-lo para outra haste e só pode colocar o disco em hastes, e não em cima da mesa, seu bastardo sorrateiro.
solução de exemplo ascii:
A B C
| | |
_|_ | |
__|__ | |
A B C
| | |
| | |
__|__ _|_ |
A B C
| | |
| | |
| _|_ __|__
A B C
| | |
| | _|_
| | __|__
Desafio
Existem três hastes chamadas A, B e C. (Você também pode chamá-las respectivamente 1,2 e 3, se isso ajudar). No início, todos os n discos estão na haste A (1).
Seu desafio é verificar uma solução para a torre de Hanói. Você precisará garantir que:
- No final, todos os n discos estão na haste C (3).
- Para qualquer disco em um dado estado, não há disco menor abaixo dele.
- Não há erros óbvios, como tentar tirar discos de uma barra vazia ou mover discos para barras inexistentes.
(a solução não precisa ser ótima.)
Entrada
Seu programa receberá duas entradas:
- O número de discos n (um número inteiro)
Os movimentos realizados, que consistem em um conjunto de tuplas de: (torre para tirar o disco atualmente mais alto), (torre para levar esse disco) onde cada tupla se refere a um movimento. Você pode escolher como eles são representados. Por exemplo, algo como as seguintes maneiras de representar a solução para n = 2, que eu desenhei nas ascii acima. (Usarei o primeiro nos casos de teste, porque é fácil para os olhos):
"A-> B; A-> C; B-> C"
[("A", "B"), ("A", "C"), ("B", "C")]
[(1,2), (1,3), (2,3)]
"ABACBC"
[1,2,1,3,2,3]
Saída
Na verdade, se as condições que podem ser encontradas em "desafio" se mantiverem.
Falsy, se não o fizerem.
Casos de teste:
Verdade:
n=1, "A->C"
n=1, "A->B ; B->C"
n=2, "A->B ; A->C ; B->C"
n=2, "A->C ; C->B ; A->C ; B->C"
n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"
Falso:
3º sugerido por @MartinEnder, 7º por @Joffan
n=1, "A->B"
n=1, "C->A"
n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=2, "A->B ; A->C ; C->B"
n=2, "A->C ; A->B ; C->B ; B->A"
n=2, "A->C ; A->C"
n=3, "A->B ; A->D; A->C ; D->C ; A->C"
n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"
n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"
Este é o código-golfe , a solução mais curta vence. Aplicam-se regras e brechas padrão. Sem pilhas incluídas.
A=1
,B=2
,C=3
, etc.)?A->A
?moving discs to nonexistant rods.
então é claro que sim, é umD
Respostas:
Retina ,
8480 Bytes-5 bytes graças a Martin Ender
Experimente online! (mais 5 bytes para testes linha por linha)
O código simula um jogo completo.
ACABCBACBABCAC~~~
.~~~
significa três discos.ACABCBACBABCAC ~~~ ~~ ~ABC
.No começo, a barra A possui todos os 3 discos e as barras B e C estão vazias.
Em fora exemplo, após a primeira etapa, o texto será algo como:
~CABCBACBABCAC ~~~ ~~ABC
.ABCBACBABCAC ~~~ ~~AB ~C
.fonte
Retina ,
167165157150123 bytesIsso parece totalmente um desafio que deve ser resolvido com um único regex ... (apesar do cabeçalho dizer "Retina", este é apenas um regex .NET baunilha, que corresponde a entradas válidas).
O formato de entrada é a lista de instruções do formulário
AB
, seguida porn
unária usando o dígito1
. Não há separadores. A saída é1
válida e0
inválida.Experimente online! (Os dois primeiros caracteres habilitam um conjunto de testes separado por avanço de linha.)
Solução alternativa, mesma contagem de bytes:
Isso pode, eventualmente, ser encurtado usando
1
,11
e111
em vez deA
,B
eC
, mas eu vou ter que olhar para isso mais tarde. Também pode ser mais curto dividir o programa em várias etapas, mas qual é o desafio nisso? ;)Explicação
Esta solução faz uso pesado dos grupos de balanceamento do .NET. Para obter uma explicação completa, veja minha postagem no Stack Overflow , mas o essencial é que capturar grupos no .NET é pilhas, onde cada nova captura envia outra substring e também é possível sair dessa pilha novamente. Isso permite contar várias quantidades em uma sequência. Nesse caso, permite implementar as três hastes diretamente como três grupos de captura diferentes, onde cada disco é representado por uma captura.
Para mover os discos entre as barras, usamos uma peculiaridade estranha da
(?<A-B>...)
sintaxe. Normalmente, isso exibe uma captura da pilhaB
e empurra para a pilhaA
a sequência entre a captura exibida e o início desse grupo. Assim, em(?<A>a).(?<B-A>c)
comparação comabc
deixariaA
vazio eB
comb
(em oposição ac
). No entanto, devido às estruturas de comprimento variável do .NET, é possível capturar(?<A>...)
e(?<B-A>...)
sobrepor. Por qualquer motivo, se for esse o caso, a interseção dos dois grupos é pressionadaB
. Eu detalhei esse comportamento na "seção avançada" sobre grupos de equilíbrio nesta resposta .Para a regex. Hastes
A
,B
eC
correspondem a grupos3
,4
e5
pela expressão regular. Vamos começar inicializando o rodA
:Então, por exemplo, se a entrada terminar com
111
, o grupo 3 / rodA
agora manterá a lista de capturas[111, 11, 1]
(a parte superior está à direita).O próximo bit do código tem a seguinte estrutura:
Cada iteração desse loop processa uma instrução. A primeira alternação puxa um disco da haste especificada (para um grupo temporário), a segunda alternação coloca o disco na outra haste especificada. Veremos em um momento como isso funciona e como garantimos que a mudança é válida.
Primeiro, retirando um disco da haste de origem:
Isso usa o comportamento estranho de interseção de grupo que descrevi acima. Note-se que grupo
3
,4
e5
terá sempre substrings de1
s no final da string cujo corresponde ao tamanho do disco comprimento. Agora usamos(?<1-N>.+)
para retirar o disco superior da pilhaN
e empurrar a interseção dessa substring com a correspondência.+
para a pilha1
. Como.+
sempre abrange necessariamente toda a captura capturadaN
, sabemos que isso simplesmente move a captura.Em seguida, colocamos esse disco da pilha
1
na pilha correspondente à segunda haste:Observe que não precisamos limpar a pilha
1
, podemos apenas deixar o disco lá, pois colocaremos uma nova por cima antes de usar a pilha novamente. Isso significa que podemos evitar a(?<A-B>...)
sintaxe e simplesmente copiar a string(\1)
. Para garantir que a mudança seja válida, usamos o lookahead negativo(?!\N)
. Isso garante que, a partir da posição em que queremos corresponder ao disco atual, é impossível corresponder ao disco que já está na pilhaN
. Isso só pode acontecer se a)\N
nunca corresponder porque a pilha está completamente vazia ou b)the disc on top of stack
Nis larger than the one we're trying to match with
\ 1`.Finalmente, tudo o que resta é garantir que a) correspondamos a todas as instruções eb) hastes
A
eB
estejam vazias, para que todos os discos tenham sido movidosC
.Nós simplesmente verificar que nem
\3
nem\4
pode igualar (que é apenas o caso se ambos estão vazios, porque qualquer disco real seria combinar) e que pode, então, corresponder a um1
modo que não omiti quaisquer instruções.fonte
"Apenas" Java
311 272 263 261 260 259256 bytesSalvou
39inúmeros bytes devido ao @Frozn perceber um recurso de depuração mais antigo, além de alguns truques inteligentes de golfe.Versão Golfed
destituído de explicações e pilhas bem impressas a cada passo
A versão ungolfed possui um recurso no qual será impressa a aparência das pilhas a cada etapa ...
fonte
System.out.println(Arrays.toString(s))
faz?&&
por&
.Python 2,
186167158135127115110102 bytesRecebe entrada em STDIN no seguinte formato:
Ou seja, uma tupla em Python do número de discos e uma lista em Python de tuplas
(from_rod,to_rod)
. Como no Python, os parênteses ao redor são opcionais. As hastes são indexadas a zero.Por exemplo, este caso de teste:
seria dado como:
Se a solução for válida, não produzirá nada e sairá com um código de saída 0. Se for inválido, lança uma exceção e sai com um código de saída 1. Lança um
IndexError
se estiver se movendo para uma haste inexistente ou tentando retirar um disco de um disco. haste que não possui discos, aZeroDivisionError
se um disco for colocado em cima de um disco menor ou aNameError
se ainda houver discos na primeira ou na segunda haste no final.Guardou 13 bytes graças a @KarlKastor!
Economizou 8 bytes graças a @xnor!
fonte
Python 2.7,
173158138130 130127123 bytes:Recebe a entrada através do stdin no formato em
(<Number of Discs>,<Moves>)
que<Moves>
é fornecida como uma matriz contendo tuplas correspondentes a cada movimento, cada uma contendo um par de números inteiros separados por vírgula. Por exemplo, o caso de teste:dado no post seria dado como:
ao meu programa. Produz um
IndexError
se a 3ª condição não for atendida, aNameError
se a 2ª condição não for atendida eFalse
se a 1ª condição não for atendida. Caso contrário, as saídasTrue
.fonte
Y
nunca é definido em seu código (acho que deve ser J) eU[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]
é mais curto por 3 caracteres que ostmt1 if cond else stmt2
Y
variável assim para aumentarNameError
sempre que a segunda condição não for atendida. Se eu fosse mudarY
paraJ
, então oNameError
não seria aumentado. Por esse motivo, eu também não posso fazerU[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]
isso, porque isso aumentariaNameError
o tempo todo , não apenas quando a 2ª condição não for atendida.VBA,
234217213196 bytesO formato de entrada para movimentos é uma sequência com um número par de dígitos (012). A chamada está na planilha, = H ([número de discos], [mover seqüência])
A matriz A mantém a posição da haste dos vários discos. Um movimento é simplesmente atualizar a primeira ocorrência do número da haste "De" para o número da haste "Para". Se você encontrar um disco de haste "Para" primeiro ou nenhum disco de haste "De", é um movimento inválido. O "valor total da haste" de A é mantido em L, que precisa terminar em 2N. Os erros são acumulados como uma contagem negativa em E.
Em comum com outras soluções, "mover" um disco de uma torre para a mesma torre não é proibido. Eu poderia proibi-lo por mais 6 bytes.
Resultados
Resultado da função na primeira coluna (o último caso de n = 3 é minha adição usando uma haste extra).
fonte
php, 141 bytes
O script da linha de comando recebe a entrada como altura e, em seguida, uma série de índices de matriz (0 indexados), por exemplo, 1 0 2 ou 2 0 1 0 2 1 2 para os casos de teste mais curtos de 1 ou 2 alturas.
Ecos 1 em casos verdadeiros e nada em casos falsos.
Dá 2 avisos e 1 aviso, portanto, precisa ser executado em um ambiente que os silencie.
fonte
JavaScript (ES6), 108
Formato de entrada: função com 2 argumentos
Saída: retorno 1 se ok, 0 se inválido, exceção se haste não existente
Menos jogado e explicado
Nota do teste : a primeira linha da função Teste é necessária para converter o formato de entrada fornecido na pergunta para a entrada esperada pela minha função
fonte