% Missionaries and Cannibals puzzle
% This is an attempt to do it without introducing
% Board/Disembark/CrossTo actions.
% I couldn't get it to work

include "../library-ontology"
include "../library"

sorts
   RiverBank;

inclusions
   RiverBank << Accumulator;

% Maximum number of missionaries/cannibals
numeric_symbol MaxMiss=3

% Maximum capacity of the boat
numeric_symbol MaxBoatCapacity=2

module MISSIONARIES;

  objects
    M, C : Resource;
    Boat : Thing;
    Bank1, Bank2 : RiverBank;
    P1, P2 : Place;

  variables
    n,n1  : 1..MaxMiss;
    r     : Resource;
    b,b1,
    b2,b3 : RiverBank;
    x     : Thing;
    p     : Place;

  import TRANSFER;

  import MOVE;

  axioms
    Location(Bank1)=P1;
    Location(Bank2)=P1;
    inertial Location(x);

    Move(Boat,p) if Transfer(n,r,b,b1) & Location(b1)=p;
    nonexecutable Transfer(n,r,b,b1) if Location(b)=p & Location(Boat)!=p;

    % Limited concurrency: Only one transfer action per resource
    nonexecutable Transfer(n,r,b,b1) & Transfer (n1,r,b2,b3) if (n!=n1 | b!=b2 | b1!=b3);
    % And that transfer must be in the same direction
    nonexecutable Transfer(n,M,b,b1) & Transfer (n1,C,b2,b3) if (b!=b2 | b1!=b3);

    % The boat cannot carry more than its capacity
    nonexecutable Transfer(n,M,b,b1) & Transfer (n1,C,b,b1) if MaxBoatCapacity < n+n1; 
    nonexecutable Transfer(n,M,b,b1) if MaxBoatCapacity < n; 
    nonexecutable Transfer(n,C,b,b1) if MaxBoatCapacity < n; 

    % Cannibals should never outnumber missionaries
    constraint -(Amount(M,b)!=0 & Amount(M,b) < Amount(C,b));
    % And no outnumbering in the boat either!
    nonexecutable Transfer(n,M,b,b1) & Transfer (n1,C,b,b1) if n < n1; 
