Résoudre Mastermind en 6 mouvements ou moins

24

Votre objectif est d'écrire un programme qui résoudra tout puzzle Mastermind en 6 mouvements ou moins.

Contexte

Mastermind est un jeu de société. Le but du jeu est de deviner exactement la combinaison (couleurs et ordre) de 4 chevilles colorées cachées par l'autre joueur. Quand une supposition est faite, l'autre joueur répond entre 0 et 4 chevilles blanches et ou rouges. Une cheville rouge est l'endroit où la couleur et l'emplacement sont corrects. Une cheville blanche est l'endroit où la couleur est représentée dans les pièces restantes, mais est au mauvais endroit. S'il y a des couleurs en double dans la supposition, il n'y aura qu'une seule cheville attribuée par couleur correspondante dans le secret. (Donc - si le secret contenait 1 bleu et que la supposition avait 2 bleus avec un au bon endroit, il y aurait une cheville rouge donnée). Il existe 6 couleurs différentes et des doublons peuvent être utilisés.

Ainsi, par exemple, un jeu peut se dérouler comme suit: (en supposant que la solution est Rouge Vert Vert Bleu)

1:  Blue Purple Black Green - 2 white pegs
2:  Green Red Black Blue    - 2 white pegs, 1 red peg
3:  Green Green Green Blue  - 3 red pegs
4:  Red Green Green Blue    - 4 red pegs

Les règles sont développées sur Wikipedia

Exigences

  • Le programme doit lire depuis stdin et écrire dans stdout
  • J'utiliserai des chiffres pour plus de simplicité au lieu de couleurs. La combinaison à deviner sera 4 nombres entre 1 et 6
  • Ils doivent produire leurs suppositions sous la forme d'une série de 4 nombres séparés par des espaces de 1 à 6 se terminant par une nouvelle ligne. Par exemple:

    1 5 2 2 \ n

  • Le programme recevra ensuite en entrée après sa supposition 2 entiers compris entre 0 et 4 séparés par un espace et se terminant par une nouvelle ligne. Le premier sera la quantité de chevilles blanches, le second la quantité de chevilles rouges.

  • Sur une entrée de "0 4" (4 piquets rouges), le programme doit se terminer
  • Le programme doit être capable de résoudre n'importe quel casse-tête en moins de 6 tours (votre programme donnant une sortie, suivi de l'entrée de réponse est de 1 tour). Il n'y a pas de bonus (en raison de la complexité de la preuve) pour pouvoir le résoudre en moins.
  • La solution doit être complètement interne et incluse dans la source. Seules les bibliothèques standard sont autorisées. La solution ne peut donc pas s'appuyer sur d'autres fichiers (tels que des dictionnaires) ou sur Internet.

Exemple d'entrée / sortie

> is your programs output
< is the responding input
Solution is 1 5 6 6

> 1 2 3 4
< 0 1
> 4 1 6 6
< 1 2
> 1 6 5 6
< 2 2
> 1 5 6 6
< 0 4 

Notation

  • Il s'agit de Code Golf pur et simple . La solution la plus courte en octets gagne.

Ceci est ma première question sur Code Golf. Je m'excuse si j'ai fait quelque chose de mal, mais j'ai essayé au mieux de faire en sorte qu'il n'y ait absolument aucune ambiguïté et d'empêcher autant de règles que possible d'avocat. Si j'ai été ambigu ou peu clair, n'hésitez pas à poser des questions.

lochok
la source
1
Dans votre exemple, l'entrée / sortie ne devrait pas 1 2 3 4revenir 0 1?
Gaffi
1
Et dans l'exemple de texte, "Green Green Green Blue" ne devrait-il pas également donner une cheville blanche (pour le premier vert)? EDIT - Wikipedia précise qu'aucun blanc ne doit être donné, comme vous l'avez écrit. Mais je pense que les règles blanches / noires devraient être explicitement énoncées dans la question.
ugoren
À quel rythme sera-t-il autorisé à fonctionner?
cessé de tourner dans le sens inverse des aiguilles d'une montre
@Gaffi - Absolument à droite - fixe
lochok
1
Les règles pour les chevilles blanches ne sont pas énoncées ici. Supposons que vous ayez choisi 1234 et je suppose 5611. Mes deux 1 sont de la bonne couleur au mauvais endroit, donc d'après la façon dont vous avez énoncé les règles, je dirais que j'obtiens 2 blancs. Mais non - Wikipedia dit que c'est 1 blanc. La méthode incorrecte est également plus facile à programmer (mais Steven Rumbalski a correctement mis en œuvre les règles de Wikipedia).
ugoren

Réponses:

8

Python 2 Python 3, 359 365 338 caractères

from itertools import*
from collections import*
m=h=set(product(*['123456']*4))
def f(g,k):b=sum(x==y for x,y in zip(g,k));return'%s %s'%(sum(min(g.count(c),k.count(c))for c in set(g))-b,b)
while len(m)>1:g=min(h,key=lambda g:max(Counter(f(g,k)for k in m).values()));print(*g);s=input();m=set(x for x in m if s==f(g,x))
print(*(m.pop()))

Drôle, il m'a fallu de nombreuses modifications pour réaliser que j'avais un nom de variable à cinq caractères.

Je n'aime pas les longues importations. J'ai l'impression que je devrais être en mesure d'implémenter un remplacement collections.Counterqui sauverait l'importation.

Je n'aime pas non plus print(*(m.pop()))la fin. J'ai l'impression qu'il devrait disparaître dans la boucle while, mais je ne peux pas trouver un moyen de le faire sans l'allonger.

Steven Rumbalski
la source
TypeError: join() takes exactly one argument (2 given)le return j(sum(min(g.count(c),k.count(c))for c in set(g))-b,b). aussi, sum () renvoie un int, tandis que j (str.join) devrait prendre un itérable
Blazer
Ma structure de boucle se débarrasse de la finale print, et je pense qu'elle est légèrement plus courte. Il correspond également mieux au comportement demandé (arrêt sur "4 0" plutôt que lorsque vous connaissez la réponse). Et len(m)>1== m[1:]. L'importation est en effet ennuyeux - from a,b import *aurait été agréable.
ugoren
ce programme semble se terminer chaque fois qu'il le juge bon. une fois je l'ai couru et il s'est arrêté à 5 suppositions, ce n'était pas correct. la prochaine fois, il s'est arrêté à 4 suppositions et c'était correct, mais je n'ai même pas encore entré 4 0, ce qui est dans les critères objectifs, et d'autres fois, il sortira avec une exception:print(*(m.pop())) KeyError: 'pop from an empty set'
Blazer
@Veste. Quels sont les cas de test qui ont provoqué cette sortie?
Steven Rumbalski
@Blazer: 4 0c'est quatre chevilles blanches. Je pense que le score est inversé.
Steven Rumbalski
7

Haskell, 317 304

q[0,4]_=error""
q[n,m]l=(\s->all(==4-m)[g s,n+g(u(foldr((u((.drop 1).(++)).).break.(==)))$unzip s)]).c(u(/=)).zip l
u=uncurry;m=map;g=length;c=filter
f a=[head.c(($(zipWith q(take n a)$f a)).all.flip($)).sequence$replicate 4[1..6]|n<-[0..]]
main=interact$unlines.m(unwords.m show).f.m(m read.words).lines

J'adore écrire des programmes interactifs purement fonctionnels! Mais bien sûr, ce style a certaines limites: il se termine maintenant avec une erreur, mais vous n'avez pas spécifié que ce n'est pas correct. J'aurais besoin de refactoriser le tout dans la IOmonade pour obtenir une sortie sans erreur.

a cessé de tourner dans le sens antihoraire
la source
Garantit-il une estimation correcte en 6 coups?
ugoren
Euh. Je le pensais (fonctionne pour l'exemple de l'OP et d'autres solutions), mais des tests exhaustifs montrent qu'il a parfois besoin de 7 suppositions. Je devrai encore travailler là-dessus!
cessé de tourner dans le sens antihoraire
5

Python, 385 357 caractères, résout en 5 mouvements

Plus je le change, il grandit de plus en plus comme celui de Steven Rumbalski ... La principale différence est qu'il travaille avec des cordes plutôt qu'avec des entiers.
Implémentation de l'algorithme de Knuth (correctement maintenant, j'espère).
A emprunté la fonction de notation à Steven Rumbalski.
Cela prend beaucoup de temps pour générer la première supposition, s'améliore plus tard.
Le codage en dur it ( g=len(A)==1296 and [1,1,2,2] or ...) facilite la vie si vous voulez le tester.
Je ne compte pas 4 nouvelles lignes + tabulations, qui peuvent être remplacées par des points-virgules.

from collections import*
from itertools import*
a=B=A=list(product(*[range(1,7)]*4))
r=lambda g,k:(sum(x==y for x,y in zip(g,k)),sum(min(g.count(c),k.count(c))for c in set(g)))
while a!=4:
    g=A[1:]and min(B,key=lambda x:max(Counter(r(x,i)for i in A).values()))or A[0]
    print"%d "*4%tuple(g)
    b,a=map(int,raw_input().split())
    A=[x for x in A if r(g,x)==(a,a+b)]
ugoren
la source
"%d "*4%tuple(g)
gnibbler
from collections import*
gnibbler
a,b=map(int,raw_input())
gnibbler
product(*[range(1,7)]*4)
gnibbler
Counter(r(x,i)for i in A).values()
gnibbler