/* prolog tutorial 2.19  Actions and plans */

:- dynamic on/2.

on(a,b).    
on(b,c).    
on(c,table).

put_on(A,B) :-
     A \== table,
     A \== B,
     on(A,X),
     clear(A),
     clear(B),
     retract(on(A,X)),
     assert(on(A,B)),
     assert(move(A,X,B)).

clear(table).
clear(B) :- 
     not(on(_X,B)).

/* ----------------------------------------------*/


r_put_on(A,B) :-
     on(A,B).
r_put_on(A,B) :-
     not(on(A,B)),
     A \== table,
     A \== B,
     clear_off(A),        /* N.B. "action" used as precondition */
     clear_off(B),
     on(A,X),
     retract(on(A,X)),
     assert(on(A,B)),
     assert(move(A,X,B)).

clear_off(table).    /* Means there is room on table */
clear_off(A) :-      /* Means already clear */
     not(on(_X,A)).
clear_off(A) :-
     A \== table,
     on(X,A),
     clear_off(X),      /* N.B. recursion */
     retract(on(X,A)),
     assert(on(X,table)),
     assert(move(X,A,table)).


do(Glist) :- 
      valid(Glist), 
      do_all(Glist,Glist). 

valid(_).                          /* Temporary. See Exercise 2.19.1 */
   
do_all([G|R],Allgoals) :-          /* already true now */
     call(G),
     do_all(R,Allgoals),!.         /* continue with rest of goals */

do_all([G|_],Allgoals) :-          /* must do work to achieve */
     achieve(G),
     do_all(Allgoals,Allgoals).    /* go back and check previous goals */
do_all([],_Allgoals).              /* finished */

achieve(on(A,B)) :-
     r_put_on(A,B).