Resolvendo Mastermind em 6 ou menos movimentos

24

Seu objetivo é escrever um programa que resolva qualquer quebra-cabeça do Mastermind em 6 ou menos movimentos.

fundo

Mastermind é um jogo de tabuleiro. O objetivo do jogo é adivinhar exatamente a combinação (cores e ordem) de quatro pinos coloridos escondidos pelo outro jogador. Quando um palpite é feito, o outro jogador responde com 0 a 4 pinos brancos e ou vermelhos. Um peg vermelho é onde a cor e o local estão corretos. Uma cavilha branca é o local onde a cor é representada nas peças restantes, mas está no local incorreto. Se houver cores duplicadas no palpite, haverá apenas um peg atribuído por cor correspondente no segredo. (Então - se o segredo contivesse 1 azul e o palpite tivesse 2 azuis com um no local correto, haveria um pino vermelho). Existem 6 cores diferentes e duplicatas podem ser usadas.

Por exemplo, um jogo pode ser o seguinte: (Supondo que a solução seja Vermelho Verde Verde Azul)

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

As regras são expandidas na Wikipedia

Exigências

  • O programa deve ler de stdin e gravar em stdout
  • Vou usar números para simplificar, em vez de cores. A combinação de adivinhação será de 4 números entre 1 e 6
  • Eles devem emitir suas suposições como uma série de 4 números separados por espaço de 1 a 6, concluindo com uma nova linha. Por exemplo:

    1 5 2 2 \ n

  • O programa receberá subseqüentemente como entrada após seu palpite 2 números inteiros entre 0 e 4 separados por um espaço e concluindo com uma nova linha. O primeiro será a quantidade de pinos brancos, o segundo a quantidade de pinos vermelhos.

  • Em uma entrada de "0 4" (4 pinos vermelhos), o programa deve terminar
  • O programa deve ser capaz de resolver qualquer quebra-cabeça em menos de 6 turnos (o seu programa fornece saída, seguido pela entrada de resposta é 1 turno). Não há bônus (devido à complexidade da prova) por poder resolvê-lo em menos.
  • A solução deve ser completamente interna e incluída na fonte. Bibliotecas padrão são permitidas apenas. Portanto, a solução não pode depender de outros arquivos (como dicionários) ou da Internet.

Exemplo de entrada / saída

> 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 

Pontuação

  • Este é o código Golf puro e simples . A solução mais curta em bytes vence.

Esta é minha primeira pergunta sobre o Code Golf. Peço desculpas se fiz algo errado, mas tentei o máximo possível para garantir que não haja ambiguidade e impedir o máximo de regras possível. Se eu fui ambíguo ou incerto, sinta-se à vontade para fazer perguntas.

Lochok
fonte
11
No seu exemplo, entrada / saída não deve 1 2 3 4retornar 0 1?
precisa saber é
11
E no texto de exemplo, "Green Green Green Blue" também não deve conter um alfinete branco (para o primeiro verde)? EDIT - Wikipedia esclarece que nenhum branco deve ser dado, como você escreveu. Mas acho que as regras de branco / preto devem ser explicitamente declaradas na pergunta.
precisa saber é o seguinte
Quão lento será permitido trabalhar?
deixou de girar no sentido anti-
@Gaffi - Absolutamente certo - fixo
lochok 21/03
11
As regras para estacas brancas não são declaradas aqui. Suponha que você escolheu 1234 e eu acho 5611. Ambos os meus 1s são da cor certa no lugar errado, então, pela maneira como você definiu as regras, eu diria que eu tenho 2 brancos. Mas não - a Wikipedia diz que é 1 branco. O método incorreto também é mais fácil de programar (mas Steven Rumbalski implementou corretamente as regras da Wikipedia).
22712 ugoren

Respostas:

8

Python 2 Python 3, 359 365 338 caracteres

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

Engraçado, levei muitas edições para perceber que eu tinha um nome de variável de cinco caracteres.

Eu não gosto das importações longas. Parece que eu deveria ser capaz de implementar uma substituição, o collections.Counterque salvaria a importação.

Eu também não gosto do print(*(m.pop()))no final. Parece que ele deve desaparecer no loop while, mas não consigo encontrar uma maneira de fazê-lo sem prolongá-lo.

Steven Rumbalski
fonte
TypeError: join() takes exactly one argument (2 given)em diante return j(sum(min(g.count(c),k.count(c))for c in set(g))-b,b). Também, soma () retorna um inteiro, enquanto j (str.join) deve ter uma iteráveis
Blazer
Minha estrutura de loop se livra da final printe acho que é um pouco menor. Também combina melhor com o comportamento solicitado (parando em "4 0" e não quando você sabe a resposta). E len(m)>1== m[1:]. A importação é realmente irritante - from a,b import *teria sido bom.
ugoren
esse programa parece sair sempre que achar necessário. uma vez eu executei e parou em 5 palpites, não estava correto. da próxima vez, ele parou em 4 palpites e estava correto, mas eu ainda não inseri 4 0, o que está nos critérios objetivos, e outras vezes ele sai com uma exceção:print(*(m.pop())) KeyError: 'pop from an empty set'
Blazer
@Blazer. Quais são os casos de teste que causaram essa saída?
Steven Rumbalski 22/03
@ Blazer: 4 0são quatro pinos brancos. Eu acho que você tem a pontuação invertida.
Steven Rumbalski 22/03/12
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 escrever programas interativos puramente funcionais! Mas é claro que esse estilo tem certas limitações: termina agora com um erro, mas você não especificou que isso não está correto. Eu precisaria refatorar tudo na IOmônada para obter uma saída sem erro.

deixou de girar contra-relógio
fonte
Isso garante um palpite correto em 6 jogadas?
22412 ugoren
Uh Eu pensei que era (funciona para o exemplo do OP e outras soluções), mas testes exaustivos mostram que às vezes precisa de 7 suposições. Ainda terei que trabalhar nisso!
deixou de girar contra-
5

Python, 385 357 caracteres, resolve em 5 movimentos

Quanto mais eu mudo, ele se torna cada vez mais parecido com o de Steven Rumbalski ... A principal diferença é que ele trabalha com strings em vez de números inteiros.
Implementado o algoritmo de Knuth (corretamente agora, espero).
Emprestou a função de pontuação de Steven Rumbalski.
Demora muito tempo para gerar o primeiro palpite, melhora depois.
Codificá-lo ( g=len(A)==1296 and [1,1,2,2] or ...) facilita a vida se você quiser testá-lo.
Não conto quatro linhas novas + pares de guias, que podem ser substituídos por ponto e vírgula.

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
fonte
"%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