O jogo BattleBlock Theatre ocasionalmente contém um quebra-cabeça que é uma versão generalizada de Lights Out . Você tem três blocos adjacentes, cada um dos quais indica um nível entre 1 e 4, inclusive com barras, por exemplo:
|
||||
||
Se você tocar em um bloco, esse bloco, assim como qualquer bloco adjacente, aumentará seu nível (retornando de 4 para 1). O quebra-cabeça é resolvido quando os três blocos mostram o mesmo nível (não importa em que nível). Como a ordem em que você toca os blocos não importa, denotamos uma solução pela frequência com que cada bloco é tocado. A solução ideal para a entrada acima seria 201
:
| --> || --> ||| |||
|||| | || |||
|| || || --> |||
O jogo generaliza muito facilmente qualquer número de blocos, embora para alguns números, nem todas as configurações sejam solucionáveis.
O desafio
Dada uma sequência de níveis de bloco, retorne com que frequência cada bloco precisa ser tocado para resolver o quebra-cabeça. Por exemplo, o exemplo acima seria dado como 142
e poderia render 201
como resultado. Se não houver solução, retorne uma saída consistente de sua escolha, que seja distinguível de todas as soluções em potencial, por exemplo, -1
ou uma string vazia.
Você pode escrever uma função ou programa, receber entradas via STDIN, argumento de linha de comando ou argumento de função, em qualquer formato conveniente de lista ou string, e gerar saída similarmente através de um valor de retorno ou imprimindo em STDOUT.
Seu código deve retornar resultados corretos para todos os casos de teste dentro de um minuto em uma máquina razoável. (Esse não é um limite completamente estrito; portanto, se a sua solução demorar um minuto e dez segundos, tudo bem, mas se demorar 3 minutos, não será. Um bom algoritmo os resolverá facilmente em segundos.)
Isso é código de golfe, então a resposta mais curta (em bytes) vence.
Exemplos
As soluções não são exclusivas, portanto, você pode obter resultados diferentes.
Input Output
1 0
11 00
12 No solution
142 201
434 101
222 000
4113 0230
32444 No solution
23432 10301
421232 212301
3442223221221422412334 0330130000130202221111
22231244334432131322442 No solution
111111111111111111111222 000000000000000000000030
111111111111111111111234 100100100100100100100133
412224131444114441432434 113013201011001101012133
Até onde eu sei, existem exatamente 4 soluções para cada entrada em que o número de blocos é 0 mod 3 ou 1 mod 3 e existem 0 ou 16 soluções em que é 2 mod 3.
fonte
Respostas:
Python 2, 115 bytes
Esta é a versão básica do programa que escrevi enquanto discutia o problema com Martin.
Entrada é uma lista via STDIN. Saída é uma lista que representa a última solução encontrada, se houver uma solução, ou zero, se não houver. Por exemplo:
Pitão,
3229 bytesO porto obrigatório. Obrigado a @Jakube pela economia de 3 bytes.
O método de entrada é o mesmo que o anterior, tente online .
Explicação (longa e cheia de lógica!)
Primeiro, duas observações básicas:
Observação 1: Não importa em qual ordem você toca nos blocos
Observação 2: se você tocar em um bloco 4 vezes, é equivalente a tocá-lo uma vez
Em outras palavras, se houver uma solução, existe uma solução em que o número de toques está entre 0 e 3, inclusive.
Como o módulo 4 é tão bom, vamos fazer isso com os blocos também. Para o restante desta explicação, o nível de bloco 0 é equivalente ao nível de bloco 4.
Agora, vamos denotar
a[k]
o nível atual do blocok
ex[k]
o número de vezes que tocamosk
no bloco em uma solução. Tambémn
seja o número total de blocos. Como o @Jakube observou, uma solução deve satisfazer:onde
C
é o nível final em que todos os blocos terminam, entre 0 e 3, inclusive (lembre-se de que estamos tratando o nível 4 como nível 0) e todas as equações acima são realmente congruências no módulo 4.Agora, aqui está a parte divertida:
0 <= C <= 3
.Existem três casos baseados no número de blocos do módulo 3. A explicação para cada um deles é a mesma - para qualquer número de blocos, existe um subconjunto de blocos que, se você tocar em um deles uma vez, aumenta todos os níveis de bloco em exatamente 1.
Isso explica por que existem 4 soluções para
0 mod 3
e1 mod 3
, e geralmente 16 soluções para2 mod 3
. Se você já possui uma solução, tocar nos blocos conforme descrito acima fornece outra solução que acaba em um nível mais alto de bloco (quebra automática).Então o que isso quer dizer? Podemos escolher qualquer nível de bloco final
C
que quisermos! Vamos escolherC = 0
, porque isso economiza em bytes.Agora nossas equações se tornam:
E reorganize:
Então, o que podemos ver é, se tivermos
x[0]
, podemos usar todas as equações, exceto a última, para descobrir todas as outrasx[k]
. A última equação é uma condição adicional que devemos verificar.Isso nos dá um algoritmo:
x[0]
x[k]
Isso dá a solução acima.
Então, por que às vezes não temos solução
2 mod 3
? Vamos dar uma olhada nesses dois padrões novamente:Agora considere as equações nessas posições, ou seja, para a primeira:
Adicione-os:
Para o segundo:
Adicione-os novamente:
Portanto, se
(a[1] + a[4] + a[7] + a[10])
e(a[0] + a[3] + a[6] + a[9])
não são iguais, não temos solução. Mas se forem iguais, obteremos 16 soluções. Foi on = 11
caso, mas é claro que isso se generaliza para qualquer número que seja2 mod 3
- pegue a soma de cada terceiro elemento começando no segundo e compare com a soma de cada terceiro elemento começando no primeiro.Agora, finalmente, é possível descobrir o que
x[0]
deve ser em vez de tentar todas as possibilidades? Afinal, como restringimos nosso nível de destinoC
a 0, existe apenas umx[0]
que fornece uma solução no caso0 mod 3
ou1 mod 3
(as4 solutions / 4 final levels = 1 solution for a specific final level
).A resposta é sim! Podemos fazer isso por
0 mod 3
:Que se traduz em:
Subtrair fornece:
Da mesma forma
1 mod 3
, podemos fazer esse padrão:Que dá:
É claro que eles generalizam estendendo os índices em incrementos de 3.
Pois
2 mod 3
, como temos dois subconjuntos que cobrem todos os blocos, podemos escolher qualquer umx[0]
. De fato, isso é verdade parax[0], x[1], x[3], x[4], x[6], x[7], ...
(basicamente qualquer índice não congruente2 mod 3
, pois eles não são cobertos por nenhum subconjunto).Portanto, temos uma maneira de escolher um em
x[0]
vez de tentar todas as possibilidades ...... mas a má notícia é que isso não economiza em bytes (124 bytes):
fonte
J
vez deH
e 2 caracteres, se você exibir o último elemento emPJ
vez de fatiar.<J_1
.V4J]NVQaJ%_+s>J_2@QN4)I!eJPJB
Pyth,
727673663938 caractereeditar 4: Realizado, que os cálculos
Q[N]-Q[N+1]+solution[-3]
eQ[-2]-Q[-1]+solution[-3]
são ident. Portanto, eu supercalculo a solução em 1 e filtro as soluções, onde a última entrada é 0. Então eu pop a última entrada. Felizmente, os casos especiais não precisam de um tratamento extra com essa abordagem. -27 caracteresedit 3: Aplicando alguns truques de golfe de FryAmTheEggman: -7 character
editar 2: Usando filtro, reduza e mapeie: -3 caracteres
edit 1: Na minha primeira versão, não imprimi nada, se não houvesse solução. Eu não acho que isso é permitido, portanto, +4 caracteres.
Espera uma lista de números inteiros como entrada
[1,4,2]
e gera uma solução válida[2,0,1]
se houver uma, caso contrário, uma lista vazia[]
.Explicação:
Let
Q
Ser a lista de 5 níveis eY
a lista da solução. As seguintes equações devem ser válidas:Portanto, se usarmos any
Y0
eY1
, podemos calcularY2
,Y3
eY4
da seguinte maneira.Todos os níveis, exceto o último, são iguais (porque não usamos a equação
= Q4 + Y3 + Y4
. Para verificar, se esse último também é igual aos outros níveis, podemos simplesmente verificar se(Q3 - Q4 + Y2) mod 4 == 0
. Observe que a parte esquerda seria o valorY5
Se eu calcular a sexta parte da solução, posso simplesmente verificar se é zero.Na minha abordagem, simplesmente itero sobre todas as possíveis partidas (
[0,0]
, para[3,3]
) e calculo o comprimento (entrada) -1 mais entradas e filtre todas as soluções que terminam com zero.é basicamente o seguinte:
então eu filtrei essas soluções possíveis para soluções válidas:
a esta lista de soluções, anexo uma lista vazia, para que ela tenha pelo menos um item
e pegue a primeira solução
h
, coloque o último elementop
e imprima-oObserve que isso também funciona, se houver apenas um bloco. Na minha abordagem, recebo a posição inicial [0,0] e não a estendo. Como a última entrada é 0, ela imprime a solução [0].
O segundo caso especial (2 blocos) não é tão especial, afinal. Não sei por que complicou demais as coisas antes.
fonte
?**lQ]0qhQeQ<lQ3h+f!%-+ePQ@T_3eQ4mu+G]%+&H@G_3-@QH@QhH4UttQd^UT2]Y
é 66 bytes. O desempenho foi atingido um pouco, mas ainda executa o maior caso de teste em <1s para mim. Ligue-me se quiser explicações sobre alguns dos campos; não há espaço suficiente neste comentário;) Espero que você esteja gostando de usar o Pyth: D+<list><int>
tem o mesmo efeito que+<list>]<int>
, para que você possa remover o primeiro]
. Além disso, solução muito agradável.~
? Não parecia ter sido quando eu tentei #~
pora
-~<list>]<int>
é equivalente aa<list><int>
.~
é+=
, ao mesmo tempoa
é.append()
Ruby,
320313 caracteresDefinitivamente pode ser jogado mais. Não produz nada para quebra-cabeças insolúveis.
Versão não destruída:
Ok, este foi divertido. Aqui está o algoritmo básico, com a
{n}
representação de n "touch" es no número acima den
, como demonstrado em um dos exemplos:Fiquei perplexo um pouco aqui. Como transformar isso
111...1110
em uma série dos mesmos números? Então, comparei minha solução e a solução correta (nota: o "toque" conta todos com um valor maior do que deveria porque a entrada é indexada 1, enquanto a saída é indexada 0:Notei que cada número foi um longe o correto
mod 4
, por isso marcou-los com+
s,-
s e=
s:Isso funcionou por um tempo, até que percebi que às vezes o resultado final foi
111...11112
ou11...1113
bem! Felizmente, aplicar repetidamente a fórmula mágica que não faz sentido, mas funciona também resolveu isso.Então, aí está. Um programa que começa a fazer sentido, mas que se degrada cada vez mais como feio. Muito típico para uma solução de código de golfe, eu acho. :)
fonte
exit if (r+=1)>5
para(r+=1)>5&&exit
. Além disso, a(code)while cond
sintaxe é menor quewhile cond \n code \n end
.Python 2,
294,289,285,281273 bytesDEMO
Tenho certeza de que isso pode ser jogado ainda mais ..
Aqui estão os resultados dos casos de teste:
O algoritmo primeiro garante que os valores de todos os blocos, exceto o último bloco, sejam os mesmos (iterando e adicionando às "contagens de toque" de todos os blocos, exceto os 2 primeiros). Então, se o número de blocos permitir (
(num_of_blocks - 1) % 3 != 1
), volte e verifique se os valores do restante dos blocos correspondem ao último bloco. Imprimex
se não houver solução.fonte