

    %  Prolog Clauses for a Blocks World with Concurrent Actions

/*  Poss for concurrent actions. These clauses are independent of
    the blocks world.  */

poss(C,S) :- concurrentAction(C),

    /* First determine all good primitive actions that are
       possible in situation S. */

             setof(A,
                   (primitive_action(A), poss(A,S), not badAction(A,S)),
                   GoodActions),

 /* Next, determine a maximal subset of these whose actions do not
    conflict with one another.  */

             maxCompatibleSubset(GoodActions,Max,S),

 % Finally, any subset of these is a possible concurrent action.

             subset(C,Max).

maxCompatibleSubset(C,Max,S) :- getTwoMembers(C,A,B),
                  conflict(A,B,S), (delete(A,C,D) ; delete(B,C,D)),
                  maxCompatibleSubset(D,Max,S), !.
maxCompatibleSubset(C,C,S).

getTwoMembers([A | L],A,B) :- member(B,L).
getTwoMembers([X | L],A,B) :- getTwoMembers(L,A,B).

/*****************************************************************/

            %   Blocks World Specific Clauses.

%   Successor State Axioms.

clear(X,do(C,S)) :- (member(move(Y,Z),C) ; member(moveToTable(Y),C)),
                    on(Y,X,S) ;
                    clear(X,S), not member(move(Y,X),C).
on(X,Y,do(C,S)) :- member(move(X,Y),C) ;
                   on(X,Y,S), not member(moveToTable(X),C),
                              not member(move(X,Z),C).
ontable(X,do(C,S)) :- member(moveToTable(X),C) ;
                      ontable(X,S), not member(move(X,Y),C).

%   Action Precondition Axioms

poss(move(X,Y),S) :- clear(X,S), clear(Y,S), not X = Y.
poss(moveToTable(X),S) :- clear(X,S), not ontable(X,S).

conflict(move(X,Y),move(Y,Z),S).  conflict(move(Y,Z),move(X,Y),S).
conflict(move(X,Y),moveToTable(X),S). conflict(moveToTable(X),move(X,Y),S).
conflict(move(X,Y),moveToTable(Y),S). conflict(moveToTable(Y),move(X,Y),S).
conflict(move(X,Y),move(X,Z),S) :- not Y = Z.
conflict(move(X,Y),move(Z,Y),S) :- not X = Z.

%   Bad actions.

badAction(move(X,Y),S) :- not goodTower(X,do([move(X,Y)],S)).
badAction(moveToTable(X),S) :- goodTower(X,S).

%  Bad situation. C doesn't include all good-tower-producing actions.

badSituation(do(C,S)) :- omitsGoodTowerProducingAction(C,S).

omitsGoodTowerProducingAction(C,S) :-
              goodTowerProducingAction(A,S), not member(A,C).

goodTowerProducingAction(A,S):- blockMoved(A,X),
                                goodTower(X,do([A],S)), poss(A,S).

blockMoved(move(X,Y),X).  blockMoved(moveToTable(X),X).

%   Primitive Action Declarations.

primitive_action(move(X,Y)).    primitive_action(moveToTable(X)).

