Проблема моделирования головоломки грабителя в Прологе - PullRequest
2 голосов
/ 28 апреля 2019

Я пытаюсь смоделировать эту простую логическую головоломку :

Только один из трех человек, Алиса, Бето и Карл украли деньги у мисс Даутфайр. Она нанимает вас в качестве детектива-консультанта. После опроса каждого из них у вас есть следующее:

Алиса: Не верь Карлу. Он лжет, и он взял деньги.

Карл: Бето лжет, но Алиса не взяла деньги.

Бето: Карл взял деньги. Я не взял деньги.

Собрав информацию, вы знаете, что всякий раз, когда один из них лжет, они лгали обе части своего утверждения. Кроме того, если один из них говорит правду, они говорят правду для обеих частей своего утверждения. Кто взял деньги?

Я смоделировал его так же, как это видео о рыцарях и рыцарях . В частности, я смоделировал это решение на основе «Пролога» около 11:34 вместо решения на основе SAT, представленного ранее. Я сделал некоторые изменения в отношении false.

says(guilty_liar, S) :- not(S).
says(innocent_liar, S) :- not(S).
says(guilty_but_honest, S) :- S.
says(innocent_and_honest, S) :- S.

false(A = guilty_liar) :- A = innocent_and_honest.
false(A = guilty_but_honest) :- A = innocent_liar.
false(A = innocent_liar) :- A = guilty_but_honest.
false(A = innocent_and_honest) :- A = guilty_liar.
false((P ; Q)) :- false(P), false(Q) .
false((P , Q)) :- ( false(P) ; false(Q) ).

Тогда я бы сделал следующие запросы:

?- [burglar].
  true.

?- says(A, (C = guilty_liar)), says(C, ((B = guilty_liar ; B = innocent_liar), (A = innocent_liar ; A = innocent_and_honest ))), says(B, ((C = guilty_liar ; C = guilty_but_honest) , (B = innocent_and_honest ; B = innocent_liar))).
    A = guilty_but_honest,
    C = B, B = guilty_liar ;
    A = guilty_but_honest,
    C = guilty_liar,
    B = innocent_and_honest ;
  false.

Хотя я ожидал бы большего, чем правильное решение (поскольку я не установил все ограничения), я бы ожидал, что появится правильное решение; а именно, Алиса невинна, но лжет, Карл говорит правду, а Бето - виновный лжец.

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

says(A, (C = guilty_liar)),
says(C, ((B = guilty_liar ; B = innocent_liar), (A = innocent_liar ; A = innocent_and_honest ))),
says(B, ((C = guilty_liar ; C = guilty_but_honest) , (B = innocent_and_honest ; B = innocent_liar))).

Я запутался, почему не появляется правильное решение.


UPDATE

Я тупо использовал not вместо функции false, которую я определил, однако даже выключение not(S) с помощью false(S) дает просто false. для запроса.

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

Это выглядит очень подозрительно для меня: says(A, (C = guilty_liar)). Предполагается, что существует ограничение, что оба утверждения истинны или оба ложны, и здесь у вас есть только одно утверждение. Вы думаете, ваша логика справляется с этим правильно?

В любом случае, вот мое наивное решение :-) Создание переменной true / false для каждого предложения и выражение всех ограничений в термах этих переменных.

true_or_false(X) :- X = true.
true_or_false(X) :- X = false.

bool_to_int(true, 1).
bool_to_int(false, 0).

true_or_false_list([]).
true_or_false_list([V | T]) :- true_or_false(V), true_or_false_list(T).

solution(AliceCorrect, CarlCorrect, BetoCorrect,
         AliceThief, CarlThief, BetoThief) :-
  true_or_false_list([AliceCorrect, CarlCorrect, BetoCorrect,
                      AliceThief, CarlThief, BetoThief]),
  % Alice statement.
  AliceCorrect \= CarlCorrect,
  AliceCorrect = CarlThief,
  % Carl statement.
  CarlCorrect \= BetoCorrect,
  CarlCorrect \= AliceThief,
  % Beto Statement.
  BetoCorrect = CarlThief,
  BetoCorrect \= BetoThief,
  % There can be only one thief.
  bool_to_int(AliceThief, AliceThiefInt),
  bool_to_int(CarlThief, CarlThiefInt),
  bool_to_int(BetoThief, BetoThiefInt),
  1 is AliceThiefInt + CarlThiefInt + BetoThiefInt.

Бето - вор.

1 голос
/ 30 апреля 2019

Я сделал это так:

?- People = [alice(_, _), beto(_, _), carl(_, _)], alice(People), carl(People), beto(People), write(People), nl, fail.

alice(People) :-
    member(alice(honest, innocent), People),
    member(carl(liar, thief), People).

alice(People) :-
    member(alice(liar, _), People),
    member(carl(honest, innocent), People).

carl(People) :-
    member(carl(honest, _), People),
    member(beto(liar, _), People),
    member(alice(_, innocent), People).

carl(People) :-
    member(carl(liar, _), People),
    member(beto(honest, _), People),
    member(alice(_, thief), People).

beto(People) :-
    member(beto(honest, innocent), People),
    member(carl(_, thief), People).

beto(People) :-
    member(beto(liar, thief), People),
    member(carl(_, innocent), People).

Результат [alice(liar, innocent), beto(liar, thief), carl(honest, innocent)].


Это немного проще:

alice([alice(honest, innocent), beto(_, _), carl(liar, thief)]).        
alice([alice(liar, _), beto(_, _), carl(honest, innocent)]).
carl([alice(_, innocent), beto(liar, _), carl(honest, _)]).     
carl([alice(_, thief), beto(honest, _), carl(liar, _)]).
beto([alice(_, _), beto(honest, innocent), carl(_, thief)]).
beto([alice(_, _), beto(liar, thief), carl(_, innocent)]).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...