使用 George F Luger (WorldCat) 的“人工智能 - 解决复杂问题的结构和策略”中的示例代码
adts
%%%
%%% This is one of the example programs from the textbook:
%%%
%%% Artificial Intelligence:
%%% Structures and strategies for complex problem solving
%%%
%%% by George F. Luger and William A. Stubblefield
%%%
%%% Corrections by Christopher E. Davis (chris2d@cs.unm.edu)
%%%
%%% These programs are copyrighted by Benjamin/Cummings Publishers.
%%%
%%% We offer them for use, free of charge, for educational purposes only.
%%%
%%% Disclaimer: These programs are provided with no warranty whatsoever as to
%%% their correctness, reliability, or any other property. We have written
%%% them for specific educational purposes, and have made no effort
%%% to produce commercial quality computer programs. Please do not expect
%%% more of them then we have intended.
%%%
%%% This code has been tested with SWI-Prolog (Multi-threaded, Version 5.2.13)
%%% and appears to function as intended.
%%%%%%%%%%%%%%%%%%%% stack operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These predicates give a simple, list based implementation of stacks
% empty stack generates/tests an empty stack
member(X,[X|_]).
member(X,[_|T]):-member(X,T).
empty_stack([]).
% member_stack tests if an element is a member of a stack
member_stack(E, S) :- member(E, S).
% stack performs the push, pop and peek operations
% to push an element onto the stack
% ?- stack(a, [b,c,d], S).
% S = [a,b,c,d]
% To pop an element from the stack
% ?- stack(Top, Rest, [a,b,c]).
% Top = a, Rest = [b,c]
% To peek at the top element on the stack
% ?- stack(Top, _, [a,b,c]).
% Top = a
stack(E, S, [E|S]).
%%%%%%%%%%%%%%%%%%%% queue operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These predicates give a simple, list based implementation of
% FIFO queues
% empty queue generates/tests an empty queue
empty_queue([]).
% member_queue tests if an element is a member of a queue
member_queue(E, S) :- member(E, S).
% add_to_queue adds a new element to the back of the queue
add_to_queue(E, [], [E]).
add_to_queue(E, [H|T], [H|Tnew]) :- add_to_queue(E, T, Tnew).
% remove_from_queue removes the next element from the queue
% Note that it can also be used to examine that element
% without removing it
remove_from_queue(E, [E|T], T).
append_queue(First, Second, Concatenation) :-
append(First, Second, Concatenation).
%%%%%%%%%%%%%%%%%%%% set operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These predicates give a simple,
% list based implementation of sets
% empty_set tests/generates an empty set.
empty_set([]).
member_set(E, S) :- member(E, S).
% add_to_set adds a new member to a set, allowing each element
% to appear only once
add_to_set(X, S, S) :- member(X, S), !.
add_to_set(X, S, [X|S]).
remove_from_set(_, [], []).
remove_from_set(E, [E|T], T) :- !.
remove_from_set(E, [H|T], [H|T_new]) :-
remove_from_set(E, T, T_new), !.
union([], S, S).
union([H|T], S, S_new) :-
union(T, S, S2),
add_to_set(H, S2, S_new).
intersection([], _, []).
intersection([H|T], S, [H|S_new]) :-
member_set(H, S),
intersection(T, S, S_new),!.
intersection([_|T], S, S_new) :-
intersection(T, S, S_new),!.
set_diff([], _, []).
set_diff([H|T], S, T_new) :-
member_set(H, S),
set_diff(T, S, T_new),!.
set_diff([H|T], S, [H|T_new]) :-
set_diff(T, S, T_new), !.
subset([], _).
subset([H|T], S) :-
member_set(H, S),
subset(T, S).
equal_set(S1, S2) :-
subset(S1, S2), subset(S2, S1).
%%%%%%%%%%%%%%%%%%%%%%% priority queue operations %%%%%%%%%%%%%%%%%%%
% These predicates provide a simple list based implementation
% of a priority queue.
% They assume a definition of precedes for the objects being handled
empty_sort_queue([]).
member_sort_queue(E, S) :- member(E, S).
insert_sort_queue(State, [], [State]).
insert_sort_queue(State, [H | T], [State, H | T]) :-
precedes(State, H).
insert_sort_queue(State, [H|T], [H | T_new]) :-
insert_sort_queue(State, T, T_new).
remove_sort_queue(First, [First|Rest], Rest).
planner
%%%%%%%%% Simple Prolog Planner %%%%%%%%
%%%
%%% This is one of the example programs from the textbook:
%%%
%%% Artificial Intelligence:
%%% Structures and strategies for complex problem solving
%%%
%%% by George F. Luger and William A. Stubblefield
%%%
%%% Corrections by Christopher E. Davis (chris2d@cs.unm.edu)
%%%
%%% These programs are copyrighted by Benjamin/Cummings Publishers.
%%%
%%% We offer them for use, free of charge, for educational purposes only.
%%%
%%% Disclaimer: These programs are provided with no warranty whatsoever as to
%%% their correctness, reliability, or any other property. We have written
%%% them for specific educational purposes, and have made no effort
%%% to produce commercial quality computer programs. Please do not expect
%%% more of them then we have intended.
%%%
%%% This code has been tested with SWI-Prolog (Multi-threaded, Version 5.2.13)
%%% and appears to function as intended.
:- [adts].
plan(State, Goal, _, Moves) :- equal_set(State, Goal),
write('moves are'), nl,
reverse_print_stack(Moves).
plan(State, Goal, Been_list, Moves) :-
move(Name, Preconditions, Actions),
conditions_met(Preconditions, State),
change_state(State, Actions, Child_state),
not(member_state(Child_state, Been_list)),
stack(Child_state, Been_list, New_been_list),
stack(Name, Moves, New_moves),
plan(Child_state, Goal, New_been_list, New_moves),!.
change_state(S, [], S).
change_state(S, [add(P)|T], S_new) :- change_state(S, T, S2),
add_to_set(P, S2, S_new), !.
change_state(S, [del(P)|T], S_new) :- change_state(S, T, S2),
remove_from_set(P, S2, S_new), !.
conditions_met(P, S) :- subset(P, S).
member_state(S, [H|_]) :- equal_set(S, H).
member_state(S, [_|T]) :- member_state(S, T).
reverse_print_stack(S) :- empty_stack(S).
reverse_print_stack(S) :- stack(E, Rest, S),
reverse_print_stack(Rest),
write(E), nl.
/* sample moves */
move(pickup(X), [handempty, clear(X), on(X, Y)],
[del(handempty), del(clear(X)), del(on(X, Y)),
add(clear(Y)), add(holding(X))]).
move(pickup(X), [handempty, clear(X), ontable(X)],
[del(handempty), del(clear(X)), del(ontable(X)),
add(holding(X))]).
move(putdown(X), [holding(X)],
[del(holding(X)), add(ontable(X)), add(clear(X)),
add(handempty)]).
move(stack(X, Y), [holding(X), clear(Y)],
[del(holding(X)), del(clear(Y)), add(handempty), add(on(X, Y)),
add(clear(X))]).
go(S, G) :- plan(S, G, [S], []).
test :- go([handempty, ontable(b), ontable(c), on(a, b), clear(c), clear(a)],
[handempty, ontable(c), on(a,b), on(b, c), clear(a)]).
大部分代码保持不变,解决您的问题所需的唯一更改是谓词move/3 和查询test。在添加谓词以解决您的问题之前,请从上述代码中注释掉或删除谓词 move/3 和 test/0。
下面是所有需要的新谓词move/3 和test/0。第一个move/3 已显示,其余部分需要显示(单击Reveal spoiler),以便您在需要时查看它们,但您应该尝试自己进行。
move(take_from_trunk(X), [hand(empty), trunk(X)],
[del(hand(empty)), del(trunk(X)),
add(hand(X)), add(trunk(empty))]).
该州跟踪四个位置,hand、ground、axle 和 trunk,以及三个值,flat、spare 和 empty。谓词move/3 也使用了变量,因此它们不能固定在它们可以做什么。
move/3 谓词有 3 个参数。
- 名称:答案中出现的内容,例如
take_from_trunk(spare)。
- 前提条件:
state 中必须存在的条件才能应用移动。
- 操作:如果应用了移动,则对状态所做的更改。这些代替了您的
assert 和retract。更改非常简单,您删除状态的一些属性,例如del(hand(empty)) 并添加一些,例如add(hand(X))。对于您给定的问题,此解决方案很简单,因为对于每个更改,每个del 都有一个匹配的add。
查询:
test :- go([hand(empty), trunk(spare), axle(flat), ground(empty)],
[hand(empty), trunk(flat), axle(spare), ground(empty)]).
示例运行:
?- test.
moves are
take_from_trunk(spare)
place_on_ground(spare)
take_off_axle(flat)
place_in_trunk(flat)
pickup_from_ground(spare)
place_on_axle(spare)
true.
需要其他move/3 谓词。尝试自己做。
移动(起飞轴(X),[手(空),轴(X)],
[del(hand(empty)), del(axle(X)),
添加(手(X)),添加(车轴(空))])。
移动(place_on_ground(X),[手(X),地面(空)],
[del(hand(X)), del(ground(empty)),
添加(手(空)),添加(地面(X))])。
移动(pickup_from_ground(X),[手(空),地面(X)],
[del(hand(empty)), del(ground(X)),
添加(手(X)),添加(地面(空))])。
移动(放置轴(X),[手(X),轴(空)],
[德尔(手(X)),德尔(车轴(空)),
添加(手(空)),添加(轴(X))])。
移动(放置_in_trunk(X),[手(X),树干(空)],
[del(hand(X)), del(trunk(empty)),
添加(手(空)),添加(树干(X))])。
在编写这些谓词时,一些move/3 没有按我的预期工作,所以我为每个谓词创建了简单的测试查询来检查它们。
使用测试还帮助我更改了 state 中的内容及其表示方式,例如,将 handempty 和 holding(X) 改为 hand(empty) 和 hand(X),这更容易理解,遵循并检查代码的一致性,但很可能使代码效率低下。
test_01 :- go([hand(empty), trunk(spare), axle(flat), ground(empty)],
[hand(spare), trunk(empty), axle(flat), ground(empty)]).
test_02 :- go([hand(empty), trunk(spare), axle(flat), ground(empty)],
[hand(flat), trunk(spare), axle(empty), ground(empty)]).
test_03 :- go([hand(flat), trunk(spare), axle(empty), ground(empty)],
[hand(empty), trunk(spare), axle(empty), ground(flat)]).
test_04 :- go([hand(empty), trunk(spare), axle(empty), ground(flat)],
[hand(flat), trunk(spare), axle(empty), ground(empty)]).
test_05 :- go([hand(spare), trunk(empty), axle(empty), ground(flat)],
[hand(empty), trunk(empty), axle(spare), ground(flat)]).
test_06 :- go([hand(flat), trunk(empty), axle(spare), ground(empty)],
[hand(empty), trunk(flat), axle(spare), ground(empty)]).
其中一些测试只使用一个招式即可按预期工作,而其他测试则返回许多招式。我没有在此处修改move/3,因此只考虑了一个move/3,但如果您愿意,可以对其进行修改。想想guard 语句或约束。
此处列出测试结果的另一个原因是表明某些动作不是按照您的想法选择的,或者没有按照您的预期进行操作,但是对已发布的查询的查询问题按预期工作。因此,如果您编写测试用例并且它们返回类似的内容,请不要假设您的 move/3 无效或有错误,它们可能不会。当您获得所有 move/3 和最终查询按预期工作时,然后返回并尝试了解为什么会发生这些多个移动,然后根据需要修改它们。
?- test_01.
moves are
take_from_trunk(spare)
true.
?- test_02.
moves are
take_from_trunk(spare)
place_on_ground(spare)
take_off_axle(flat)
place_in_trunk(flat)
pickup_from_ground(spare)
place_on_axle(spare)
take_from_trunk(flat)
place_on_ground(flat)
take_off_axle(spare)
place_in_trunk(spare)
pickup_from_ground(flat)
true.
?- test_03.
moves are
place_on_ground(flat)
true.
?- test_04.
moves are
take_from_trunk(spare)
place_on_axle(spare)
pickup_from_ground(flat)
place_in_trunk(flat)
take_off_axle(spare)
place_on_ground(spare)
take_from_trunk(flat)
place_on_axle(flat)
pickup_from_ground(spare)
place_in_trunk(spare)
take_off_axle(flat)
true.
?- test_05.
moves are
place_on_axle(spare)
true.
?- test_06.
moves are
place_on_ground(flat)
take_off_axle(spare)
place_in_trunk(spare)
pickup_from_ground(flat)
place_on_axle(flat)
take_from_trunk(spare)
place_on_ground(spare)
take_off_axle(flat)
place_in_trunk(flat)
pickup_from_ground(spare)
place_on_axle(spare)
true.