% File: /u3/pec/project/strips % Author: Peter Clark % Date: 1 May 1985 % Purpose: STRIPS revised 16 May 1985 for EMAS :- op(80 ,xfy,'<>'). :- op(90 ,xfy,and). :- op(100,xfy,[':',then,add]). :- op(100, fy,[want,if,delete]). watch :- retract(nowatching), assert(watching). nowatch :- retract(watching), assert(nowatching). nowatching. % go/0 : the top level. Enter the initial and desired world states, format as % follows.... % eg. initial a final a % b b % c d d % ------- --- % Format is [floor,c,b,a,floor,d]. [floor,d,b,a]. % % (Note not all the blocks have to be specified in the final state). go:- prompt(_,'Initial state: '), read(Initial), convert(Initial, World), nl, draw(World), prompt(_,'Desired state: '), read(Desired), convert(Desired, Goals), nl, draw(Goals), !, solve(Goals,true,0,World,NewWorld,[],Answer), pretty_write(Answer). % solve/7 : (goals to be solved, goals already solved and to be protected, % level of recursion,initial world state, final world state, % solution up to now, final solution). % : The top level of the planner. solve(_,_,Level,_,_,_,_) :- Level > 30, write('Got stuck in a loop!'), nl, abort. solve(Goal and Goals,Prot,Level,World,NewWorld,SoFar,Ans) :- !, solve(Goal,Prot,Level,World,MidWorld,SoFar,NewSoFar), solve(Goals,Goal and Prot,Level,MidWorld,NewWorld,NewSoFar,Ans). solve(Goal,_,Level,World,World,SoFar,SoFar) :- contained_in(Goal,World), ( watching, tab(Level), write(Goal), write(' is true already.'), nl ; nowatching ). % Prevent achieving an already true clause by making it false then making % it true again. NB a cut in the above clause doesn't work as there may % be more than one solution for contained_in. solve(Goal,_,_,World,_,_,_) :- contained_in(Goal,World), !, fail. solve(Goal,Prot,Level,World,NewWorld,SoFar,[Name|NewSoFar]) :- find_action(Goal,Action), Action = Name : if PCs then delete Dels add Adds, ( watching, tab(Level), write('To solve '), write(Goal), write(' try action '), write(N), write(' with preconditions '), write(PCs), nl ; nowatching ), NewLevel is Level+3, solve(PCs,Prot,NewLevel,World,MidWorld,SoFar,NewSoFar), preserves(Dels,Prot), do_action(Action,MidWorld,NewWorld). solve(Goal,_,Level,_,_,_,_) :- watching, tab(Level), write('Failed to solve '), write(Goal), nl, !, fail. % find_action/2 : (goal to be solved, action which will achieve it) find_action(A<>B,_) :- !, fail. find_action(Goal,Action) :- Action = Name : if PCs then delete Dels add Adds, clause(Action,true), contained_in(Goal,Adds). do_action(Action,World,NewWorld) :- Action = Name : if PCs then delete Dels add Adds, do_delete(Dels,World,MidWorld), do_add(Adds,MidWorld,NewWorld), ( watching, write('doing action '), write(Action), nl, draw(NewWorld) ; nowatching ). do_action(Action,World,_) :- (watching, write('retracting action '), write(Action), nl, draw(World) ; nowatching ), !, fail. do_delete(Del and Dels,World,NewWorld) :- !, do_delete(Del,World,MidWorld), do_delete(Dels,MidWorld,NewWorld). % do_delete(any(Fact)....) : delete any occurances of Fact do_delete(any(Fact),World,NewWorld) :- copy(Fact,SameFact), do_delete(Fact and any(SameFact),World,NewWorld), !. do_delete(any(_),World,World) :- !. do_delete(A<>B,World,World) :- !. do_delete(Del,Del and World,World) :- !. % item is at start do_delete(Del,State and Del,State) :- !. % item is at end do_delete(Del,State and World,State and NewWorld) :- do_delete(Del,World,NewWorld). % item is in middle do_add(Add and Adds,World,NewWorld) :- !, do_add(Add,World,MidWorld), do_add(Adds,MidWorld,NewWorld). do_add(A<>B,World,World) :- !. do_add(Add,World,Add and World). % copy/2 : copies the fact WITHOUT unifying the variable arguments copy(Fact,Copy) :- Fact=..FactList, copy_list(FactList,CopyList), Copy=..CopyList. copy_list([],[]). copy_list([A|B],[C|D]) :- var(A), !, copy_list(B,D). copy_list([A|B],[A|D]) :- copy_list(B,D). contained_in(not(Fact),World) :- contained_in(Fact,World), !, fail. contained_in(not(_),World). contained_in(A<>B,_) :- !, not(A=B). contained_in(Goal,Goal and Rest). contained_in(Goal,State and Rest) :- contained_in(Goal,Rest). contained_in(Goal,Goal). % preserves/2 : items about to be deleted, items which must not be deleted preserves(Del and Dels,Prots) :- !, preserves(Del,Prots), preserves(Dels,Prots). preserves(Del,Prots) :- not(contained_in(Del,Prots)). % convert/2 : input format, relational format. Converts [floor,a,b] to % 'on(a,floor) and on(b,a) and clear(b)' for example convert([floor,Block|Rest],on(Block,floor) and Rest2) :- !, convert([Block|Rest],Rest2). convert([Block,floor|Rest],clear(Block) and Rest2) :- !, convert([floor|Rest],Rest2). convert([Block1,Block2|Rest],on(Block2,Block1) and Rest2) :- convert([Block2|Rest],Rest2). convert([Block],clear(Block)). % Function for drawing the current world state : draw(World) :- contained_in(on(X,floor),World), write('| '), write(X), write(' '), draw_tower(X,World). draw(_) :- nl. draw_tower(X,World) :- contained_in(on(Y,X),World), !, write(Y), write(' '), draw_tower(Y,World). draw_tower(X,World) :- not(contained_in(clear(X),World)), write('Error! Top of tower not clear!'). draw_tower(_,_) :- nl, fail. % pretty_write/1 : Answer. Displays the answer nicely. pretty_write([]). pretty_write([Name|Rest]) :- pretty_write(Rest), write(Name), nl. % List the three allowed actions... move(A,B) : if A<>B and B<>floor and on(A,floor) and clear(A) and clear(B) then delete on(A,floor) and clear(B) add on(A,B). move(A,C) : if on(A,B) and B<>floor and clear(A) and clear(C) and A<>C then delete on(A,B) and clear(C) add on(A,C) and clear(B). move(A,floor) : if on(A,B) and B<>floor and clear(A) then delete on(A,B) add on(A,floor) and clear(B).