Memecahkan Mastermind dalam 6 gerakan atau kurang

24

Tujuan Anda adalah untuk menulis sebuah program yang akan memecahkan teka-teki Mastermind dalam 6 gerakan atau kurang.

Latar Belakang

Mastermind adalah permainan papan. Tujuan permainan ini adalah untuk menebak dengan tepat kombinasi (warna dan urutan) 4 pasak berwarna yang disembunyikan oleh pemain lain. Ketika tebakan dibuat, pemain lain merespons dengan antara 0 dan 4 pasak putih dan atau merah. Pasak merah adalah tempat warna dan lokasi benar. Pasak putih adalah tempat warna diwakili di bagian yang tersisa, tetapi di lokasi yang salah. Jika ada warna duplikat di tebakan, hanya akan ada satu pasak yang diberikan per warna yang sesuai dalam rahasia. (Jadi - jika rahasianya berisi 1 Biru, dan tebakan itu memiliki 2 blues dengan satu di lokasi yang benar, akan ada satu pasak merah yang diberikan). Ada 6 warna berbeda, dan duplikat dapat digunakan.

Jadi misalnya, permainan mungkin berjalan sebagai berikut: (Dengan asumsi solusinya adalah Merah Hijau Hijau Biru)

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

Aturan diperluas di Wikipedia

Persyaratan

  • Program harus membaca dari stdin, dan menulis ke stdout
  • Saya akan menggunakan angka untuk kesederhanaan, bukan warna. Kombinasi untuk menebak adalah 4 angka antara 1 dan 6
  • Mereka harus menampilkan tebakan mereka sebagai serangkaian 4 angka yang dipisahkan oleh spasi dari 1 hingga 6 yang diakhiri dengan baris baru. Contohnya:

    1 5 2 2 \ n

  • Program selanjutnya akan menerima input setelah tebakan 2 integer antara 0 dan 4 dipisahkan oleh spasi dan diakhiri dengan baris baru. Yang pertama adalah jumlah pasak putih, yang kedua jumlah pasak merah.

  • Pada input "0 4" (4 pasak merah), program harus diakhiri
  • Program harus mampu menyelesaikan puzzle apa pun dalam waktu kurang dari 6 putaran (program Anda memberikan output, diikuti oleh input respon adalah 1 putaran). Tidak ada bonus (karena kompleksitas pembuktian) karena dapat menyelesaikannya dalam waktu kurang.
  • Solusinya harus sepenuhnya internal dan termasuk dalam sumber. Hanya Perpustakaan Standar yang diizinkan. Karena itu solusinya mungkin tidak bergantung pada file lain (seperti kamus), atau internet.

Contoh 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 

Mencetak gol

  • Ini adalah Golf Code yang murni dan sederhana . Solusi terpendek dalam byte menang.

Ini adalah pertanyaan Golf Code pertama saya. Saya minta maaf jika saya telah melakukan sesuatu yang salah, tetapi saya telah berusaha sebaik mungkin untuk memastikan bahwa sama sekali tidak ada ambiguitas, dan mencegah sebanyak mungkin peraturan yang mengatur hukum. Jika saya ambigu atau tidak jelas, jangan ragu untuk bertanya.

lochok
sumber
1
Dalam contoh Anda input / output tidak boleh 1 2 3 4kembali 0 1?
Gaffi
1
Dan dalam contoh teks, tidakkah seharusnya "Green Green Green Blue" memberikan patokan putih juga (untuk Green pertama)? EDIT - Wikipedia menjelaskan bahwa tidak boleh ada putih yang diberikan, seperti yang Anda tulis. Tapi saya pikir aturan putih / hitam harus secara eksplisit dinyatakan dalam pertanyaan.
ugoren
Seberapa lambat itu akan dibiarkan bekerja?
Berhenti menghidupkan counterclockwis
@ Gaffi - Benar sekali - tetap
lochok
1
Aturan untuk pasak putih tidak disebutkan di sini. Misalkan Anda memilih 1234 dan saya kira 5611. Kedua 1 saya adalah warna yang tepat di tempat yang salah, jadi dari cara Anda menyatakan aturan saya akan mengatakan saya mendapatkan 2 putih. Tapi tidak - Wikipedia mengatakan itu 1 putih. Metode yang salah juga lebih mudah diprogram (tetapi Steven Rumbalski menerapkan aturan Wikipedia dengan benar).
ugoren

Jawaban:

8

Python 2 Python 3, 359 365 338 karakter

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

Lucu, saya butuh banyak suntingan untuk menyadari bahwa saya memiliki nama variabel lima karakter.

Saya tidak suka impor panjang. Rasanya seperti saya harus bisa menerapkan pengganti collections.Counteryang akan menghemat impor.

Saya juga tidak suka print(*(m.pop()))pada akhirnya. Rasanya seperti itu harus menghilang ke loop sementara, tetapi saya tidak dapat menemukan cara untuk melakukannya tanpa membuatnya lebih lama.

Steven Rumbalski
sumber
TypeError: join() takes exactly one argument (2 given)pada return j(sum(min(g.count(c),k.count(c))for c in set(g))-b,b). juga, jumlah () mengembalikan int, sementara j (str.join) harus mengambil iterable
Blazer
Struktur loop saya menghilangkan final print, dan saya pikir itu sedikit lebih pendek. Itu juga cocok dengan perilaku yang diminta lebih baik (berhenti pada "4 0" daripada ketika Anda tahu jawabannya). Dan len(m)>1== m[1:]. Impor memang menyebalkan - from a,b import *pasti menyenangkan.
ugoren
program ini sepertinya keluar kapan pun terasa benar. Suatu kali saya menjalankannya dan berhenti pada 5 tebakan, itu tidak benar. kali berikutnya berhenti pada 4 tebakan dan itu benar, tapi saya bahkan 4 0belum memasukkan , yang ada dalam kriteria objektif, dan di lain waktu itu akan keluar dengan pengecualian:print(*(m.pop())) KeyError: 'pop from an empty set'
Blazer
@Jaket. Apa kasus uji yang menyebabkan hasil ini?
Steven Rumbalski
@ Blazer: 4 0adalah empat pasak putih. Saya pikir skor Anda terbalik.
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

Saya suka menulis program interaktif murni fungsional! Tetapi tentu saja gaya ini memiliki batasan tertentu: sekarang diakhiri dengan kesalahan, tetapi Anda tidak menentukan bahwa ini tidak masalah. Saya perlu mengubah semuanya menjadi IOmonad untuk keluar tanpa kesalahan.

berhenti untuk memutar balik
sumber
Apakah itu menjamin tebakan yang benar dalam 6 gerakan?
ugoren
Uh. Saya pikir itu (berfungsi untuk contoh OP dan solusi lainnya), tetapi pengujian lengkap menunjukkan bahwa kadang-kadang membutuhkan 7 tebakan. Saya harus mengerjakan ini dulu!
Berhenti berputar counterclockwis
5

Python, 385 357 karakter, Menyelesaikan dalam 5 gerakan

Semakin saya mengubahnya, semakin banyak tumbuh seperti milik Steven Rumbalski ... Perbedaan utamanya adalah ia bekerja dengan string daripada bilangan bulat.
Diimplementasikan algoritma Knuth (sekarang dengan benar, saya harap).
Meminjam fungsi penilaian dari Steven Rumbalski.
Butuh waktu lama untuk menghasilkan tebakan pertama, menjadi lebih baik nanti.
Hard-coding it ( g=len(A)==1296 and [1,1,2,2] or ...) membuat hidup lebih mudah jika Anda ingin mengujinya.
Saya tidak menghitung 4 pasang baris baru + tab, yang dapat diganti dengan titik koma.

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