%        WARPLAN - A System for Generating Plans
%    ( used with the kind permission of the Author,
%                   David H.D.Warren )

%  The general planner.
%  --------------------
:-   op( 200, xfy, & ),   op( 100, yfx, : ).

% Generate and output a plan.
plans( C, T )   :-
        nononexistent,                                                     %% FK
	nl,  write( C ),  write( '  starting from  ' ),  write( T ),  nl,
	fail.
plans( C, _ )   :-
	inconsistent( C, true ),   !,   write( 'Impossible.' ),   nl,
        nonexistent.                                                       %% FK
plans( C, T )   :-
	plan( C, true, T, T1 ),   output( T1 ),   !,
        nonexistent.                                                       %% FK
plans( _, _ )   :-
	write( 'Can''t do this.' ),   nl,
        nonexistent.                                                       %% FK

output( Xs : X )   :-
	mkground( Xs : X ),   output1( Xs ),   output2( X, ' .' ).
output( _ )   :-   write( 'Nothing need be done.' ),   nl.

output1( Xs : X )   :-   !,   output1( Xs ),   output2( X, ' ;' ).
output1( _ ).

output2( Item, Punct )   :-   write( Item ),   write( Punct ),   nl.

% Main planning routine.
%    Definitions of 'always', 'imposs', 'given', 'can', 'add', 'del' -
%    see specific world descriptions.

plan( X & C, P, T, T2 )   :-
	!,   solve( X, P, T, P1, T1 ),   plan( C, P1, T1, T2 ).
plan( X, P, T, T1 )   :-   solve( X, P, T, _, T1 ).

% Ways of solving a goal.
solve( X, P, T, P, T )   :-   always( X ).
solve( X, P, T, P, T )   :-   X.
solve( X, P, T, P1, T )   :-   holds( X, T ),   and( X, P, P1 ).
solve( X, P, T, X & P, T1 )   :-
	add( X, U ),   achieve( X, U, P, T, T1 ).

% Methods of achieving a goal -
%   by extension:
achieve( _, U, P, T, T1 : U )   :-
	preserves( U, P ),   can( U, C ),   not inconsistent( C, P ),
	plan( C, P, T, T1 ),   preserves( U, P ).
%    by insertion:
achieve( X, U, P, T : V, T1 : V )   :-
	preserved( X, V ),   retrace( P, V, P1 ),
	achieve( X, U, P1, T, T1 ),   preserved( X, V ).

% Check if a fact holds in a given state.
holds( X, _ : V )   :-   add( X, V ).
holds( X, T : V )   :-
	!,   preserved( X, V ),   holds( X, T ),   preserved( X, V ).
holds( X, T )   :-   given( T, X ).

% Prove that an action preserves a fact.
preserves( U, X & C )   :-   preserved( X, U ),   preserves( U, C ).
preserves( _, true ).

preserved( X, V )   :-   check( pres( X, V ) ).
pres( X, V )   :-   mkground( X & V ),   not del( X, V ).

% Retracing a goal already achieved.
retrace( P, V, P2 )   :-
   can( V, C ),   retrace( P, V, C, P1 ),   append_amp( C, P1, P2 ).

retrace( X & P, V, C, P1 )   :-
	add( Y, V ),   X == Y,   !,   retrace( P, V, C, P1 ).
retrace( X & P, V, C, P1 )   :-
	elem( Y, C ),   X == Y,   !,   retrace( P, V, C, P1 ).
retrace( X & P, V, C, X & P1 )   :-   retrace( P, V, C, P1 ).
retrace( true, _, _, true ).

%  Inconsistency with a goal already achieved.
inconsistent( C, P )   :-
	mkground( C & P ),   imposs( S ),
	check( intersect( C, S ) ),   implied( S, C & P ),   !.

%  Utilities.
%  ----------

and( X, P, P )   :-   elem( Y, P ),   X == Y,   !.
and( X, P, X & P ).

append_amp( X & C, P, X & P1 )   :-   !,   append_amp( C, P, P1 ).
append_amp( X, P, X & P ).

elem( X, Y & _ )   :-   elem( X, Y ).
elem( X, _ & C )   :-   !,   elem( X, C ).
elem( X, X ).

implied( S1 & S2, C )   :-   !,   implied( S1, C ),   implied( S2, C ).
implied( X, C )   :-   elem( X, C ).
implied( X, _ )   :-   X.

intersect( S1, S2 )   :-   elem( X, S1 ),   elem( X, S2 ).

notequal( X, Y )   :-   not var( X ),   var( Y ),   !.                     %% FK
notequal( X, Y )   :-   var( X ),   not var( Y ),   !.                     %% FK
notequal( X, Y )   :-   not X=Y ,   not X='V'(_) ,   not Y='V'(_).         %% FK

mkground( Term )   :-  numbervars( Term, 0, _ ).                           %% FK

%% check( Cond )   :-   not not Cond.      %% FK:  already defined in Toy Prolog

%% FK:-   unknown( _, fail ).
end.                                                                       %% FK
