首先,感谢您提出我的问题。关于这个问题,我一直在编写Prolog代码来模拟爱因斯坦之谜。我认为这是一个非常优雅的解决方案,它基本上是一个带有某些字段的元组列表,如房屋颜色、宠物、国籍等。我已经建模了列表,提示也在那里,但我在尝试建模这个问题时遇到了困难。
问题是,我不想只停留在一个简单的问题上;谁拥有鱼&";。我想模拟一个更难的问题。例如:";住在红色房子右侧的房子里的人拥有什么宠物&";。这似乎是对列表中索引i
的简单检查,该列表中有颜色为red
的元组,并返回列表中索引为i+1
的元组的字段pet
,但我使用Prolog的经验非常有限(这实际上是我第一次使用它(,我真的不确定如何实现它。我将提供下面的代码。我感谢所有的回答。非常感谢。
persoane(0, []) :- ! .
persoane(N, [(_Men, _Color, _Drink, _Smoke, _Animal)|T]) :- N1 is N-1, persoane(N1,T) .
persoana(1, [H|_], H) :- ! .
persoana(N, [_|T], R) :- N1 is N-1, persoana(N1, T, R)
% Function that tests if A is to the right of B (will be used in the final question)
right(A, B, List) :- nextto(B, A, List).
% The Brit lives in the red house
hint1([(brit, red, _, _, _)|_]) .
hint1([_|T]) :- hint1(T) .
% The Swede keeps dogs as pets
hint2([(swede, _, _, _, dog)|_]) .
hint2([_|T]) :- hint2(T) .
% The Dane drinks tea
hint3([(dane, _, tea, _, _)|_]) .
hint3([_|T]) :- hint3(T) .
% The green house is on the left of the white house
hint4([(_, green, _, _, _,),(_, white, _, _, _)|_]) .
hint4([_|T]) :- hint4(T) .
% The green house owner drinks coffee
hint5([(_, green, cofee, _, _)|_]) .
hint5([_|T]) :- hint5(T) .
% The person who smokes Pall Mall rears birds
hint6([(_, _, _, pallmall, bird)|_]) .
hint6([_|T]) :- hint6(T) .
% The owner of the yellow house smokes Dunhill
hint7([(_, yellow, _, dunhill, _)|_]) .
hint7([_|T]) :- hint7(T) .
% The man living in the center house drinks milk
hint8(persoane) :- persoana(3, persoane, (_, _, milk, _, _)) .
% The Norwegian lives in the first house
hint9(persoane) :- persoana(1, persoane, (norwegian, _, _, _, _)) .
% The man who smokes Blends lives next to the one who keeps cats
hint10([(_, _, _, blend, _),(_, _, _, _, cat)|_]) .
hint10([(_, _, _, _, cat),(_, _, _, blend, _)|_]) .
hint10([_|T]) :- hint10(T) .
% The man who keeps horses lives next to the man who smokes Dunhill
hint11([(_, _, _, dunhill, _),(_, _, _, _, horse)|_]) .
hint11([(_, _, _, _, horse),(_, _, _, dunhill, _)|_]) .
hint11([_|T]) :- hint11(T) .
% The owner who smokes BlueMaster drinks beer
hint12([(_, _, beer, bluemaster, _)|_]) .
hint12([_|T]) :- hint12(T) .
% The German smokes Prince
hint13([(german, _, _, prince, _)|_]) .
hint13([_|T]) :- hint13(T) .
% The Norwegian lives next to the blue house
hint14([(norwegian, _, _, _, _),(_, blue, _, _, _)|_]) .
hint14([(_, blue, _, _, _),(norwegian, _, _, _, _)|_]) .
hint14([_|T]) :- hint14(T) .
% The man who smokes Blend has a neighbour who drinks water
hint15([(_, _, _, blend, _),(_, _, water, _, _)|_]) .
hint15([(_, _, water, _, _),(_, _, _, blend, _)|_]) .
hint15([_|T]) :- hint15(T) .
% The question: What pet does the man who lives to the right of the red house have ?
% question (right((_, _, _, _, _), (_, red, _, _, _), persoane)) .
question([(_, red, _, _, _),()])
question([_|T]) :- question(T) .
solution(persoane) :-
persoana(5, persoane),
hint1(persoane),
hint2(persoane),
hint3(persoane),
hint4(persoane),
hint5(persoane),
hint6(persoane),
hint7(persoane),
hint8(persoane),
hint9(persoane),
hint10(persoane),
hint11(persoane),
hint12(persoane),
hint13(persoane),
hint14(persoane),
hint15(persoane),
question(persoane) .
您可以定位访问如下列表:
index(one, [One, _, _, _, _], One).
index(two, [_, Two, _, _, _], Two).
index(three, [_, _, Three, _, _], Three).
index(four, [_, _, _, Four, _], Four).
index(five(, [_, _, _, _, Five], Five).
您也可以用类似的方式定义next_to
:
next_to(List, A, B) :- left_right(List, A, B).
next_to(List, A, B) :- right_left(List, A, B).
right_left(List, A, B) :- left_right(List, B, A).
left_right([A,B,_,_,_], A,B).
left_right([_,A,B,_,_], A,B).
left_right([_,_,A,B,_], A,B).
left_right([_,_,_,A,B], A,B).
有更通用的解决方案适用于任何长度的列表(作为练习留下(。
我们可以用自上而下的风格对其进行编码。这意味着使用一些虚构的谓词,然后根据我们刚刚使用它们的方式来实现它们:
puzzle( P, Pet ) :- length( P, _ ),
clue( P, [house-red , nation-brit ] ), % (* 1. The Brit lives in red house *)
clue( P, [keeps-dogs, nation-swede] ), % (* 2. The Swede has dogs as pets *)
clue( P, [drinks-tea, nation-dane ] ), % (* 3. ..... *)
clue( P, left_of, [[house -red ], [house -white ]] ), % (* 4. ..... *)
clue( P, [house-green, drinks-coffee ] ), % (* ....... *)
clue( P, [keeps-birds, smokes-pallmall] ),
clue( P, [house-yellow, smokes-dunhill ] ),
clue( P, center, [[drinks-milk ] ] ),
clue( P, first, [[nation-norse ] ] ),
clue( P, next_to, [[smokes-blends], [keeps -cats ]] ),
clue( P, next_to, [[keeps -horses], [smokes-dunhill]] ),
clue( P, [smokes-bluemaster, drinks-beer ] ),
clue( P, [nation-german , smokes-prince] ),
clue( P, next_to, [[nation-norse ], [house -blue ]] ),
clue( P, next_to, [[smokes-blends], [drinks-water ]] ),
%% (* Who has the zebra ? *)
clue( P, [keeps-zebra, nation- _Who] ),
%% (* What pet the man owns who lives to the right of the red house? *)
clue( P, right_of, [[keeps-Pet ], [house -red ]] ),
maplist( length, P, _ ).
clue( P, AS ) :- member( H, P ), attrs( H, AS ).
clue( P, C, ASs ) :- G =.. [ C, P | ASs], G.
left_of( P, AS1, AS2 ) :- append( _, [H1, H2 | _], P ),
attrs( H1, AS1 ),
attrs( H2, AS2 ).
next_to( P, AS1, AS2 ) :- left_of( P, AS1, AS2 ) ; right_of( P, AS1, AS2 ).
right_of( P, AS1, AS2 ) :- left_of( P, AS2, AS1 ).
center( P, AS ) :- middle( P, H ), attrs( H , AS ).
first( [H | _], AS ) :- attrs( H , AS ).
middle( [H ], H ).
middle( [_ | R], H ) :- append( X, [_], R ), middle( X, H ).
剩下的就是定义attrs/2
,实现各种可扩展记录,并将它们用作基本的对象系统;学习";关于所涉及的对象(此处为人(的属性,仅从的使用开始——而不是人类程序员通过先验地在程序中固定所述对象的特定表示(例如5元组等(来灌输他们的理解。
最终目标CCD_;冻结";那些可扩展记录(为了简单起见,实现为开放式列表(,方法是将[]
放入它们的哨兵中(例如,尝试X = [1, 2 | _], length( X, _ )
来查看它的作用(。
目标length( P, _ )
在一开始就提供了迭代深化方法。不幸的是,如果没有它,谓词就会循环。
对于漂亮的打印输出,我们可以通过运行它
test :- puzzle( P, Pet ),
maplist( sort, P, PS ), maplist( writeln, PS ), nl,
writeln( Pet ).
产生输出(手动校准(
62 ?- test, !.
[drinks-water, house-yellow,keeps-cats, nation-norse, smokes-dunhill ]
[drinks-tea, house-blue, keeps-horses,nation-dane, smokes-blends ]
[drinks-milk, house-red, keeps-birds, nation-brit, smokes-pallmall ]
[drinks-beer, house-white, keeps-dogs, nation-swede, smokes-bluemaster]
[drinks-coffee,house-green, keeps-zebra, nation-german,smokes-prince ]
dogs
true.