quine-ish tic-tac-toe

19

Écrivez un programme dans la langue de votre choix qui joue un jeu parfait de tic-tac-toe sur un tableau 3 * 3 contre un joueur humain. Cependant, chaque mouvement doit être un programme différent , généré à partir de l'itération précédente.

La façon dont vous évaluez la contribution humaine et la forme sous laquelle vous l'évaluez dépendent de vous, mais elle doit être lue à partir de la saisie standard. De même, vous êtes libre de choisir une méthode pour déterminer quel joueur commencera (par exemple, vous demandez d'abord, ou vous permettez à l'humain d'entrer un mouvement invalide pour signaler que l'ordinateur démarre, ou d'autres idées).

La validation des mouvements n'est pas nécessaire, vous pouvez supposer un adversaire humain assez joueur.

Fondamentalement, vous avez un programme qui correspond à un état de la carte. L'état est imprimé de n'importe quelle manière reconnaissable, mais au moins le niveau de détail suivant est attendu:

X..
00X
x..

Une fois que le joueur humain a entré ses mouvements, votre programme doit générer la prochaine itération de lui-même en tant que fichier source dans la même langue (soit vers la sortie standard, soit vers un fichier) et se terminer. Vous n'êtes pas autorisé à stocker des informations ailleurs que dans ce fichier source. (il n'est pas nécessaire que votre programme crée et exécute le programme généré, cela peut être fait par l'utilisateur - cependant, ce n'est pas interdit). Lorsque le programme généré est construit et exécuté, il se comportera de manière similaire, affichera l'état, attendra l'entrée de l'utilisateur, etc.

À la fin du jeu, vous devez imprimer le résultat (que vous ayez gagné ou que ce soit une égalité) de manière identifiable sans ambiguïté.

Par jeu parfait, je veux dire que le programme ne doit pas perdre, et s'il y a une possibilité de forcer une victoire, elle devrait gagner.

Le code le plus court gagne , le gagnant est sélectionné au moins 10 jours après la première entrée valide.

Vous obtenez une réduction de 10% du score si votre programme peut gérer la construction et le lancement de sa prochaine itération. (Je sais, cela n'en vaut probablement pas la peine) Bien sûr, le programme lui-même doit être terminé au moment où la prochaine itération accepte les mouvements de l'utilisateur.

Si vous utilisez des trucs étranges et inhabituels, veuillez poster une courte explication avec votre code.

vsz
la source
2
Beau défi, mais je pense que je vais me retirer.
John Dvorak
"Chaque mouvement doit être un programme différent". Voulez-vous dire, "chaque jeu doit être lancé et géré par une nouvelle instance distincte du programme d'origine"?
DavidC
1
@DavidCarraher: Non. Chaque coup, pas seulement chaque match. Vérifiez la description sous l'exemple de carte. Lorsque l'ordinateur doit bouger (de sorte que l'état de la carte change), votre programme doit générer un fichier source qui, une fois construit et exécuté, deviendra l'état suivant. Le programme d'origine se ferme ensuite. Le programme nouvellement généré, lors d'un déplacement, se comportera de la même manière: il crée un fichier source qui, une fois construit et exécuté, deviendra l'état suivant, et ainsi de suite. Comme aucun stockage d'informations n'est autorisé sauf dans le fichier source généré, c'est comme une quine avec des différences entre les itérations.
vsz

Réponses:

13

Perl, 933 caractères

$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"}

Veuillez noter que la ligne vierge au milieu du script doit en fait être là. (Les sauts de ligne à la fin des longues lignes ne sont pas nécessaires, sauf pour la lisibilité, et ne sont pas inclus dans le nombre de caractères.)

Utilisation: Lorsque le programme est exécuté sans arguments, il affiche l'état actuel du jeu. Puisqu'au début la carte est vide, la sortie sera:

...
...
...

Exécutez le programme avec un argument compris entre 1 et 9 pour réclamer ce carré comme mouvement. Le programme fera son propre mouvement, puis affichera un script de remplacement avec le nouvel état. Ainsi, par exemple:

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

Au tout premier tour seulement, vous pouvez donner un coup de 0pour indiquer que l'ordinateur doit prendre le premier coup. Notez que le premier joueur le sera toujours X.

Lorsque le jeu est terminé, la sortie d'affichage inclura une note à cet effet:

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

Le programme fonctionne en effectuant une recherche minimax standard de l'arbre de jeu. (Tic-tac-toe est un jeu suffisamment petit pour qu'un arbre de jeu complet puisse être généré à chaque exécution.) L'exception à cette règle est lorsque l'ordinateur se déplace en premier - dans ce cas, le déplacement initial vers le coin supérieur gauche est difficile- codé.

Notez que ce programme fonctionne à la manière d'une quine appropriée - à aucun moment le script n'accède à son propre fichier source afin de produire sa sortie.

boite à pain
la source
1
C'est beau! Je ne savais pas que je regardais un énorme ici-doc depuis le plus longtemps, puis j'ai fait une double prise.
Jesse Smith