Решить Mastermind в 6 или менее ходов

24

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

Задний план

Mastermind - настольная игра. Цель игры состоит в том, чтобы точно угадать комбинацию (цвета и порядок) из 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

Правила расширены в Википедии

Требования

  • Программа должна читать из стандартного ввода и писать в стандартный вывод
  • Я буду использовать цифры для простоты вместо цветов. Комбинация для угадывания будет 4 числами от 1 до 6
  • Они должны вывести свои предположения в виде серии из 4 чисел, разделенных пробелами, от 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. Приношу свои извинения, если я сделал что-то не так, но я постарался как можно лучше убедиться, что нет абсолютно никакой двусмысленности, и предотвратить как можно больше правил, связанных с адвокатской деятельностью. Если я был неоднозначен или неясен, пожалуйста, не стесняйтесь задавать вопросы.

lochok
источник
1
В вашем примере ввод / вывод не должен 1 2 3 4возвращаться 0 1?
Гаффи
1
И в тексте примера не должен ли «Зеленый зеленый зеленый зеленый синий» давать также белый колышек (для первого зеленого)? РЕДАКТИРОВАТЬ - Википедия разъясняет, что не следует давать белый, как вы написали. Но я думаю, что белые / черные правила должны быть четко указаны в вопросе.
Угорен
Как медленно это будет разрешено работать?
перестал поворачивать против часовой стрелки
@Gaffi - Абсолютно верно - исправлено
lochok
1
Правила для белых колышков здесь не указаны. Предположим, вы выбрали 1234, а я, наверное, 5611. Обе мои цифры 1 - правильный цвет в неправильном месте, поэтому из того, как вы сформулировали правила, я бы сказал, что я получаю 2 белых. Но нет - Википедия говорит, что это 1 белый. Неправильный метод также легче программировать (но Стивен Румбальски правильно выполнил правила Википедии).
Угорен

Ответы:

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()))в конце. Такое ощущение, что он должен исчезнуть в цикле while, но я не могу найти способ сделать это, не увеличивая его.

Стивен Румбальский
источник
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 *было бы неплохо.
Угорен
эта программа, кажется, завершается всякий раз, когда чувствует, что это правильно. Однажды я запустил его, и он остановился на 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 ходов?
Угорен
Э - э. Я думал, что это так (работает для примера ОП и других решений), но исчерпывающее тестирование показывает, что иногда требуется 7 догадок. Я должен буду работать над этим еще!
перестал поворачивать против часовой стрелки
5

Питон, 385 357 символов, решает в 5 ходов

Чем больше я его изменяю, тем больше и больше он становится похож на Стивена Румбальски ... Главное отличие в том, что он работает со строками, а не с целыми числами.
Реализован алгоритм Кнута (надеюсь, теперь правильно).
Заимствовал функцию подсчета очков у Стивена Румбальски.
Требуется много времени, чтобы сгенерировать первое предположение, а потом поправиться.
Жесткое программирование it ( 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)]
ugoren
источник
"%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