Tic-Tac-Latin!
Esta es una historia real, por lo que los nombres han sido alterados.
Mi profesor de latín, el señor Latin, creó su propia variante patentada (no es broma) de tic tac toe. Llamémoslo tic-tac-latin. El juego es simple, es esencialmente un tic tac toe jugado en una cuadrícula cuatro por cuatro.
Declaración de regla formal
Una línea es una fila, columna o diagonal. Hay dos símbolos, 'X' y 'O', pero uno o ambos pueden ser sustituidos por un símbolo diferente.
Obtienes un punto cuando tienes tres de tu símbolo y uno del otro personaje.
Estos arreglos puntúan:
--- O -O-- XXXO XOOX O -XX - O - - X - --- O
Estos no puntúan:
---- XXXX ---- OOOO ---- XXX- ---- OOO-
El juego se gana cuando un jugador tiene más puntos que otro. El juego es un empate solo si el tablero se llena.
Desafío
Resuelve este juego. Su trabajo es proporcionar una forma de garantizar una victoria o un empate, el que sea el resultado óptimo.
Su solución puede elegir comenzar primero o segundo (y, por lo tanto, puede elegir su símbolo). No es obligatorio implementar un juego interactivo donde el usuario ingresa movimientos y la pantalla correspondiente cambia. También puede ser una función o programa que toma la entrada como un estado del juego y genera un nuevo tablero o una descripción de su movimiento . Cualquiera de las opciones debe ejecutarse dentro de aproximadamente diez segundos por movimiento realizado.
Jugar a tu jugador contra cualquier secuencia de movimientos debe dar el resultado óptimo. Esto significa que puede asumir que la posición de entrada es una que se puede alcanzar desde el juego con su reproductor. Los envíos deben ser deterministas, y no necesariamente tienen que proporcionar una prueba de optimización, pero si se agrietan (al ser golpeados) sus envíos se considerarán inválidos (puede dejarlos, pero agregarlos (agrietados) en el título).
Esta es una tarea no trivial, por lo que cualquier presentación válida es impresionante y merece un tick aceptado, pero haré del código golf el criterio principal para ganar.
El ganador se elige bajando por esta lista hasta que se elija un ganador.
- Implementación resuelta más corta que siempre gana
- Implementación más corta
Respuestas:
Perl, 147 bytes (no compite, toma más de 10 segundos por movimiento)
Incluye +4 para
-0p
El programa juega
X
. Jugará un juego perfecto.Ingrese la placa en STDIN, por ejemplo:
La salida será la misma placa con todos
X
reemplazados porO
y viceversa. Los espacios vacíos se llenarán con un número que indica el resultado si X jugaría allí, lo que1
significa que el resultado será una victoria,2
un empate y3
una derrota. Un juego terminado solo devuelve la misma posición con los colores invertidos.En este ejemplo, la salida sería:
Entonces, la posición es una victoria
X
si juega en los 3 lugares a lo largo de la parte superior e izquierda. Todos los demás movimientos pierden.Este resultado confuso es realmente conveniente si quieres saber cómo continúa el juego después de un movimiento. Como el programa siempre se reproduce,
X
debes intercambiarX
yO
ver los movimientosO
. Aquí, por ejemplo, está bastante claro queX
gana jugando en la parte superior izquierda, pero ¿qué pasa siX
juega en la tercera posición en la parte superior? Simplemente copie el resultado, coloque unO
lugar en el movimiento que seleccione y reemplace todos los demás números de-
nuevo, así que aquí:Resultando en:
Obviamente, cada movimiento
O
debe perder, entonces, ¿cómo pierde si juega en la esquina superior izquierda? Nuevamente, haga esto colocandoO
en la esquina superior izquierda y reemplazando los dígitos por-
:Dando:
Entonces X solo tiene un camino por recorrer para su victoria:
Dando
La situación para
O
sigue siendo desesperada. Es fácil ver ahora que cada movimiento permiteX
ganar de inmediato. Al menos intentemos hacer 3 O seguidas:Dando:
X
juega el único movimiento ganador (observe que esto se realizaXXXO
en la tercera columna:Aquí la salida es:
porque el juego ya estaba terminado. Puedes ver la victoria en la tercera columna.
El programa actual
tictaclatin.pl
:Aplicado al tablero vacío, esto evalúa 9506699 posiciones que toman 30Gb y 41 minutos en mi computadora. El resultado es:
Por lo tanto, cada movimiento inicial se basa. Entonces el juego es un empate.
El uso extremo de la memoria es causado principalmente por el uso recurrente
do$0
. El uso de esta versión de 154 bytes que utiliza una función simple necesita 3Gb y 11 minutos:que es más soportable (pero aún demasiado, algo debe estar perdiendo memoria).
La combinación de varias aceleraciones conduce a esta versión de 160 bytes (5028168 posiciones, 4 minutos y 800M para el tablero vacío):
El último se usa
0
para ganar (no confundir conO
),1
para empatar y2
para perder. La salida de este también es más confusa. Completa el movimiento ganador para X en caso de una victoria sin cambio de color, pero si el juego de entrada ya fue ganado, todavía cambia el color y no completa ningún movimiento.Todas las versiones, por supuesto, se vuelven más rápidas y usan menos memoria a medida que la placa se llena. Las versiones más rápidas deberían generar un movimiento en menos de 10 segundos tan pronto como se hayan realizado 2 o 3 movimientos.
En principio, esta versión de 146 bytes también debería funcionar:
pero en mi máquina activa un error perl y vuelca el núcleo.
En principio, todas las versiones seguirán funcionando si
$$_||=
se elimina el almacenamiento en caché de la posición de 6 bytes, pero eso consume tanto tiempo y memoria que solo funciona para tableros casi llenos. Pero, en teoría, al menos tengo una solución de 140 bytes.Si coloca
$\=
(costo: 3 bytes) justo antes de$@<=>0
cada placa de salida, le seguirá el estado de toda la placa:1
paraX
victorias,0
para empates y-1
para pérdidas.Aquí hay un controlador interactivo basado en la versión más rápida mencionada anteriormente. El controlador no tiene lógica para cuando finaliza el juego, por lo que debes detenerte. Sin embargo, el código de golf lo sabe. Si el movimiento sugerido regresa sin ser
-
reemplazado por nada, el juego ha terminado.fuente
$move
se declara en la línea 11. No tengo idea si hay una heurística humana. Este programa solo hace minimax en el árbol del juego, no tiene ningún conocimiento estratégico.JavaScript (ES6) 392 bytes
Uso
El "bot" jugará segundo.
Dibuja una cuadrícula de 4x4 que esté numerada así:
Ejecutemos esto en la consola del navegador: solo ponga
f=
antes del códigoEntonces, si quiero comenzar
1
, correríaf([1])([])
y me daría14
.Buen movimiento ... ¿Qué pasa si juego
2
después?f([2,1])([14])
. Se volverá13
.Déjame intentar rendirte. Jugar
3
.f([3,2,1])([14,13])
. Oh0
! ¡Me tienes!Jugar
0
?f([0,2,1])([14,13])
.15
Ok, sigamos jugando ...Nota
Juega interactivamente. Comenzar con
f([your-step])([])
.Antepone tu próximo paso. (Ver demo arriba)
Ayuda al "bot" a ingresar sus pasos. No le dará buenos resultados si le da una configuración aleatoria. (Al igual
f([1,2,4])([14,12])
que dará14
- ¡Hey, el bot quería jugar13
en su segundo movimiento!Resumen breve
Mientras no te rindas, el bot jugará un movimiento espejo.
Gracias @EHTproductions por decirme que leí mal las reglas del juego y los consejos de golf: P
Ahora también detectará si tiene jaque mate. Si es así, ¡bloquéalo!
Sus prioridades: Bloquear> Espejo> (respaldo) buscan formas de reproducir un espejo
fuente
3,2,1
para ti y0
para el bot una victoria para ti?[0,1,2,3].map(i=>{k(n=>n%4==i);k(n=>Math.floor(n/4)==i);})
se puede jugar al golf[0,1,2,3].map(i=>k(n=>n%4==i)+k(n=>(n/4|0)==i))
.