四、谁是凶手
下面看一个比较有趣的逻辑题。
Boddy 先生死于谋杀,现有六个嫌疑犯,每个人在不同的房间,每间房间各有一件可能的凶器,但不知道嫌疑犯、房间、凶器的对应关系。请根据下面的条件和线索,找出谁是凶手。
已知条件:六个嫌疑犯是三男(George、John、Robert)三女(Barbara、Christine、Yolanda)。
代码语言:javascript复制man(george). man(john). man(robert).
woman(barbara). woman(christine). woman(yolanda).
为了后面解题的方便,需要把"男人"和"女人"都定义为"人"。
代码语言:javascript复制
person(X):- man(X).
person(X):- woman(X).
六个嫌疑犯分别待在六个房间:浴室(Bathroom)、饭厅(Dining Room)、厨房(Kitchen)、起居室(Living Room)、 储藏室(Pantry)、书房(Study)。每间房间都有一件可疑的物品,可以当作凶器:包(Bag)、火枪(Firearm)、煤气(Gas)、刀(Knife)、毒药(Poison)、绳索(Rope)。
代码语言:javascript复制
location(bathroom). location(dining). location(kitchen).
location(livingroom). location(pantry). location(study).
weapon(bag). weapon(firearm). weapon(gas).
weapon(knife). weapon(poison). weapon(rope).
下面声明一条规则,每个房间的人都是不一样的。
代码语言:javascript复制
uniq_ppl(A,B,C,D,E,F):-
person(A), person(B), person(C),
person(D), person(E), person(F),
A=B, A=C, A=D, A=E, A=F,
B=C, B=D, B=E, B=F,
C=D, C=E, C=F,
D=E, D=F,
E=F.
然后,定义一个表达式murderer(X)
,变量X
就是凶手。该表达式只有满足以下所有条件,才可能为true
。
代码语言:javascript复制
murderer(X) :-
uniq_ppl(Bathroom, Dining, Kitchen, Livingroom, Pantry, Study),
uniq_ppl(Bag, Firearm, Gas, Knife, Poison, Rope),
注意,上面代码中Bathroom
和Bag
这样的字符串,都是大写字母开头,所以都是变量,代表对应的人。至于具体是谁,就要通过推理得到。
线索一:厨房里面是一个男人,那里的凶器不是绳索、刀子、包和火枪。
代码语言:javascript复制
man(Kitchen),
Kitchen=Rope, Kitchen=Knife, Kitchen=Bag, Kitchen=Firearm,
线索二:Barbara 和 Yolanda 在浴室和书房。
代码语言:javascript复制
woman(Bathroom), woman(Study),
christine=Bathroom, christine=Study,
barbara=Dining, barbara=Kitchen,
barbara=Livingroom, barbara=Pantry,
yolanda=Dining, yolanda=Kitchen,
yolanda=Livingroom, yolanda=Pantry,
线索三:带包的那个人不是 Barbara 和 George,也不在浴室和饭厅。
代码语言:javascript复制
barbara=Bag, george=Bag,
Bag=Bathroom, Bag=Dining,
线索四:书房里面是一个带绳子的女人。
代码语言:javascript复制
woman(Rope), Rope=Study,
线索五:起居室里面那件凶器,与 John 或 George 在一起。
代码语言:javascript复制
man(Livingroom), Livingroom=robert,
线索六:刀子不在饭厅。
代码语言:javascript复制
Knife=Dining,
线索七:书房和食品储藏室里面的凶器,没跟 Yolanda 在一起。
代码语言:javascript复制
yolanda=Pantry, yolanda=Study,
线索八:George 所在的那间屋子有火枪。
代码语言:javascript复制
Firearm=george,
线索九:Boddy 先生死在食品储藏室里,那里的凶器是煤气。
代码语言:javascript复制
Pantry=Gas, Pantry=X, Gas=X,
线索就是上面这些,然后把写好的所有表达式放在一起,组成一个完整的脚本crime.pl
,代码看这里。
加载这个脚本,执行murderer(X)
函数,由于条件复杂,运算时间较长,最终会显示凶手是谁。
代码语言:javascript复制
?- [crime].
true.
?- murderer(X).
KILLER IS :christine
Bathroom: yolanda
Dining: george
Livingroom: john
Pantry: christine
Study: barbara
Kitchen: robert
Knife: yolanda
Gas: christine
Rope: barbara
Bag: john
Poison: robert
Firearm: george
X = christine ;