
%%% GOAL %%%

%           
%   c      b
%   a      d
%--------------

goal:-  on(a,table,T),  on(c,a,T), on(d,table,T), on(b,d,T),
        legal(T), lastTime(T).



%%% GUESS FOR ACTIONS MODULE %%%
% guess for actions
move(B,L,T) v notMove(B,L,T) :- block(B), location(L), time(T), B!=L.

moved(B,T) :- move(B,L,T).
somethingMoved(T):- moved(B,T).

% no actions are executed at last time
 :- move(B,L,T), lastTime(T).

% no concurrency
 :- move(B,L,T), move(B1,L1,T), B < B1.
 :- move(B,L,T), move(B1,L1,T), L < L1.


%%% INITIAL STATE MODULE %%%

% Partial initial state
% Note the we do not know whether c is on the table or on top of b.
on(a,table,0):-true.
on(b,a,0):-true.
on(d,c,0):-true.

% guess for a complete initial state
on(B,L,0) v notOn(B,L,0) :- block(B), location(L).
% check whether the initial state is legal
illegalInitialState :- block(B), unsupported(B).
illegalInitialState :- block(B), on(B2,B,0), on(B1,B,0), B1!=B2.
illegalInitialState :- block(B), on(B,B2,0), on(B,B1,0), B1!=B2.
illegalInitialState :- on(B,L,0), notOn(B,L,0).
illegalInitialState :- on(B,B,0).



%%% TRANSITION FUNCTION MODULE %%%

% effect of moving a block
on(B,L,T1) :- block(B), location(L), move(B,L,T), next(T,T1).

% a block can be moved only when it's clear
legal(T1):- legal(T), next(T,T1), move(B,L,T), clear(B,T), clear(L,T).
legal(T1):- legal(T), next(T,T1), not somethingMoved(T).
legal(0):-true.

clear(table,T):- time(T).
clear(B,T):- noBlockOn(B,T).

% wherever a block is, it's not anywhere else
notOn(B,L1,T) :- on(B,L,T), location(L1), L!=L1.

% inertia
on(B,L,T1) :- on(B,L,T), next(T,T1), not moved(B,T).


%%% SATURATION %%%

% The plan is checked with respect to the guessed initial state
checkedPlan :- goal.

% Ilegal initial states cannot disprove the validity of the guessed plan
checkedPlan :- illegalInitialState.

% saturation
on(B,L,T) :- checkedPlan, time(T), block(B), location(L).
notOn(B,L,T) :- checkedPlan, time(T), block(B), location(L).

% constraint
:- not checkedPlan.


%%% BACKGROUND KNOWLEDGE %%%

block(a). block(b). block(c). block(d).
location(L) :- block(L).
location(table):-true.

firstBlock(a). lastBlock(d).
nextBlock(a,b). nextBlock(b,c). nextBlock(c,d).

% include -N=k as an option
time(T) :- #int(T).
lastTime(#maxint).
next(X,Y) :- #succ(X,Y).


%%% USEFUL PREDICATES %%%

true.

% Check whether no block is on B at time T.
noBlockOn(B,T) :- nothingOn(B,T,MAX), lastBlock(MAX).

nothingOn(B,T,B1):- firstBlock(B1), notOn(B1,B,T).
nothingOn(B,T,B1):- nothingOn(B,T,B2), nextBlock(B2,B1), notOn(B1,B,T).


% Check whether block B is unsupported at the initial time 0.
unsupported(B) :- supportedBy(B,B).
unsupported(B) :- dangling(B,MAX), lastBlock(MAX).

supportedBy(B,L) :- on(B,L,0).
supportedBy(B,L) :- supportedBy(B,B1), on(B1,L,0).

dangling(B,B1):- firstBlock(B1), notOn(B,B1,0), notOn(B,table,0).
dangling(B,B1):- dangling(B,B2), nextBlock(B2,B1), notOn(B,B1,0).
