% 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 
:- move(B,L,T), on(B1,B,T).

% any two blocks cannot be on the same block at the same time.
:- block(B), on(B2,B,T), on(B1,B,T), B1 < B2.

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

% every block is supported by the table
supported(B,T) :- on(B,table,T).
supported(B,T) :- on(B,B1,T), supported(B1,T), B != B1.
:- block(B), time(T), not supported(B,T).

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

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

% initial values and actions are exogeneous
on(B,L,0) ; -on(B,L,0) :- block(B), location(L).
move(B,L,T) ; -move(B,L,T):- block(B), location(L), time(T), T < #maxint.

% include -N=k as an option 
time(T) :- #int(T).

true.
location(L) :- block(L).
location(table) :- true.

next(X,Y) :- #succ(X,Y).
