El juego BattleBlock Theater ocasionalmente contiene un rompecabezas que es una versión generalizada de Lights Out . Tienes tres bloques adyacentes, cada uno de los cuales indica un nivel entre 1 y 4 inclusive con barras, por ejemplo:
|
||||
||
Si tocas un bloque, entonces ese bloque, así como cualquier bloque adyacente, incrementará su nivel (retrocediendo de 4 a 1). El rompecabezas se resuelve cuando los tres bloques muestran el mismo nivel (no importa qué nivel). Como el orden en el que toca los bloques no importa, denotamos una solución por la frecuencia con la que se toca cada bloque. La solución óptima para la entrada anterior sería 201
:
| --> || --> ||| |||
|||| | || |||
|| || || --> |||
El juego generaliza fácilmente cualquier número de bloques, aunque para algunos números, no todas las configuraciones son solucionables.
El reto
Dada una secuencia de niveles de bloque, regrese la frecuencia con la que se debe tocar cada bloque para resolver el rompecabezas. Por ejemplo, el ejemplo anterior se daría como 142
y podría dar 201
como resultado. Si no hay solución, devuelva un resultado consistente de su elección, que se distingue de todas las soluciones potenciales, por ejemplo, -1
o una cadena vacía.
Puede escribir una función o programa, recibir información a través de STDIN, argumento de línea de comando o argumento de función, en cualquier lista conveniente o formato de cadena, y generar de manera similar a través de un valor de retorno o imprimiendo en STDOUT.
Su código debe devolver resultados correctos para todos los casos de prueba dentro de un minuto en una máquina razonable. (Este no es un límite completamente estricto, por lo que si su solución demora un minuto y diez segundos, está bien, pero si demora 3 minutos, no lo es. Un buen algoritmo los resolverá fácilmente en segundos).
Este es el código de golf, por lo que gana la respuesta más corta (en bytes).
Ejemplos
Las soluciones no son únicas, por lo que puede obtener 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
Hasta donde yo sé, hay exactamente 4 soluciones para cada entrada donde el número de bloques es 0 mod 3, o 1 mod 3, y hay 0 o 16 soluciones donde es 2 mod 3.
fuente
Respuestas:
Python 2, 115 bytes
Esta es la versión de golf del programa que escribí mientras discutía el problema con Martin.
La entrada es una lista a través de STDIN. La salida es una lista que representa la última solución encontrada si hay una solución, o cero si no la hay. Por ejemplo:
Pyth,
3229 bytesEl puerto obligatorio. Gracias a @Jakube por el ahorro de 3 bytes.
El método de entrada es el mismo que el anterior, pruébelo en línea .
Explicación (¡larga y llena de lógica!)
Primero, dos observaciones básicas:
Observación 1: no importa en qué orden toque los bloques
Observación 2: si tocas un bloque 4 veces, es equivalente a tocarlo una vez
En otras palabras, si hay una solución, entonces hay una solución donde el número de toques está entre 0 y 3 inclusive.
Como el módulo 4 es muy bueno, hagámoslo también con los bloques. Para el resto de esta explicación, el nivel de bloque 0 es equivalente al nivel de bloque 4.
Ahora denotemos
a[k]
ser el nivel actual de bloquek
yx[k]
la cantidad de veces que tocamos el bloquek
en una solución. Deje tambiénn
ser el número total de bloques. Como ha notado @Jakube, una solución debe satisfacer:dónde
C
es el nivel final en el que terminan todos los bloques, entre 0 y 3 inclusive (recuerde que estamos tratando el nivel 4 como nivel 0) y todas las ecuaciones anteriores son realmente congruencias módulo 4.Ahora aquí está la parte divertida:
0 <= C <= 3
.Existen tres casos basados en el número de bloques del módulo 3. La explicación para cada uno de ellos es la misma: para cualquier número de bloques, existe un subconjunto de bloques que, si toca cada uno de ellos una vez, aumenta todos los niveles de bloque en exactamente 1.
Esto explica por qué hay 4 soluciones para
0 mod 3
y1 mod 3
, y generalmente 16 soluciones para2 mod 3
. Si ya tiene una solución, tocar los bloques como se muestra arriba le da otra solución que termina en un nivel de bloque más alto (envolviendo).Entonces, ¿qué significa esto? ¡Podemos elegir cualquier nivel de bloque final
C
que queramos! Vamos a elegirC = 0
, porque esto ahorra en bytes.Ahora nuestras ecuaciones se convierten en:
Y reorganizar:
Entonces, lo que podemos ver es que, si lo hemos hecho
x[0]
, podemos usar todas las ecuaciones, excepto la última, para descubrir las demás.x[k]
. La última ecuación es una condición adicional que debemos verificar.Esto nos da un algoritmo:
x[0]
x[k]
Eso da la solución anterior.
Entonces, ¿por qué a veces no tenemos solución
2 mod 3
? Echemos un vistazo a estos dos patrones nuevamente:Ahora considere las ecuaciones en esas posiciones, es decir, para la primera:
Añádelos:
Para el segundo:
Agréguelos nuevamente:
Entonces, si
(a[1] + a[4] + a[7] + a[10])
y(a[0] + a[3] + a[6] + a[9])
no son iguales, entonces no tenemos solución. Pero si son iguales, obtenemos 16 soluciones. Esto fue para eln = 11
caso, pero por supuesto esto se generaliza a cualquier número que sea2 mod 3
: tome la suma de cada tercer elemento a partir del segundo y compárela con la suma de cada tercer elemento a partir del primero.Ahora, finalmente, ¿es posible descubrir qué
x[0]
tiene que ser en lugar de probar todas las posibilidades? Después de todo, dado que restringimos nuestro nivel objetivoC
a 0, solo hay unox[0]
que da una solución en el caso0 mod 3
o1 mod 3
(as4 solutions / 4 final levels = 1 solution for a specific final level
).¡La respuesta es sí! Podemos hacer esto para
0 mod 3
:Lo que se traduce en:
Restando da:
Del mismo modo
1 mod 3
, podemos hacer este patrón:Lo que da:
Estos, por supuesto, se generalizan al extender los índices en incrementos de 3.
Porque
2 mod 3
, dado que tenemos dos subconjuntos que cubren cada bloque, en realidad podemos elegir cualquierax[0]
. De hecho, esto es cierto parax[0], x[1], x[3], x[4], x[6], x[7], ...
(básicamente cualquier índice no congruente con2 mod 3
, ya que no están cubiertos por ninguno de los subconjuntos).Así que tenemos una forma de elegir un en
x[0]
lugar de probar todas las posibilidades ...... pero la mala noticia es que esto no se guarda en bytes (124 bytes):
fuente
J
lugar deH
y 2 caracteres, si hace estallar el último elemento enPJ
lugar de cortar.<J_1
.V4J]NVQaJ%_+s>J_2@QN4)I!eJPJB
Pyth,
727673663938 caracteresedit 4: Realizado, que los cálculos
Q[N]-Q[N+1]+solution[-3]
yQ[-2]-Q[-1]+solution[-3]
son ident. Por lo tanto, calculo en exceso la solución por 1, y filtro las soluciones, donde la última entrada es 0. Luego hago estallar la última entrada. Afortunadamente, los casos especiales no necesitan un tratamiento adicional con este enfoque. -27 caractereseditar 3: Aplicar algunos trucos de golf de FryAmTheEggman: -7 personaje
editar 2: Usar filtro, reducir y mapear: -3 caracteres
editar 1: en mi primera versión no imprimí nada, si no había solución. No creo que esté permitido, por lo tanto, +4 personaje.
Espera una lista de enteros como entrada
[1,4,2]
y genera una solución válida[2,0,1]
si hay una, de lo contrario, una lista vacía[]
.Explicación:
Deje
Q
ser la lista de 5 niveles yY
la lista de la solución. Deben mantenerse las siguientes ecuaciones:Por lo tanto, si usamos cualquiera
Y0
yY1
, podemos calcularY2
,Y3
yY4
de la siguiente manera.Que todos los niveles, excepto el último, son iguales (porque no usamos la ecuación
= Q4 + Y3 + Y4
. Para verificar, si este último también es igual a los otros niveles, simplemente podemos verificar si(Q3 - Q4 + Y2) mod 4 == 0
. Observe que la parte izquierda sería el valorY5
Si calculo la sexta parte de la solución, simplemente puedo verificar si es cero.En mi enfoque, simplemente itero sobre todos los inicios posibles (
[0,0]
, a[3,3]
) y calculo la longitud (entrada) -1 entradas más y filtro todas las soluciones que terminan con un cero.es básicamente lo siguiente:
luego filtro estas posibles soluciones por otras válidas:
a esta lista de soluciones agrego una lista vacía, para que tenga al menos un elemento
y tome la primera solución
h
, haga estallar el último elementop
e imprímaloTenga en cuenta que esto también funciona si solo hay un bloque. En mi enfoque obtengo la posición inicial [0,0] y no la extiende. Como la última entrada es 0, imprime la solución [0].
El segundo caso especial (2 bloques) no es tan especial después de todo. No estoy seguro, por qué complicaba demasiado las cosas antes.
fuente
?**lQ]0qhQeQ<lQ3h+f!%-+ePQ@T_3eQ4mu+G]%+&H@G_3-@QH@QhH4UttQd^UT2]Y
es de 66 bytes. El rendimiento se vio afectado un poco, pero todavía ejecuta el caso de prueba más grande en <1s para mí. Hazme un ping si quieres explicaciones de algunos de los campos de golf; no hay suficiente espacio en este comentario;) Espero que estés disfrutando usando Pyth: D+<list><int>
tiene el mismo efecto que+<list>]<int>
, por lo que puede eliminar el primero]
. Además, muy buena solución.~
? No parecía ser cuando lo intenté~
cona
-~<list>]<int>
es equivalente aa<list><int>
.~
es+=
, mientrasa
es.append()
Ruby,
320313 caracteresDefinitivamente se puede jugar más al golf. No genera nada para rompecabezas sin solución.
Versión sin golf:
Bien, este fue divertido. Aquí está el algoritmo básico, con la
{n}
representación de n "touch" es en el número arriba deln
, como se demuestra en uno de los ejemplos:Me quedé perplejo por un momento aquí. ¿Cómo puedo convertir el
111...1110
en una serie de mismos números? Así que comparé mi solución y la solución correcta (nota: todos los recuentos "táctiles" son uno mayor de lo que deberían ser porque la entrada está indexada en 1, mientras que la salida está indexada en 0):Noté que cada número estaba uno lejos del correcto
mod 4
, así que los marqué con+
s,-
sy=
s:Eso funcionó por un tiempo, ¡hasta que me di cuenta de que a veces el resultado final era
111...11112
o11...1113
también! Afortunadamente, la aplicación repetida de la fórmula mágica que no tiene sentido pero que funciona también los solucionó.Entonces, ahí lo tienes. Un programa que comienza teniendo sentido, pero que se degrada y se vuelve más y más feo a medida que avanza. Muy típico para una solución de código de golf, creo. :)
fuente
exit if (r+=1)>5
a(r+=1)>5&&exit
. Además, la(code)while cond
sintaxis es más corta quewhile cond \n code \n end
.Python 2,
294,289,285,281273 bytesMANIFESTACIÓN
Estoy seguro de que esto se puede jugar más golf ..
Aquí están los resultados de los casos de prueba:
El algoritmo primero se asegura de que los valores de todos los bloques, excepto el último bloque, sean los mismos (al iterar y agregar a los "recuentos táctiles" de todos los bloques excepto los primeros 2). Luego, si el número de bloques lo permite (
(num_of_blocks - 1) % 3 != 1
), regresa y se asegura de que los valores del resto de los bloques coincidan con el último bloque. Imprimex
si no hay solución.fuente