% A reconstruction of simple version of Cohen's planning program
% Based on Gazdar and Mellish

% Christopher Manning May 1999

%%% ----- The initial states and goals
%%% ----- These are given a number, so that we can refer to multiple
%%% ----- scenarios in one program.  They can be tested out by
%%% ----- trying: test(number).
%%% ----- You need that full stop at the end!
%%% ----- An inital state is an id number followed by a list of true things
%%% ----- A goal is an ID, whose goal it is, and then what the goal is

initial(1, [at(alan,inside), door(inside, outside, open)]).
goal(1, alan, at(alan,outside)).

initial(2, [at(alan,room1),
	door(room1,room2,open),
	door(room2,room3,open),
	door(room3,room4,open)]).
goal(2, alan, at(alan,room4)).

initial(3, 
	[at(alan,inside), at(sue,inside),
	 cando(alan,move(alan,inside,outside)),
	 believes(sue,cando(alan,move(alan,inside,outside))),
	 door(inside, outside, open)]).

goal(3, sue, at(alan,outside)).

initial(4, [at(john, r1), at(mary, r2),
	door(r1, r2, closed), bolt(door, back)]).
goal(4, john, at(john, r2)).

initial(5, [at(john, r1), at(mary, r2), cando(john, talkto(john, mary)),
	cando(mary, move(mary, bolt)),
	believes(john, cando(mary, move(mary, bolt))),
	door(r1, r2, closed), bolt(door, across)]).
goal(5, john, bolt(door, back)).


initial(7, [cando(ann, talkto(ann, sandra)),
    cando(sandra, talkto(sandra, ann)),
    knows(sandra, safecombination)]).
goal(7, ann, knows(ann, safecombination)).




%%% ----- Information about possible actions and plans for achieving them
%%% ----- Actions have four arguments:
%%% ----- 1. The action predicate
%%% ----- 2. A list of preconditions for being able to do the action
%%% ----- 3. A list of things that become true as a result of doing the action
%%% ----- 4. A list of things that cease to become true as a result

action(request(P1, P2, Act),	% action
	[cando(P1, talkto(P1, P2)), 
	 believes(P1, cando(P2, Act))],		% preconditions
	[believes(P2, wants(P1, Act))],		% becomes true
	[]).			% no longer true

action(move(Agent, Source, Destination),
	[at(Agent, Source), wants(Agent, move(Agent, Source, Destination)),
	 door(Source, Destination, open)],
	[at(Agent, Destination)],
	[at(Agent, Source)]).

action(cause_to_want(Speaker, Addressee, Action),	% action
	[cando(Addressee, Action),			% preconditions
	 believes(Addressee, wants(Speaker, Action))],
	[wants(Addressee, Action)],
	[]).

action(pushopen(P, door),
	[door(Source, Destination, closed), 
	 bolt(door, back),
	 at(P, Source)],
	[door(Source, Destination, open)],
	[door(Source, Destination, closed)]).

action(move(P, bolt),
	[at(P, r2), wants(P, move(P, bolt))],	% can take out want
	[bolt(door, back)],
	[bolt(door, across)]).






%%% ----- below here is the planner used.  You shouldn't need to look at
%%% ----- or touch anything below here.

% The length of a list -- used in generation mode for iterative deepening

listlen(List, Length) :- lenacc(List, 0, Length).

lenacc([], Length, Length).
lenacc([_Head|Tail], A, Length) :- A1 is A + 1, lenacc(Tail, A1, Length).

member(X, [X|_]).
member(X, [_|Y]) :- member(X, Y).

setdifference([], _, []).
setdifference([A|T], B, R) :- member(A,B), !, setdifference(T, B, R).
setdifference([A|T], B, [A|R]) :- setdifference(T, B, R).

% 
planner(Id, Actions) :-
	initial(Id, World),
	goal(Id, Agent, Goal),
	plan(Agent, Goal, World, Actions, [], _Done),
	write_acts(Actions), nl.

% Plan to achieve a single goal

% plan(Agent, Goal, World, ActionsDiff1, ActionsDiff2, DoneFlag).

plan(A, Goal, _W, _, _, _) :- write([goal,for,A,is,Goal]), nl, fail.

% If a goal is commonknowledge, everyone believes it
% plan(Agent, believes(_, Goal), World, Actions1, Actions2, Done) :-
%	commonknowledge(Goal), !,
%	plan(Agent, Goal, World, Actions1, Actions2, Done).

% if it's something in the world, then we are done
plan(_Agent, Goal, World, Actions, Actions, _Done) :-
	groundstate(Goal, State),
	member(Goal, World),
	write([it,is,true,that,Goal]), nl,
	((State=ground,!); true).

% Agents want things for themselves
plan(Agent, wants(Agent, _Want), _World, Actions, Actions, _Done).

% Agents believe things providing they are true in the world
plan(Agent, believes(Agent, Goal), World, Actions1, Actions2, Done) :-
	plan(Agent, Goal, World, Actions1, Actions2, Done).

% the general recursive case
plan(Agent, Goal, World, [Action|Actions0], Actions2, Done) :- 
	action(Action, Precond, Effect, NegEffect),
%	write([testing,Goal,in,Effect]), nl,
	member(Goal, Effect),
	write([trying, operator, Action]), nl,
	allplan(Agent, Precond, World, Actions0, Actions2, Done),
%	allplan(Agent, Want, World, Actions1, Actions2, Done),
%	this part is a noop at present
	setdifference(World, NegEffect, _World2),
	Done = yes.

% Plan a set of goals

allplan(_Agent, [], _World, Actions, Actions, _Done).
allplan(Agent, [Goal|Goals], World, Actions0, Actions2, Done) :-
% 	var(Done), !,
	plan(Agent, Goal, World, Actions0, Actions1, Done),
	allplan(Agent, Goals, World, Actions1, Actions2, Done).
% allplan(_Agent, _Goals, _World, Actions, Actions, _Done).

groundstate(Goal, nonground) :- \+ ground(Goal), !.
groundstate(_Goal, ground).

write_acts([]) :- !,
	nl, write('*** Plan is: '), nl.
write_acts([Act|Acts]) :-
	write_acts(Acts),
	write(Act), nl.

test(Id) :- listlen(Actions, Length),
	( Length =< 8 -> 
	   write('Trying plan of length '), write(Length), nl,
	   planner(Id, Actions)
 	;
	   nl, 
	   write('*** It doesn''t seem possible to solve that plan!'), nl,
	   write('*** Aborting...'), nl,
	   true
	).
