Пролог: каждый игрок в игре играет карту. Имея частичное представление о том, кто какие карты разыграл, сделайте вывод, кто разыгрывал остальные

Я пытаюсь использовать Пролог для решения простой игры, в которой есть 3 игрока: Алиса, Боб и Чарли. Каждый игрок тайно выбирает карту для игры, причем карты могут быть красными или синими. Затем карты перемешиваются и переворачиваются.

Принимая точку зрения Алисы, мы знаем, какую карту она сыграла. Следовательно, если открытые карты синие, синие и красные, а Алиса играла красными, то она может сделать вывод, что и Боб, и Чарли играли синими. Я изо всех сил пытаюсь определить соответствующие причины для этого. Вот мои основные факты:

player(alice).
player(bob).
player(charlie).

color(blue).
color(red).

% The overturned cards -- all players can see these. Order is unimportant.
cards([blue, red, red]).

played(alice, blue).

Из этого мы должны сделать вывод, что Боб и Чарли играли красным. Я не знаю, как сообщить Прологу, что каждый из трех игроков сыграл ровно одну карту из факта cards([blue, red, red]). Или, может быть, что-то вроде num_cards(blue, 1), num_cards(red, 2) было бы лучше?

В качестве чуть более сложного примера можно использовать следующие факты для вывода о том, что Чарли сыграл красную карточку (например, если Алиса смогла посмотреть на карту, сыгранную Бобом):

player(alice).
player(bob).
player(charlie).

color(blue).
color(red).

% The overturned cards -- all players can see these. Order is unimportant.
cards([blue, red, red]).

played(alice, red).
played(bob, blue).

Самый похожий вопрос SO, который мне удалось найти, был этот, но я не был в состоянии применить это к моей проблеме. Библиотека CLPFD определенно кажется актуальной.


person Tim    schedule 26.04.2016    source источник


Ответы (2)


Уже за действительно хорошо сделанный фоновый поиск: +1! Вопрос, на который вы ссылались, и решение Бориса действительно тесно связаны с этой задачей.

Во-первых, я хотел бы отметить, что ваша задача выглядит легкой на первый взгляд и на первый взгляд выглядит подходящей для новичков в Прологе. На мой взгляд, такие задачи совсем непростые, и сложность быстро выходит из-под контроля, когда необходимо также представить дополнительные знания (например: кто знает что, по разным слоям). Я вполне могу себе представить, что новички, которые получают такие задачи в качестве заданий, быстро уходят с чувством «я мог бы легко решить это на Java, но это невозможно на Prolog». Тот факт, что они не смогли решить ее и на Java, обычно их ничуть не смущает.

В этом конкретном случае clpfd ограничения действительно отлично подходят. На самом деле ограничение global_cardinality/2, доступное, например, в SICStus Prolog, легко решает оба примера.

При использовании ограничений CLP(FD) хитрость заключается в том, чтобы сопоставить интересующий вас домен с целыми числами. В этом случае я буду (произвольно) использовать:

  • 1 для синего
  • 2 для красного.

Кроме того, я буду просто использовать переменные, по одной для каждого человека, обозначающие конкретную «карту» (то есть целое число), которую сыграл человек. Идея состоит в том, чтобы указать то, что мы знаем, и позволить решателю ограничений выяснить все остальное.

Итак, в первом случае имеем:

?- global_cardinality([Alice,Bob,Charlie], [1-1,2-2]),
   Alice = 1.
Alice = 1,
Bob = Charlie, Charlie = 2.

А во втором случае:

?- global_cardinality([Alice,Bob,Charlie], [1-1,2-2]),
   Alice = 2,
   Bob = 1.
Alice = Charlie, Charlie = 2,
Bob = 1.

Таким образом, в обоих случаях достаточно просто указать заданные ограничения, чтобы вывести единственное соответствующее решение, как вы и ожидали.

person mat    schedule 26.04.2016

моя подсказка нуждается в «синтаксической адаптации», чтобы соответствовать вашему вопросу: с моей точки зрения, важно отделить факты, выражающие конкретный запрос, от идентичностей сущностей: поэтому я предлагаю игру/2, оценивающую отношение между набор карт (конечно, перевернутых) и ассоциация игрока и сыгранной карты, выраженная как Player-Card:

player(alice).
player(bob).
player(charlie).

color(blue).
color(red).

game(Cs, [P-C|Ps]) :-
    player(P), color(C),
    select(C, Cs, Other),
    game(Other, Ps),
    \+ memberchk(P-_, Ps).
game([], []).

теперь можно ответить на множество конкретных вопросов. Например

game([blue, red, red], [alice-blue,bob-B,charlie-C]).
B = C, C = red ;
B = C, C = red ;
false.

or

?- so:game([blue, red, red], [alice-blue,X,Y]).
X = bob-red,
Y = charlie-red ;
...

or

?- game([blue, red, red], [alice-red, bob-blue, Y]).
Y = charlie-red ;
...

Чтобы избежать дублирования решений, можно использовать setof/3.

person CapelliC    schedule 27.04.2016