%  WARPLAN - the STRIPS problem
% <strips_onoff>

add(  at( robot, P ),  goto1( P, _R )  ).
add(  nextto( robot, X ),  goto2( X, _R )  ).
add(  nextto( X, Y ),  pushto( X, Y, _R )  ).
add(  nextto( Y, X ),  pushto( X, Y, _R )  ).
add(  status( Sw, on ),  turnon( Sw )  ).
add(  status( Sw, off ),  turnoff( Sw )  ).
add(  on( robot, B ),  climbon( B )  ).
add(  onfloor,  climboff( _B )  ).
add(  inroom( robot,  R2 ),  gothrough( _D, _R1, R2 )  ).
add(  inroom( robot,  R2 ),  pushthrough( _X, _D, _R1, R2 )  ).
add(  inroom( X,  R2 ),  pushthrough( X, _D, _R1, R2 )  ).

del(  at( X, _Z ),  U  )    :-    moved( X, U  ).
del(  nextto( Z, robot ),  U  )    :-    !,   del(  nextto( robot, Z ),  U  ).
del(  nextto( robot,  X ),  pushto( X, _Y, _R )  )    :-    !,   fail.
del(  nextto( robot,  X ),  pushthrough( X, _D, _R1, _R2 )  )    :-    !,   fail.
del(  nextto( robot,  B ),  climbon( B )  )    :-    !,   fail.
del(  nextto( robot,  B ),  climboff( B )  )    :-    !,   fail.
del(  nextto( X, _Z ),  U  )    :-    moved(  X,  U  ).
del(  nextto( _Z, X ),  U  )    :-    moved(  X,  U  ).
del(  on( robot, _Z ),  climboff( _B )  ).
del(  onfloor,  climbon( _B )  ).
del(  inroom( robot, _Z ),  gothrough( _D, _R1, _R2 )  ).
del(  inroom( robot, _Z ),  pushthrough( _X, _D, _R1, _R2 )  ).
del(  inroom( X, _Z ),  pushthrough( X, _D, _R1, _R2 )  ).
del(  status( Sw, _Z ),  turnon( Sw )  ).
del(  status( Sw, _Z ),  turnoff( Sw )  ).

moved(  robot,  goto1( _P, _R )  ).
moved(  robot,  goto2( _X, _R )  ).
moved(  robot,  pushto( _X, _Y, _R )  ).
moved(  robot,  gothrough( _D, _R1, _R2)  ).
moved(  robot,  pushthrough( _X, _D, _R1, _R2)  )  :-  !.
moved(  X,  pushto( X, _Y, _R )  ).
moved(  X,  pushthrough( X, _D, _R1, _R2)  ).

can(  goto1( P, R ),
	locinroom( P, R )  &   inroom( robot, R )  &   onfloor  ).
can(  goto2( X, R ),
	inroom( X, R )  &   inroom( robot, R )  &   onfloor  ).
can(  turnon( lightswitch(S) ),
	nextto( box(1), lightswitch(S) )  &  on( robot, box(1) )  ).
can(  turnoff( lightswitch(S) ),
	nextto( box(1), lightswitch(S) )  &  on( robot, box(1) )  ).
can(  pushto( X, Y, R ),
	pushable( X )  &  notequal( Y, robot )  &  inroom( Y, R )  &
	inroom( X, R )  &  nextto( robot, X )  &   onfloor  ).
can(  gothrough( D, R1, R2 ),
	connects( D, R1, R2 )  &  inroom( robot, R1 )  &
	nextto( robot, D )  &   onfloor  ).
can(  pushthrough( X, D, R1, R2 ),
	pushable( X )  &  connects( D, R1, R2 )  &
	inroom( X, R1 )  &  nextto( X, D )  &
	inroom( robot, R1 )  &    onfloor  &
	nextto( robot, X )  ).
can(  climboff( box(B) ),  on( robot, box(B) )  ).
can(  climbon( box(B) ),  nextto( robot, box(B) )  &   onfloor  ).

always(  inroom( D, R1 )  )    :-    always(  connects( D, R1, _R2 )  ).
always(  connects( D, R1, R2 )  )    :-    connects1(  D, R1, R2  ).
always(  connects( D, R2, R1 )  )    :-    connects1(  D, R1, R2  ).
always(  pushable( box(_N) )  ).
always(  locinroom( point(N), room(1) )  )    :-    range(  N, 1, 5  ).
always(  locinroom( point(6), room(4) )  ).
always(  locinroom( point(7), room(2) )  ).
always(  inroom( lightswitch(N), room(N) )  )   :-   range( N, 1, 2 ).
always(  at( lightswitch(1), point(4) )  ).
always(  at( lightswitch(2), point(7) )  ).

connects1(  door(N), room(N), room(5)  )    :-    range(  N, 1, 4  ).

range(  M, M, _  ).
range(  M, L, N  )    :-
	L  <  N,    L1  is  L + 1,    range(  M, L1, N  ).

imposs(  at( X, Y )  &  at( X, Z )  &  notequal( Y, Z )  ).
imposs(  pushable( X )  &  notequal( X, box(_) )  ).

given(  strips1,  at( box(N), point(N) )  )    :-    range(  N, 1, 3  ).
given(  strips1,  at( robot, point(5) )  ).
given(  strips1,  inroom( box(N), room(1) )  )    :-    range(  N, 1, 3  ).
given(  strips1,  onfloor  ).
given(  strips1,  status( lightswitch(1), off )  ).
given(  strips1,  status( lightswitch(2), on )  ).
given(  strips1,  inroom( robot, room(1) )  ).

% A few tests.
p( X )  :-  plans( X, strips1 ).

wait :-  see( user ),  display( '<press "return" to continue>' ),
         rdch( _ ),    seen.

:-   p( at( robot, point(5) ) ),  wait.
:-   p( at( robot, point(1) ) & at( robot, point(2) ) ),  wait.
:-   p( at( robot, point(4) ) ),  wait.
:-   p( at( robot, point(6) ) ),  wait.
:-   p( nextto( box(1), box(2) ) & nextto( box(3), box(2) ) ),  wait.
:-   p( status( lightswitch(1), on ) ),  wait.
:-   p( status( lightswitch(1), on ) & inroom( robot, room(2) ) ),  wait.
:-   p( status( lightswitch(2), off ) ),  wait.
% :-   p( status( lightswitch(1), on ) & status( lightswitch(2), off ) ),  wait.
:-   p( inroom( robot, room(2) ) & nextto( box(1), door(1) ) ),  wait.
:-   p( nextto( box(2), box(3) ) & nextto( box(3), door(1) ) &
            status( lightswitch(1), on ) & nextto( box(1), box(2) ) &
            inroom( robot, room(2) ) ),  wait.
end.
