问题描述
我正在阅读"7天之内的7种语言"一书,并且已经读到Prolog章节.作为学习练习,我试图解决一些文本逻辑难题.难题如下:
I'm reading the "7 Languages in 7 Days"-book, and have reached the Prolog chapter. As a learning exercises I'm trying to solve some textual logic puzzles. The puzzle goes as follow:
五个姐妹的生日分别在不同的月份和每个星期的不同日期.使用以下线索,确定每个姐姐的生日是几月几号.
- 宝拉(Paula)于三月出生,但不在星期六出生.阿比盖尔的生日不是星期五或星期三.
- 生日在星期一的那个女孩比布伦达和玛丽早得多.
- Tara不是2月份出生,生日是在周末.
- 玛丽既不是12月出生的,也不是平日的生日.六月份生日的女孩是星期天出生的.
- 塔拉(Tara)在布伦达(Brenda)之前出生,布伦达的生日不在星期五.玛丽不是7月份出生的.
对于经验丰富的Prolog程序员,我当前的实现可能看起来像是在开玩笑.该代码粘贴在下面.
My current implementation probably looks like a joke to experienced Prolog programmers. The code is pasted below.
我很乐意就如何解决问题以及如何使代码既清晰又密集的问题提供一些建议.
I would love some input on how to solve the question, and how to make the code both clear and dense.
即:
- 如何避免写出限制,即天数必须是唯一的".
- 如何避免输入限制,指出月份必须是唯一的.
- 添加有关生日排序的限制.
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的回答,我能够解决难题.遵循相同的配方,我们(正在工作的编程语言能力小组)也能够解决第二个难题.我已经发布了完整的实现,并将示例输出作为要点在GitHub上.
Update Based on the answer from chac I was able to solve the puzzle. Following the same recipe we (the programming language competency group at work) was able to solve a second puzzle as well. I have posted the complemete implementation, and example output as a gist on GitHub.
推荐答案
也许谜题未指定,或者您的解决方案未完成:测试您的代码,我明白了
Maybe the riddle is underspecified, or your solution not complete: testing your code, I get
?- solve(X),maplist(writeln,X).
[abigail,february,monday]
[brenda,july,wednesday]
[mary,june,sunday]
[paula,march,friday]
[tara,december,saturday]
X = [[abigail, february, monday], [brenda, july, wednesday], [mary, june, sunday], [paula, march, friday], [tara, december, saturday]] ;
[abigail,february,monday]
[brenda,december,wednesday]
[mary,june,sunday]
[paula,march,friday]
[tara,july,saturday]
X = [[abigail, february, monday], [brenda, december, wednesday], [mary, june, sunday], [paula, march, friday], [tara, july, saturday]]
以及更多解决方案.那么布伦达是什么时候出生的?
and yet more solutions. So when is brenda born?
唯一性的交易技巧"是使用选择/3谓词,或简单地置换/2.最后使用的代码变成类似
A 'trick of the trade' for uniqueness is using select/3 predicate, or simply permutation/2. Using this last the code becomes something like
solve(S) :-
S = [[Name1, Month1, Day1],
[Name2, Month2, Day2],
[Name3, Month3, Day3],
[Name4, Month4, Day4],
[Name5, Month5, Day5]],
Girls = [abigail, brenda, mary, paula, tara],
Girls = [Name1, Name2, Name3, Name4, Name5],
Months = [february, march, june, july, december],
Days = [sunday, monday, wednesday, friday, saturday],
permutation(Months, [Month1, Month2, Month3, Month4, Month5]),
permutation(Days, [Day1, Day2, Day3, Day4, Day5]),
% Paula was born in March but not on Saturday.
member([paula, march, C1], S), C1 \= saturday,
...
关于一年中之前"的关系可以这样编码:
the relation about 'before in year' can be coded like this:
...
% The girl whose birthday is on Monday was born
% earlier in the year than Brenda and Mary.
member([_, C3, monday], S),
member([brenda, C4, C10], S), before_in_year(C3, C4, Months),
member([mary, C5, _], S), before_in_year(C3, C5, Months),
...
带有服务谓词
before_in_year(X, Y, Months) :-
nth1(Xi, Months, X),
nth1(Yi, Months, Y),
Xi < Yi.
周末出生"可以这样编码:
The 'born in weekend' can be coded like
...
% Tara wasn't born in February, and
% her birthday was on the weekend.
member([tara, C6, C7], S), C6 \= february, (C7 = saturday ; C7 = sunday),
% Mary was not born in December nor was her
% birthday on a weekday.
member([mary, C8, C9], S), C8 \= december, (C9 = saturday ; C9 = sunday),
...
,依此类推.重写之后,我得到了独特的解决方案
and so on. After this rewrite I get the unique solution
?- solve(X),maplist(writeln,X).
[abigail,february,monday]
[brenda,december,wednesday]
[mary,june,sunday]
[paula,march,friday]
[tara,july,saturday]
X = [[abigail, february, monday], [brenda, december, wednesday], [mary, june, sunday], [paula, march, friday], [tara, july, saturday]] ;
false.
修改
我刚刚注意到,我引入了一些冗余的member/2和自由变量,例如member([brenda, C4, C10], S),...
.那些C4,C10显然可以被绑定到Brenda的变量替换为原始代码中的Month2,Day2.
I've noted just now that I introduced some redundant member/2 and free variables, like member([brenda, C4, C10], S),...
. Those C4, C10 obiouvsly can be replaced by the variables bound to Brenda as Month2, Day2, as was in original code.
这篇关于解决Prolog中的文字逻辑难题-查找生日和月份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!