quine-ish tic-tac-toe

19

Escriba un programa en su idioma elegido que juegue un juego perfecto de tic-tac-toe en un tablero de 3 * 3 contra un jugador humano. Sin embargo, cada movimiento debe ser un programa diferente , generado a partir de la iteración anterior.

Depende de usted cómo y de qué forma evalúa el aporte humano, pero debe leerse a partir del aporte estándar. Del mismo modo, puede elegir un método para determinar qué jugador comienza (por ejemplo, pregunta primero, o permite que el humano ingrese un movimiento no válido para indicar que la computadora se inicia u otras ideas).

No es necesario validar movimientos, puedes asumir que eres un oponente humano que juega con justicia.

Básicamente, tiene un programa que corresponde a un estado del tablero. El estado se imprime de cualquier manera reconocible, pero al menos se espera el siguiente nivel de detalle:

X..
00X
x..

Después de que el jugador humano ingresó sus movimientos, su programa tiene que generar la siguiente iteración de sí mismo como un archivo fuente en el mismo idioma (ya sea a la salida estándar o a un archivo) y finalizar. No está permitido almacenar información en ningún otro lugar fuera de ese archivo fuente. (no es necesario que su programa compile y ejecute el programa generado, puede hacerlo el usuario; sin embargo, no está prohibido). Cuando el programa generado se construye y ejecuta, se comportará de manera similar, mostrará el estado, esperará la entrada del usuario, etc.

Al final del juego, debes imprimir el resultado (ya sea que hayas ganado o sea un empate) de una manera inequívocamente identificable.

Por juego perfecto quiero decir que el programa no debe perder, y si existe la posibilidad de forzar una victoria, debería ganar.

El código más corto gana , el ganador se selecciona al menos 10 días después de la primera entrada válida.

Obtiene una reducción del 10% en la puntuación si su programa puede manejar la construcción y el lanzamiento de su próxima iteración. (Lo sé, lo más probable es que no valga la pena). Por supuesto, el programa en sí debe estar terminado para cuando la próxima iteración acepte los movimientos del usuario.

Si usa algunos trucos extraños y poco comunes, publique una breve explicación con su código.

vsz
fuente
2
Buen desafío, pero creo que voy a optar por no participar.
John Dvorak
"Cada movimiento tiene que ser un programa diferente". ¿Quiere decir que "cada juego debe ser iniciado y administrado por una nueva instancia distinta del programa original"?
DavidC
1
@DavidCarraher: No. Cada movimiento, no solo cada juego. Verifique la descripción debajo del ejemplo del tablero. Cuando la computadora tiene que hacer un movimiento (para que cambie el estado del tablero), su programa tiene que generar un archivo fuente, que cuando se construye y ejecuta, se convertirá en el siguiente estado. El programa original se cierra. El programa recién generado, al hacer un movimiento, se comportará de manera similar: crea un archivo fuente, que cuando se crea y ejecuta, se convertirá en el siguiente estado, y así sucesivamente. Como no se permite el almacenamiento de información, excepto en el archivo fuente generado, es como una quine con diferencias entre iteraciones.
vsz

Respuestas:

13

Perl, 933 caracteres

$m=<<'';$_='         ';
sub h{/^(?:...)*(\d)\1\1/|/^.?.?(\d)..\1..\1/|/(\d)...\1...\1/|/^..(\d).\1.\1/&&$1}
sub r{substr($_,$p-1,1)=pop}sub p{my$w=pop;my@b=(0,h==$w||h&&-1);if(!$b[1]&&/ /){$b[1]=-9;
while(/ /g){local($_,$p)=($_,pos);r$w;$r=-(p($w^1))[1];@b=($p,$r)if$r>$b[1]}}@b}
if(($w=h||!/ /)||!@ARGV){$w--&&print+(nobody,X,O)[$w]," wins\n";s/(...)/$1\n/g;
tr/ 23/.XO/;print}else{$w=3;$w^=1for/\d/g;($p=pop)?r($w^1)&&!h&&(($p)=p$w)&&r$w:s/ /2/;
print"\$m=<<'';\$_='$_';\n$m\n$m"}

sub h{/^(?:...)*(\d)\1\1/|/^.?.?(\d)..\1..\1/|/(\d)...\1...\1/|/^..(\d).\1.\1/&&$1}
sub r{substr($_,$p-1,1)=pop}sub p{my$w=pop;my@b=(0,h==$w||h&&-1);if(!$b[1]&&/ /){$b[1]=-9;
while(/ /g){local($_,$p)=($_,pos);r$w;$r=-(p($w^1))[1];@b=($p,$r)if$r>$b[1]}}@b}
if(($w=h||!/ /)||!@ARGV){$w--&&print+(nobody,X,O)[$w]," wins\n";s/(...)/$1\n/g;
tr/ 23/.XO/;print}else{$w=3;$w^=1for/\d/g;($p=pop)?r($w^1)&&!h&&(($p)=p$w)&&r$w:s/ /2/;
print"\$m=<<'';\$_='$_';\n$m\n$m"}

Tenga en cuenta que la línea en blanco en el medio de la secuencia de comandos realmente debe estar allí. (Los saltos de línea al final de las líneas largas no son obligatorios, excepto para la legibilidad, y no se incluyen en el recuento de caracteres).

Uso: cuando el programa se ejecuta sin argumentos, muestra el estado actual del juego. Como al principio el tablero está vacío, la salida será:

...
...
...

Ejecute el programa con un argumento entre 1 y 9 para reclamar esa casilla como su movimiento. El programa hará su propio movimiento y luego generará un script de reemplazo con el nuevo estado. Así, por ejemplo:

$ perl ./qttt 5 > ./qttt-2
$ perl ./qttt-2
O..
.X.
...

Solo en el primer turno, puede hacer un movimiento 0para indicar que la computadora debe hacer el primer movimiento. Tenga en cuenta que el primer jugador siempre será X.

Cuando termine el juego, la salida de la pantalla incluirá una nota a tal efecto:

$ perl ./qttt-4 6 > ./qttt-5
$ perl ./qttt-5
O wins
OXX
OOX
X.O

El programa funciona haciendo una búsqueda estándar de minimax del árbol del juego. (Tic-tac-toe es un juego lo suficientemente pequeño como para generar un árbol de juego completo en cada carrera). La excepción a esto es cuando la computadora se mueve primero, en este caso el movimiento inicial a la esquina superior izquierda es difícil. codificado

Tenga en cuenta que este programa funciona a la manera de una quine adecuada: en ningún momento el script accede a su propio archivo fuente para producir su salida.

caja de pan
fuente
1
¡Eso es hermoso! No me di cuenta de que estaba mirando un enorme documento aquí durante mucho tiempo, luego hice una doble toma.
Jesse Smith