

     %   Bad Situations for the OCTOPUS Blocks World

/*  Canonical ordering on robot hand use: When a free hand is
    needed, choose the least. This prevents plans that are
    permutations of one another wrt hands being used.  */

badSituation(do(startMove(H,X,Y,T,T1),S)) :- not leastAvailableHand(H,S).
badSituation(do(startMoveToTable(H,X,T,T1),S)) :-
                                  not leastAvailableHand(H,S).

leastAvailableHand(H,S) :- not handInUse(H,S),
                           not (hand(H1), H1 < H, not handInUse(H1,S)).

/*  Eliminate permutations of actions whose start times are the same.
    When two identical action types occur at the same times, choose
    the action that moves the lexicographically least block.  */

badSituation(do(A,do(B,S))) :- precedes(A,B),
                               sameOccurrenceTimes(A,B),
                               poss(A,S), poss(B,do(A,S)).

precedes(endMove(H1,X1,Y1,T1,T2),
         startMove(H2,X2,Y2,T3,T4)).
precedes(endMove(H1,X1,Y,T1,T2),
         startMoveToTable(H2,X2,T3,T4)).
precedes(endMoveToTable(H1,X1,T1,T2),
         startMove(H2,X2,Y,T3,T4)).
precedes(endMoveToTable(H1,X1,T1,T2),
         startMoveToTable(H2,X2,T3,T4)).
precedes(startMove(H1,X1,Y,T1,T2),
         startMoveToTable(H2,X2,T3,T4)).
precedes(endMoveToTable(H2,X2,T3,T4),
         endMove(H1,X1,Y,T1,T2)).
precedes(endMoveToTable(H1,X1,T1,T2),
         endMoveToTable(H2,X2,T3,T4)) :- X1 @< X2.
precedes(startMove(H1,X1,Y1,T1,T2),
         startMove(H2,X2,Y2,T3,T4)) :- X1 @< X2.
precedes(endMove(H1,X1,Y1,T1,T2),
         endMove(H2,X2,Y2,T3,T4)) :- X1 @< X2.

sameOccurrenceTimes(A,B) :- time(A,T), time(B,T).

%  Don't create a bad tower by a move action.

badSituation(do(startMove(H,X,Y,T,T1),S)) :-
                  not goodTower(X,do(endMove(H,X,Y,T,T1),
                                     do(startMove(H,X,Y,T,T1),S))).

%  Don't move anything from a good tower to the table.

badSituation(do(startMoveToTable(H,X,T,T1),S)) :- goodTower(X,S).

/*  Opportunistic rule: If an action can create a good tower, don't
    do a bad-tower-creating moveToTable action.  */

badSituation(do(startMoveToTable(H,X,T,T1),S)) :-
           not goodTower(X, do(endMoveToTable(H,X,T,T1),
                               do(startMoveToTable(H,X,T,T1),S))),
           existsActionThatCreatesGoodTower(S).

existsActionThatCreatesGoodTower(S) :-
  (A = startMove(H,Y,Z,T,T1), B = endMove(H,Y,Z,T,T1) ;
   A = startMoveToTable(H,Y,T,T1), B = endMoveToTable(H,Y,T,T1)),
  poss(A,S), poss(B,do(A,S)), goodTower(Y,do(B,do(A,S))).

