Faites une parfaite partie de Mu Torere

14

Contexte

Mu Torere est un jeu qui est l'un des deux seuls connus des Maoris de Nouvelle-Zélande avant l'influence européenne. Cela en fait un jeu très unique en ce qu'il a un "critère de gain objectif" et des règles de jeu différentes de la plupart des autres jeux existants.

Gameplay:

Le plateau est un octogone. Il existe des connexions entre chaque sommet adjacent et un nœud central est connecté à tous les sommets. À tout moment, huit des neuf nœuds sont occupés par des pierres. Au début, il y a quatre pierres blanches et quatre pierres noires qui occupent chacune la moitié de l'octogone, avec le nœud central vide. Les noirs bougent en premier.

Chaque tour, un joueur peut déplacer l'une de ses pierres le long d'un des 16 bords d'un nœud au nœud vide. Une pierre ne peut être déplacée d'un nœud extérieur au nœud central que si la pierre est à côté de la pierre d'un adversaire.

Un joueur perd lorsqu'il n'est pas en mesure d'effectuer un mouvement légal, ce qui se produit lorsqu'il n'y a aucun bord reliant une pierre au nœud vide.

Un schéma et une explication des règles

Voici un site Web qui explique les règles (avec un diagramme) et propose une analyse.

Le défi

Votre défi est d'écrire le programme le plus court qui puisse jouer un jeu parfait de Mu Torere contre un adversaire humain. Votre programme devrait être capable d'afficher et de mettre à jour le plateau de jeu, d'effectuer des mouvements et de recevoir des mouvements d'un adversaire humain. Plus important encore, il devrait jouer un jeu parfait.

Jeu parfait?

Oui, jeu parfait. J'ai fait une analyse de jeu et j'ai constaté que le jeu dure pendant une durée infinie s'il est joué parfaitement par les deux parties. Cela signifie que votre programme ne devrait jamais perdre. De plus, votre programme devrait être en mesure de forcer une victoire chaque fois que l'adversaire humain commet une erreur qui permet au programme de forcer une victoire. Quant à savoir comment votre programme trouve le mouvement parfait, cela dépend de vous.

Détails

Après chaque coup (et au début du jeu), votre programme devrait imprimer le plateau de jeu. Quelle que soit la façon dont vous choisissez d'afficher la carte, celle-ci doit afficher tous les nœuds et être entièrement connectée (les 16 lignes de connexion doivent être dessinées sans lignes croisées). Au départ, la planche doit avoir la bonne position de départ. Une façon d'y parvenir est de faire du plateau de jeu un carré.

w-w-w
|\|/|
b-o-w
|/|\|
b-b-b

Les deux couleurs sont noir et blanc ou foncé / clair. Le plateau doit montrer quels nœuds sont occupés par les pièces de quel joueur, comme les marquer avec un "b" ou "w", et quel nœud est vacant. Les participants sont encouragés (mais pas requis) à rendre le plateau de jeu plus graphique, plutôt que du texte brut.

Votre plateau de jeu devrait avoir un système de numérotation qui donne à chaque nœud un numéro unique. Vous pouvez choisir de numéroter le tableau comme bon vous semble, mais cela devrait être expliqué dans votre réponse ou par le programme. Le panneau carré peut être numéroté comme suit:

1-2-3
|\|/|
4-5-6
|/|\|
7-8-9

L'humain est le premier à bouger. Son entrée sera un numéro unique. Ce sera le numéro du nœud où se trouve actuellement la pierre déplacée. Si je voulais déplacer une pierre du nœud 4 vers un nœud vide 5, je taperai a 4. Le 5 est implicite car c'est le seul nœud vide.

Supposons que l'humain fera toujours un pas légal.

Après que l'humain se soit déplacé, un tableau mis à jour devrait être imprimé. Une fois que votre programme a décidé d'un coup légal, il devrait imprimer un autre tableau mis à jour, puis attendre que l'humain entre dans un autre coup.

Votre programme devrait se terminer une fois qu'il a gagné.

Remarques

Les règles de golf de code standard s'appliquent, pas d'accès aux fichiers externes, etc., etc. De plus, je vais imposer un délai flexible de 15 secondes (sur une machine raisonnable) pour que votre programme effectue chacun de ses mouvements. Comme indiqué, ce jeu a la possibilité de former des boucles infinies, et je ne veux pas qu'une recherche en profondeur passe dans une boucle infinie.

PhiNotPi
la source
2
Grand défi. Seulement "Si l'homme entre un mouvement illégal, alors votre programme devrait attendre et lui permettre de saisir un mouvement différent." me semble un peu anti-golf: ne pouvons-nous pas laisser le comportement indéfini en cas d'entrées illégales?
cessé de tourner dans
1
J'ai ajouté cette exigence à la dernière minute, et je suppose que ce serait bien si nous la supprimions. Cela rend tout simplement plus difficile pour l'humain, qui est déjà condamné à ne pas gagner. :)
PhiNotPi
1
Ce n'est pas si difficile de toujours entrer dans un mouvement légal ... Au fait, après une analyse assez détaillée, je pense qu'il n'est pas nécessaire de rechercher plus de 1,5 mouvement. Que cette approche soit la plus courte est une autre question.
Peter Taylor
3
Le site Web lié n'est plus disponible, il serait préférable de le transformer en lien vers une version archivée.
Tally

Réponses:

6

Rubis, 390 caractères

o=->s,c{f=s=~/o/;[*0..8].select{|t|s[t]==c&&(t<1||(t+6)%8+1==f||t%8+1==f||f<1&&(s[(t+6)%8+1]!=c||s[t%8+1]!=c))}.map{|t|k=s*1;k[f]=c;k[t]=?o;k}}
v=->s,c,h{f=o[s,c];f==[]?0:h<1?1:2-f.map{|t|v[t,c>?b??b:?w,h-1]}.min}
q=->g{puts"1-2-3\n|\\|/|\n8-0-4\n|/|\\|\n7-6-5\n".tr"0-8",g;$>.flush}
q[g="obbbbwwww"]
(g.tr!?o,?b;g[gets.to_i]=?o;q[g];q[g=o[g,?w].sort_by{|q|v[q,?w,5]}[-1]])while v[g,?b,5]>0

Une implémentation en rubis qui calcule directement l'arborescence du jeu (qui prend pas mal de code) et joue donc toujours de manière optimale. Les positions de la planche sont en spirale vers l'extérieur comme indiqué dans la figure suivante:

1 - 2 - 3
| \ | / |
8 - 0 - 4
| / | \ |
7 - 6 - 5
Howard
la source
5

bash et ses amis ( 463 447 caractères)

t(){ tr 0-8a-i $b$b
}
p(){ t<<E
0-1-2
|\|/|
3-4-5
|/|\|
6-7-8

E
}
g(){ b=`tr $x$e $e$x<<<012345678|t`
p
e=$x
}
b=bbbbowwww
e=4
m=0
p
while [ $m != 5 ]&&read x;do
g
m=0
for y in {0..8};do
s=0
S=05011234
grep -E "w.*($y$e|$e$y)"<<<${b:$y:1}30125876340142548746>/dev/null&&for p in wow.\*/ww wow.\*/w bbo.\*/b obb.\*/b www wbw .
do
((s++))
tr $y$e $e$y<<<3012587630/4e|t|grep $p>/dev/null&&break
done
s=${S:$s:1}
[ $s -gt $m ]&&m=$s x=$y
done
g
done

L'homme joue comme b, l'ordinateur comme w. La position du conseil est numérotée comme dans le doc ici en haut. Il s'avère que l'heuristique pour jouer à un jeu parfait est étonnamment simple.

D'un autre côté, perdre le chemin intéressant est assez difficile. http://ideone.com/sXJPy démontre le suicide le plus court possible contre ce bot. Notez que le 0 supplémentaire à la fin est pour tester qu'il sort correctement de la boucle.

Peter Taylor
la source
NB Je pourrais sauver un personnage en rendant read xobligatoire, mais cela rendrait les tests assez frustrants. Je pourrais aussi sauver un personnage en supprimant la ligne vierge après le tableau, mais ...
Peter Taylor