Risolvere Mastermind in 6 o meno mosse


24

Il tuo obiettivo è scrivere un programma che risolva qualsiasi enigma di Mastermind in 6 o meno mosse.

sfondo

Mastermind è un gioco da tavolo. L'obiettivo del gioco è indovinare esattamente la combinazione (colori e ordine) di 4 pioli colorati nascosti dall'altro giocatore. Quando viene fatta un'ipotesi, l'altro giocatore risponde con un numero compreso tra 0 e 4 pioli bianchi e o rossi. Un piolo rosso è dove il colore e la posizione sono corretti. Un piolo bianco è dove il colore è rappresentato nei pezzi rimanenti, ma si trova nella posizione errata. Se nell'ipotesi ci sono colori duplicati, nel segreto verrà assegnato un solo piolo per colore corrispondente. (Quindi - se il segreto contenesse 1 Blu, e l'ipotesi avesse 2 blu con uno nella posizione corretta, ci sarebbe un piolo rosso dato). Esistono 6 colori diversi e possono essere utilizzati duplicati.

Ad esempio, un gioco potrebbe essere il seguente: (Supponendo che la soluzione sia Rosso Verde Verde Blu)

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

Le regole sono estese su Wikipedia

Requisiti

  • Il programma deve leggere da stdin e scrivere su stdout
  • Userò i numeri per semplicità invece di colori. La combinazione da indovinare sarà di 4 numeri tra 1 e 6
  • Devono emettere le loro ipotesi come una serie di 4 numeri separati da spazio da 1 a 6 che si concludono con una nuova riga. Per esempio:

    1 5 2 2 \ n

  • Il programma riceverà successivamente come input dopo aver indovinato 2 numeri interi compresi tra 0 e 4 separati da uno spazio e conclusi con una nuova riga. Il primo sarà la quantità di pioli bianchi, il secondo la quantità di pioli rossi.

  • Con un input di "0 4" (4 pioli rossi), il programma deve terminare
  • Il programma deve essere in grado di risolvere qualsiasi enigma in meno di 6 turni (il programma che dà l'output, seguito dall'input di risposta è di 1 turno). Non vi è alcun bonus (a causa della complessità della prova) per essere in grado di risolverlo in meno.
  • La soluzione deve essere completamente interna e inclusa nell'origine. Sono ammesse solo le librerie standard. Pertanto, la soluzione potrebbe non fare affidamento su altri file (come dizionari) o su Internet.

Esempio di input / output

> 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 

punteggio

  • Questo è puro e semplice Code Golf . Vince la soluzione più breve in byte .

Questa è la mia prima domanda su Code Golf. Mi scuso se ho fatto qualcosa di sbagliato, ma ho cercato nel miglior modo possibile di garantire l'assenza di ambiguità e di prevenire quante più norme possibili legiferare. Se sono stato ambiguo o poco chiaro, non esitare a porre domande.


1
Nel tuo esempio input / output non dovrebbe 1 2 3 4tornare 0 1?
Gaffi,

1
E nel testo di esempio, "Verde Verde Verde Blu" non dovrebbe dare anche un piolo bianco (per il primo Verde)? EDIT - Wikipedia chiarisce che nessun bianco dovrebbe essere dato, come hai scritto. Ma penso che le regole bianco / nero debbano essere esplicitamente indicate nella domanda.
ugoren,

Quanto sarà lento il funzionamento?
cessò di girare in senso antiorario il

@Gaffi - Assolutamente giusto - risolto
lochok

1
Le regole per i pioli bianchi non sono indicate qui. Supponiamo che tu abbia scelto 1234 e suppongo 5611. Entrambi i miei 1 sono del colore giusto nel posto sbagliato, quindi dal modo in cui hai dichiarato le regole direi che ottengo 2 bianchi. Ma no - Wikipedia dice che è 1 bianco. Anche il metodo errato è più facile da programmare (ma Steven Rumbalski ha implementato correttamente le regole di Wikipedia).
ugoren,

Risposte:


8

Python 2 Python 3, 359 365 338 caratteri

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

Divertente, mi ci sono volute molte modifiche per rendermi conto che avevo un nome variabile di cinque caratteri.

Non mi piacciono le lunghe importazioni. Mi sento come se dovessi essere in grado di implementare una sostituzione per collections.Countersalvare l'importazione.

Anche print(*(m.pop()))alla fine non mi piace . Sembra che dovrebbe scomparire nel ciclo while, ma non riesco a trovare un modo per farlo senza allungarlo.


TypeError: join() takes exactly one argument (2 given)su return j(sum(min(g.count(c),k.count(c))for c in set(g))-b,b). inoltre, sum () restituisce un int, mentre j (str.join) dovrebbe prendere un iterabile
Blazer

La mia struttura ad anello si libera della finale printe penso che sia leggermente più corta. Abbina anche meglio il comportamento richiesto (fermandosi su "4 0" piuttosto che quando si conosce la risposta). E len(m)>1== m[1:]. L'importazione è davvero fastidiosa - from a,b import *sarebbe stato bello.
ugoren,

questo programma sembra uscire ogni volta che sembra giusto. una volta l'ho eseguito e si è fermato a 5 ipotesi, non era corretto. la prossima volta si è fermato a 4 ipotesi ed era corretto, ma non ho ancora inserito 4 0, che è nei criteri oggettivi, e altre volte uscirà con un'eccezione:print(*(m.pop())) KeyError: 'pop from an empty set'
Blazer

@Blazer. Quali sono i casi di test che hanno causato questo risultato?
Steven Rumbalski,

@Blazer: 4 0sono quattro pioli bianchi. Penso che tu abbia invertito il punteggio.
Steven Rumbalski il

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

Adoro scrivere programmi interattivi puramente funzionali! Ma ovviamente questo stile ha alcune limitazioni: termina ora con un errore, ma non hai specificato che non va bene. Dovrei refactificare il tutto nella IOmonade per ottenere un'uscita senza errori.


Garantisce un'ipotesi corretta in 6 mosse?
ugoren,

Uh. Ho pensato che fosse (funziona per l'esempio del PO e altre soluzioni), ma test approfonditi dimostrano che a volte ha bisogno di 7 ipotesi. Dovrò ancora lavorare su questo!
cessò di girare in senso antiorario il

5

Python, 385 357 caratteri, Risolve in 5 mosse

Più lo cambio, cresce sempre più come quello di Steven Rumbalski ... La differenza principale è che lavora con le stringhe piuttosto che con i numeri interi.
Implementato l'algoritmo di Knuth (correttamente ora, spero).
Preso in prestito la funzione di punteggio di Steven Rumbalski.
Ci vuole molto tempo per generare la prima ipotesi, migliora in seguito.
Hard-coding ( g=len(A)==1296 and [1,1,2,2] or ...) semplifica la vita se si desidera testarlo.
Non conto 4 newline + coppie di schede, che possono essere sostituite da punti e virgola.

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

"%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,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.