Вирішення натхненника в 6 і менше рухів


24

Ваша мета - написати програму, яка вирішить будь-яку головоломку Mastermind за 6 і менше рухів.

Фон

Натхненник - настільна гра. Мета гри - точно вгадати поєднання (кольори та порядок) 4 кольорових кілочків, прихованих іншим гравцем. Коли здогадка зроблена, інший гравець відповідає між 0 і 4 білими або червоними кілочками. Червоний кілочок - це правильний колір та розташування. Білий кілочок - це те, де колір зображений на решти фрагментах, але знаходиться в неправильному місці. Якщо у відгадуванні є дублюючі кольори, буде виділено лише один кілочок для відповідного кольору в секреті. (Отже - якби секрет містив 1 Блакитний, а здогад мав 2 блюзи з одним у правильному місці, було б вказано один червоний кілочок). Є 6 різних кольорів, і можуть бути використані дублікати.

Так, наприклад, гра може йти наступним чином: (якщо припустити, що це червоний зелений зелений синій)

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

Правила розширені у Вікіпедії

Вимоги

  • Програма повинна читати зі stdin та записувати до stdout
  • Я буду використовувати цифри для простоти замість кольорів. Комбінація для здогадки складе 4 числа від 1 до 6
  • Вони повинні виводити свої здогадки у вигляді серії з чотирьох розділених пробілами чисел від 1 до 6, що закінчуються новим рядком. Наприклад:

    1 5 2 2 \ n

  • Згодом програма отримає як вхід після її здогадки 2 цілих числа між 0 і 4, розділених пробілом і закінчуючи новим рядком. Перша буде кількість білих кілочків, друга кількість червоних кілочків.

  • На вході "0 4" (4 червоних кілочки) програма повинна припинитися
  • Програма повинна вміти вирішувати будь-яку головоломку менш ніж за 6 оборотів (програма, яка дає вихід, з подальшим входом відповіді - 1 оборот). Не існує бонусу (через складність доказування) за можливість вирішити його менше.
  • Розчин повинен бути повністю внутрішнім і включатися до джерела. Дозволені лише стандартні бібліотеки. Тому рішення може не покладатися на будь-які інші файли (наприклад, словники) чи Інтернет.

Приклад введення / виводу

> 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 

Оцінка балів

  • Це чистий і простий Code Golf . Виграє найкоротше рішення в байтах .

Це моє перше запитання Code Golf. Вибачте, якщо я зробив щось не так, але я намагався якомога краще переконатись у відсутності неоднозначності та запобігти максимально можливим правилам закону. Якщо я був неоднозначним чи незрозумілим, будь ласка, не соромтесь задавати питання.


1
У вашому прикладі вхід / вихід не повинен 1 2 3 4повертатися 0 1?
Гаффі

1
І в прикладі тексту, чи не повинен "Зелений зелений зелений синій" давати і білий кілочок (для першого Зеленого)? EDIT - Вікіпедія пояснює, що білого кольору не потрібно давати, як ви писали. Але я думаю, що біло / чорні правила повинні бути чітко зазначені у питанні.
ugoren

Наскільки повільно буде дозволено працювати?
перестала повертати проти годинника,

@Gaffi - Абсолютно правильно - виправлено
lochok

1
Правила щодо білих кілочків тут не вказані. Припустимо, ви вибрали 1234, і я думаю, 5611. Обидва моїх 1 - це правильний колір у неправильному місці, тож із того, як ви заявили правила, я б сказав, що я отримую 2 білі. Але ні - у Вікіпедії сказано, що це 1 білий. Неправильний метод також простіше програмувати (але Стівен Румбальський правильно реалізував правила Вікіпедії).
ugoren

Відповіді:


8

Python 2 Python 3, 359 365 338 символів

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

Смішно, мені знадобилося багато редагувань, щоб зрозуміти, що я маю назву змінної п'яти символів.

Мені не подобається довгий імпорт. Складається враження, що я повинен бути в змозі здійснити заміну collections.Counter, щоб зберегти імпорт.

Мені теж не подобається print(*(m.pop()))в кінці. Створюється враження, що він повинен зникнути в циклі, але я не можу знайти спосіб зробити це, не зробивши його довше.


TypeError: join() takes exactly one argument (2 given)на return j(sum(min(g.count(c),k.count(c))for c in set(g))-b,b). також sum () повертає int, тоді як j (str.join) повинен брати ітерабельний
Blazer

Моя структура циклу позбавляється від фіналу print, і я думаю, що це трохи коротше. Він також краще відповідає запитуваній поведінці (зупиняючись на "4 0", а не тоді, коли ви знаєте відповідь). І len(m)>1== m[1:]. Імпорт справді дратує - from a,b import *було б добре.
ugoren

Ця програма, схоже, виходить, коли відчуває, що це правильно. одного разу я запустив його, і він зупинився на 5 здогадах, це було не правильно. наступного разу він зупинився на 4 здогадах, і це було правильно, але я ще навіть не ввів 4 0, що є об'єктивними критеріями, і в інший час він вийде за винятком:print(*(m.pop())) KeyError: 'pop from an empty set'
Blazer

@Blazer. Які тестові випадки спричинили цей результат?
Стівен Румбальський

@Blazer: 4 0це чотири білих кілочки. Я думаю, що ви змінили бал.
Стівен Румбальський

7

Хаскелл, 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

Я люблю писати суто функціональні інтерактивні програми! Але звичайно цей стиль має певні обмеження: він зараз закінчується помилкою, але ви не вказали, що це не нормально. Мені потрібно буде перефактурувати всю річ у IOмонаду, щоб отримати вихід без помилок.


Чи гарантує це правильна здогадка за 6 ходів?
ugoren

Ага. Я думав, що це (працює на прикладі ОП та інших рішень), але вичерпне тестування показує, що іноді потрібно 7 здогадок. Мені доведеться ще над цим працювати!
перестали повертати проти годинника,

5

Пітон, 385 357 символів, вирішує в 5 ходів

Чим більше я його змінюю, тим він стає все більше схожим на Стівена Румбальського ... Основна відмінність полягає в тому, що він працює з рядками, а не цілими числами.
Реалізовано алгоритм Кнута (зараз я сподіваюся правильно).
Запозичив бальну функцію від Стівена Румбальського.
Потрібно тривалий час, щоб генерувати першу здогадку, згодом стає краще.
Жорстке кодування його ( g=len(A)==1296 and [1,1,2,2] or ...) полегшує життя, якщо ви хочете перевірити його.
Я не рахую 4 нових рядків + пари вкладок, які можна замінити крапками з комою.

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)
гніблер

from collections import*
гніблер

a,b=map(int,raw_input())
гніблер

product(*[range(1,7)]*4)
гніблер

Counter(r(x,i)for i in A).values()
гніблер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.