Löse Mastermind in 6 oder weniger Zügen

24

Ihr Ziel ist es, ein Programm zu schreiben, das jedes Mastermind-Puzzle in 6 oder weniger Zügen löst.

Hintergrund

Mastermind ist ein Brettspiel. Das Ziel des Spiels ist es, die Kombination (Farben und Reihenfolge) von 4 farbigen Stiften, die der andere Spieler verbirgt, genau zu erraten. Wenn eine Vermutung vorliegt, antwortet der andere Spieler mit 0 bis 4 weißen und / oder roten Stiften. Bei einem roten Stift stimmen Farbe und Position. Bei einem weißen Stift ist die Farbe in den übrigen Stücken dargestellt, befindet sich jedoch an der falschen Stelle. Wenn die Vermutung doppelte Farben enthält, wird im Geheimnis nur ein Stift pro entsprechender Farbe vergeben. (Also - wenn das Geheimnis 1 Blau enthielte und die Vermutung 2 Blues mit einem an der richtigen Stelle hatte, würde ein roter Stift gegeben werden). Es gibt 6 verschiedene Farben und Duplikate können verwendet werden.

So könnte ein Spiel beispielsweise wie folgt ablaufen: (Angenommen, die Lösung lautet Rot Grün Grün Blau.)

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

Die Regeln werden auf Wikipedia erweitert

Bedarf

  • Das Programm muss von stdin lesen und nach stdout schreiben
  • Ich werde der Einfachheit halber Zahlen anstelle von Farben verwenden. Die zu erratende Kombination besteht aus 4 Zahlen zwischen 1 und 6
  • Sie müssen ihre Vermutungen als eine Reihe von 4 durch Leerzeichen getrennten Zahlen von 1 bis 6 ausgeben, die mit einem Zeilenumbruch abschließen. Zum Beispiel:

    1 5 2 2 \ n

  • Das Programm erhält anschließend als Eingabe 2 ganze Zahlen zwischen 0 und 4, die durch ein Leerzeichen getrennt sind und mit einer neuen Zeile abschließen. Das erste ist die Anzahl der weißen Stifte, das zweite die Anzahl der roten Stifte.

  • Bei einer Eingabe von "0 4" (4 rote Stifte) muss das Programm beendet werden
  • Das Programm muss in der Lage sein, jedes Rätsel in weniger als 6 Runden zu lösen (Ihr Programm gibt eine Ausgabe aus, gefolgt von einer Antworteingabe von 1 Runde). Es gibt keinen Bonus (aufgrund der Komplexität der Beweise), wenn Sie es in weniger lösen können.
  • Die Lösung muss vollständig intern sein und in der Quelle enthalten sein. Es sind nur Standardbibliotheken zulässig. Die Lösung ist daher möglicherweise nicht auf andere Dateien (z. B. Wörterbücher) oder das Internet angewiesen.

Beispiel Eingabe / Ausgabe

> 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 

Wertung

  • Das ist schlicht und einfach Code Golf . Die kürzeste Lösung in Bytes gewinnt.

Dies ist meine erste Code Golf Frage. Ich entschuldige mich, wenn ich etwas falsch gemacht habe, aber ich habe versucht, so gut wie möglich sicherzustellen, dass es absolut keine Unklarheiten gibt, und verhindert, dass so viele Regeln wie möglich erlassen werden. Wenn ich mehrdeutig oder unklar war, können Sie gerne Fragen stellen.

Lochok
quelle
1
In Ihrem Beispiel sollte die Eingabe / Ausgabe nicht 1 2 3 4zurückkehren 0 1?
Gaffi
1
Und sollte "Green Green Green Blue" im Beispieltext nicht auch einen weißen Stift geben (für das erste Grün)? BEARBEITEN - Wikipedia stellt klar, dass kein Weiß angegeben werden soll, wie Sie geschrieben haben. Aber ich denke, die Weiß / Schwarz-Regeln sollten in der Frage explizit angegeben werden.
Ugoren
Wie langsam darf es arbeiten?
aufgehört, gegen den Uhrzeigersinn am
@ Gaffi - Absolut richtig - behoben
Lochok
1
Die Regeln für weiße Stifte sind hier nicht angegeben. Angenommen, Sie haben 1234 gewählt, und ich schätze, 5611. Beide meine Einsen haben die richtige Farbe am falschen Ort. Aus der Art und Weise, wie Sie die Regeln angegeben haben, würde ich sagen, dass ich zwei Weiße bekomme. Aber nein - Wikipedia sagt, dass es 1 Weiß ist. Die falsche Methode ist auch einfacher zu programmieren (aber Steven Rumbalski hat die Regeln von Wikipedia korrekt implementiert).
Ugoren

Antworten:

8

Python 2 Python 3, 359 365 338 Zeichen

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()))

Witzigerweise habe ich viele Änderungen vorgenommen, um festzustellen, dass ich einen fünfstelligen Variablennamen hatte.

Ich mag die langen Importe nicht. Es fühlt sich an, als ob ich in der Lage sein sollte, einen Ersatz zu implementieren collections.Counter, der den Import erspart.

Das gefällt mir auch print(*(m.pop()))am Ende nicht. Es fühlt sich an, als sollte es in der while-Schleife verschwinden, aber ich kann keinen Weg finden, es zu tun, ohne es länger zu machen.

Steven Rumbalski
quelle
TypeError: join() takes exactly one argument (2 given)auf return j(sum(min(g.count(c),k.count(c))for c in set(g))-b,b). Außerdem gibt sum () ein int zurück, während j (str.join) einen iterablen Wert annehmen sollte
Blazer
Meine Loop-Struktur wird das Finale los printund ich denke, es ist etwas kürzer. Es stimmt auch besser mit dem angeforderten Verhalten überein (Anhalten bei "4 0", anstatt wenn Sie die Antwort kennen). Und len(m)>1== m[1:]. Import ist ja nervig - from a,b import *wäre schön gewesen.
Ugoren
Dieses Programm scheint zu beenden, wenn es sich richtig anfühlt. Einmal habe ich es ausgeführt und es hörte bei 5 Vermutungen auf, es war nicht korrekt. das nächste Mal hörte es bei 4 Vermutungen auf und es war korrekt, aber ich habe noch nicht einmal eingegeben 4 0, was in den objektiven Kriterien ist, und ein anderes Mal wird es mit einer Ausnahme beendet:print(*(m.pop())) KeyError: 'pop from an empty set'
Blazer
@Blazer. Welche Testfälle haben diese Ausgabe verursacht?
Steven Rumbalski
@ Blazer: 4 0ist vier weiße Stifte. Ich denke, Sie haben die Wertung umgekehrt.
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

Ich liebe es, rein funktionale interaktive Programme zu schreiben! Dieser Stil hat natürlich einige Einschränkungen: Er wird jetzt mit einem Fehler beendet, aber Sie haben nicht angegeben, dass dies nicht in Ordnung ist. Ich müsste das Ganze in die IOMonade umgestalten , um einen fehlerfreien Ausgang zu erhalten.

hörte auf, sich gegen den Uhrzeigersinn zu drehen
quelle
Garantiert es eine korrekte Schätzung in 6 Zügen?
Ugoren
Äh. Ich dachte, dass dies der Fall ist (funktioniert für das OP-Beispiel und andere Lösungen), aber ausführliche Tests haben gezeigt, dass manchmal 7 Vermutungen erforderlich sind. Daran muss ich noch arbeiten!
aufgehört, gegen den Uhrzeigersinn am
5

Python, 385 357 Zeichen, löst in 5 Zügen

Je mehr ich es ändere, desto mehr ähnelt es Steven Rumbalski ... Der Hauptunterschied besteht darin, dass er eher mit Zeichenfolgen als mit ganzen Zahlen arbeitet.
Knuths Algorithmus implementiert (hoffe ich jetzt richtig).
Leihte die Scoring-Funktion von Steven Rumbalski.
Es dauert lange, bis die erste Vermutung erstellt ist, und wird später besser.
Die Hardcodierung von it ( g=len(A)==1296 and [1,1,2,2] or ...) erleichtert das Leben, wenn Sie es testen möchten.
Ich zähle nicht 4 Zeilenumbrüche + Tabulatorpaare, die durch Semikolons ersetzt werden können.

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
quelle
"%d "*4%tuple(g)
Knabberzeug
from collections import*
Knabberzeug
a,b=map(int,raw_input())
Knabberzeug
product(*[range(1,7)]*4)
Knabberzeug
Counter(r(x,i)for i in A).values()
Knabberzeug