Tic-Tac-Latin!
Ceci est une histoire vraie, donc les noms ont été modifiés.
Mon professeur de latin, M. Latin, a créé sa propre variante propriétaire (sans blague) tic tac toe. Appelons-le tic-tac-latin. Le jeu est simple, il s'agit essentiellement de tic tac toe joué sur une grille de quatre par quatre.
Déclaration de règle formelle
Une ligne est soit une ligne, une colonne ou une diagonale. Il existe deux symboles, «X» et «O», mais l'un ou les deux peuvent remplacer un symbole différent.
Vous marquez un point lorsque vous avez trois de votre symbole et l'un de l'autre personnage.
Ces arrangements marquent:
--- O -O-- XXXO XOOX O -XX - O - - X - --- O
Ceux-ci ne marquent pas:
---- XXXX ---- OOOO ---- XXX- ---- OOO-
La partie est gagnée chaque fois qu'un joueur a plus de points qu'un autre. Le jeu n'est nul que si le plateau est rempli.
Défi
Résolvez ce jeu. Votre travail consiste à fournir un moyen de garantir une victoire ou une égalité, selon le résultat optimal.
Votre solution peut choisir de commencer en premier ou en deuxième (et peut donc choisir son symbole). Il n'est pas obligatoire de mettre en œuvre un jeu interactif où les entrées de l'utilisateur se déplacent et l'affichage correspondant change. Il peut également s'agir d'une fonction ou d'un programme qui prend l'entrée en tant qu'état de jeu et génère un nouveau plateau ou une description de son mouvement . L'une ou l'autre option doit s'exécuter dans environ dix secondes par mouvement effectué.
Jouer votre joueur contre n'importe quelle séquence de mouvements doit donner le résultat optimal. Cela signifie que vous pouvez supposer que la position d'entrée est une position accessible depuis le jeu avec votre lecteur. Les soumissions doivent être déterministes et ne doivent pas nécessairement fournir une preuve d'optimalité, mais si elles sont fissurées (en étant battues), vos soumissions seront considérées comme non valides (vous pouvez les laisser en place, mais ajouter (fissurées) dans le titre).
Il s'agit d'une tâche non triviale, donc toute soumission valide est impressionnante et mérite une coche acceptée, mais je ferai du code golf le principal critère de gain.
Le gagnant est choisi en descendant cette liste jusqu'à ce qu'un gagnant soit choisi.
- Mise en œuvre résolue la plus courte qui gagne toujours
- Mise en œuvre la plus courte
Réponses:
Perl, 147 octets (non concurrent, prend plus de 10 secondes par coup)
Comprend +4 pour
-0p
Le programme joue
X
. Il jouera un jeu parfait.Entrez la carte sur STDIN, par exemple:
La ouptut sera la même carte avec tous
X
remplacés parO
et vice versa. Les emplacements vides seront remplis d'un nombre indiquant le résultat si X y jouerait, ce qui1
signifie que le résultat sera une victoire,2
un match nul et3
une défaite. Un jeu terminé renvoie simplement la même position avec les couleurs inversées.Dans cet exemple, la sortie serait:
La position est donc une victoire
X
s'il joue aux 3 places en haut et à gauche. Tous les autres coups perdent.Cette sortie déroutante est en fait pratique si vous voulez savoir comment le jeu continue après un coup. Puisque le programme est toujours joué,
X
vous devez échangerX
etO
voir les mouvementsO
. Ici, par exemple, il est assez clair que l'onX
gagne en jouant en haut à gauche, mais qu'en est-il s'ilX
joue en troisième position en haut? Copiez simplement la sortie, mettez unO
à la place du mouvement que vous sélectionnez et remplacez tous les autres numéros par-
, alors voici:Résultant en:
Évidemment, chaque coup
O
doit perdre, alors comment perd-il s'il joue en haut à gauche? Faites de nouveau ceci en mettantO
en haut à gauche et en remplaçant les chiffres par-
:Donnant:
X n'a donc qu'une seule voie à suivre pour sa victoire:
Donnant
La situation
O
reste désespérée. Il est facile de voir maintenant que chaque mouvement permetX
de gagner immédiatement. Essayons au moins d'aller chercher 3 O d'affilée:Donnant:
X
joue le seul coup gagnant (notez que cela fait leXXXO
long de la troisième colonne:Ici, la sortie est:
parce que le jeu était déjà terminé. Vous pouvez voir la victoire sur la troisième colonne.
Le programme actuel
tictaclatin.pl
:Appliqué au tableau vide, il évalue 9506699 positions, ce qui prend 30 Go et 41 minutes sur mon ordinateur. Le résultat est:
Donc, chaque coup de départ est nul. Le jeu est donc un match nul.
L'utilisation extrême de la mémoire est principalement causée par la récursivité utilisant
do$0
. L'utilisation de cette version de 154 octets à l'aide d'une fonction simple nécessite 3 Go et 11 minutes:ce qui est plus supportable (mais toujours trop, quelque chose doit encore fuir la mémoire).
La combinaison d'un certain nombre d'accélérations conduit à cette version de 160 octets (5028168 positions, 4 minutes et 800M pour le plateau vide):
Ce dernier utilise
0
pour une victoire (ne pas confondre avecO
),1
pour un match nul et2
pour une défaite. La sortie de celui-ci est également plus déroutante. Il remplit le coup gagnant pour X en cas de victoire sans changement de couleur, mais si le jeu d'entrée a déjà été gagné, le changement de couleur continue et ne remplit aucun coup.Toutes les versions deviennent bien sûr plus rapides et utilisent moins de mémoire lorsque la carte se remplit. Les versions plus rapides devraient générer un coup en moins de 10 secondes dès que 2 ou 3 coups ont été effectués.
En principe, cette version de 146 octets devrait également fonctionner:
mais sur ma machine, il déclenche un bogue perl et vide le noyau.
Toutes les versions fonctionneront en principe toujours si la mise en cache de position de 6 octets effectuée par
$$_||=
est supprimée mais qui utilise tellement de temps et de mémoire qu'elle ne fonctionne que pour les cartes presque remplies. Mais en théorie au moins, j'ai une solution de 140 octets.Si vous mettez
$\=
(coût: 3 octets) juste avant,$@<=>0
chaque carte de sortie sera suivie par le statut de la carte entière:1
pour lesX
victoires,0
pour le match nul et-1
pour la perte.Voici un pilote interactif basé sur la version la plus rapide mentionnée ci-dessus. Le conducteur n'a aucune logique pour la fin du jeu, vous devez donc vous arrêter. Le code golfé le sait cependant. Si le coup suggéré revient sans être
-
remplacé par quoi que ce soit, la partie est terminée.la source
$move
est déclaré à la ligne 11. Je n'ai aucune idée s'il existe une heuristique humaine. Ce programme ne fait que minimax sur l'arbre de jeu, il n'a aucune connaissance stratégique.JavaScript (ES6) 392 octets
Usage
Le "bot" jouera en second.
Dessinez une grille 4x4 numérotée comme suit:
Exécutons ceci dans la console du navigateur: il suffit de mettre
f=
avant le codeDonc, si je veux commencer
1
, je courraisf([1])([])
et ça me donnerait14
.Joli coup ... Et si je jouais
2
après?f([2,1])([14])
. Il reviendra13
.Laisse-moi essayer de te rendre. Jouez
3
.f([3,2,1])([14,13])
. Oh0
! Tu m'as eu!Jouer
0
?f([0,2,1])([14,13])
.15
Ok continuons à jouer ...Remarque
Jouez de manière interactive. Commencez par
f([your-step])([])
.Préparez votre prochaine étape. (Voir la démo ci-dessus)
Aidez le "bot" à entrer ses étapes. Il ne vous donnera pas de bons résultats si vous lui donnez un réglage aléatoire. (Comme
f([1,2,4])([14,12])
donnera14
- Hé, le bot voulait jouer13
à son deuxième coup!Bref résumé
Tant que vous ne vous rendez pas, le bot jouera un mouvement de miroir.
Merci @EHTproductions de m'avoir dit que j'avais mal lu les règles du jeu et les astuces de golf: P
Maintenant, il détectera également s'il a échoué. Si oui, bloquez-le!
Ses priorités: Block> Mirror> (fallback) chercher des moyens de reproduire un miroir
la source
3,2,1
pour vous et0
pour le bot une victoire pour vous?[0,1,2,3].map(i=>{k(n=>n%4==i);k(n=>Math.floor(n/4)==i);})
peut être joué au golf[0,1,2,3].map(i=>k(n=>n%4==i)+k(n=>(n/4|0)==i))
.