prolog - 解决 Prolog 中的文本逻辑难题 - 查找生日和月份

标签 prolog prolog-dif zebra-puzzle

我正在阅读“7 天 7 种语言”一书,并已读到序言章节。作为学习练习,我正在尝试解决一些文本逻辑难题。谜题如下:

五姐妹的生日都在不同的月份和一周中的不同日子。使用下面的线索,确定每个姐妹生日的月份和星期几。

  1. Paula 出生于三月,但不是星期六。阿比盖尔的生日不是星期五或星期三。
  2. 生日在星期一的女孩比布伦达和玛丽早出生。
  3. 塔拉不是二月出生的,她的生日是在周末。
  4. Mary 不是十二月出生的,她的生日也不是工作日。六月生日的女孩在星期天出生。
  5. Tara 比 Brenda 早出生,而 Brenda 的生日不是星期五。玛丽不是七月出生的。

对于有经验的 Prolog 程序员来说,我当前的实现可能看起来像个笑话。代码贴在下面。

我希望就如何解决问题以及如何使代码既清晰又紧凑提供一些意见。

即:

  1. 我怎样才能避免输入“日期必须是唯一的”限制。
  2. 如何避免输入月份必须唯一的限制。
  3. 添加生日顺序限制。
is_day(Day) :-
    member(Day, [sunday, monday, wednesday, friday, saturday]).

is_month(Month) :-
    member(Month, [february, march, june, july, december]).

solve(S) :-

    S = [[Name1, Month1, Day1],
         [Name2, Month2, Day2],
         [Name3, Month3, Day3],
         [Name4, Month4, Day4],
         [Name5, Month5, Day5]],

    % Five girls; Abigail, Brenda, Mary, Paula, Tara    
    Name1 = abigail,
    Name2 = brenda,
    Name3 = mary,
    Name4 = paula,
    Name5 = tara,

    is_day(Day1), is_day(Day2), is_day(Day3), is_day(Day4), is_day(Day5),
    Day1 \== Day2, Day1 \== Day3, Day1 \== Day4, Day1 \== Day5,
    Day2 \== Day1, Day2 \== Day3, Day2 \== Day4, Day2 \== Day5,
    Day3 \== Day1, Day3 \== Day2, Day3 \== Day4, Day3 \== Day5,
    Day4 \== Day1, Day4 \== Day2, Day4 \== Day3, Day4 \== Day5,

    is_month(Month1), is_month(Month2), is_month(Month3), is_month(Month4), is_month(Month5),
    Month1 \== Month2, Month1 \== Month3, Month1 \== Month4, Month1 \== Month5,
    Month2 \== Month1, Month2 \== Month3, Month2 \== Month4, Month2 \== Month5,
    Month3 \== Month1, Month3 \== Month2, Month3 \== Month4, Month3 \== Month5,
    Month4 \== Month1, Month4 \== Month2, Month4 \== Month3, Month4 \== Month5,

    % Paula was born in March but not on Saturday.  
    member([paula, march, _], S),
    Day4 \== sunday,

    % Abigail's birthday was not on Friday or Wednesday.    
    Day1 \== friday,
    Day1 \== wednesday,

    % The girl whose birthday is on Monday was born
    % earlier in the year than Brenda and Mary.

    % Tara wasn't born in February, and 
    % her birthday was on the weekend.
    Month5 \== february,
    Day5 \== monday, Day5 \== wednesday, Day5 \== friday,   

    % Mary was not born in December nor was her
    % birthday on a weekday.
    Month3 \== december,
    Day3 \== monday, Day3 \== wednesday, Day3 \== friday,

    % The girl whose birthday was in June was 
    % born on Sunday.
    member([_, june, sunday], S),

    % Tara was born before Brenda, whose birthday
    % wasn't on Friday.
    Day2 \== friday,

    % Mary wasn't born in July.
    Month3 \== july.

更新 根据 chac 的回答,我解决了这个难题。按照相同的方法,我们(工作中的编程语言能力小组)也能够解决第二个难题。我已经发布了 complemete implementation, and example output as a gist on GitHub .

最佳答案

使用 maplist/2 将大大缩短您的代码。例如:

maplist(is_month, [Month1,Month2,Month3,Month4,Month5]).

month/1 可能是比 is_month/1 更好的谓词名称。要声明两个项不同,请使用约束 dif/2。使用 maplist/2 和 dif/2,您可以描述一个列表包含成对不同的元素:

all_dif([]).
all_dif([L|Ls]) :-
        maplist(dif(L), Ls),
        all_dif(Ls).

例子:

?- all_dif([X,Y,Z]).
dif(X, Z),
dif(X, Y),
dif(Y, Z).

solve/1 是命令式名称 - 您正在描述解决方案,因此最好将其称为 solution/1。

关于prolog - 解决 Prolog 中的文本逻辑难题 - 查找生日和月份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12253974/

相关文章:

prolog - 这个序言输出想表达什么?

list - `var(A)` 和执行顺序

Prolog - 功能术语与谓词

prolog - 如何在prolog中追踪clpfd的回溯?

prolog - Prolog 规则中目标(语句)的顺序

list - 在Prolog中不统一删除列表的所有成员

Prolog 和逻辑难题

Prolog 房间邻接难题

prolog - 爱因斯坦之谜与术语列表

prolog - 为什么SWI-Prolog只给出一种解决方案?