%%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% %%% 
%%% Problema auto da no 89 di EATCS, pagina 183 (by Laurent Rosaz):
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% You are on the road. 
%%% At km 0 is the unique gas station.
%%% You have N cars (and drivers) and you can fill the N cars at the gas station. 
%%% No supplementary gas recipients are allowed.
%%% It is allowed at any time to decant gas from one car tank to another. 
%%% A full tank allow a car to drive for a constant distance K.
%%% You have car number 1 and you can abandon the other cars on the road.
%%% How far can you go ?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Per semplicita', K e' sia la capacita' di ogni
%%% serbatoio che la distanza percorribile con quella
%%% benzina (basta usare le unita' di misura giuste)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Si analizza il tutto discretamente (movimenti unitari)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Inoltre facciamo fare il refill solo da auto di indice
%%% maggiore in auto di indice minore (evitiamo loops)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Congetturo possano fare:
%%% ~ K + log_2(N)*K/2.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Examples:
%% cars(2) capacity(2) distance(1,3) => 5 actions ok
%% cars(3) capacity(3) distance(1,5) => 10 actions ok 
%% cars(4) capacity(2) distance(1,4) => 11 actions ok (12 or 13 as well)

%%%% PARAMETERS

cars(4). 
capacity(2).

maxdist(M) :- 
    cars(C),capacity(K),M is C * K.

%%%% DOMAIN PREDICATES 

car(X) :-
   cars(N), interval(X,1,N).  
fuel(X) :-
   capacity(K), interval(X,0,K).
dist(D) :-
   maxdist(M), interval(D,0,M).   

%%%%% Fluents Definition
   
fluent(tank(X,Y)) :-
     car(X), fuel(Y).
fluent(distance(X,D)) :-
     car(X), dist(D).
     
%%%%% Actions Definition

action(move(X)):-  
   car(X).
action(refill(X,Y)) :-
   car(X),car(Y),X>Y.
   
%%%%% Executability Conditions
   
executable(move(X),[tank(X,Y)]) :-
       car(X), %%% action(move(X))
       fuel(Y),
       Y > 0.
        
executable(refill(X,Y),[distance(X,Z), distance(Y,Z),
                        tank(X,FX), tank(Y,FY)]) :-  
       car(X),car(Y),X>Y, %%% action(refill(X,Y))
       fuel(FX), fuel(FY),
       dist(Z),
       capacity(K),
       FX > 0, FY < K.
                
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

causes(move(X),tank(X,Y1),[tank(X,Y)]):-
       car(X),
       fuel(Y),
       Y > 0, %%% action(move(X))
       Y1 is Y - 1.
causes(move(X),distance(X,Y1), [distance(X,Y)]) :-
       car(X),
       dist(Y),
       Y1 is Y + 1.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

causes(refill(X,Y), tank(X,0), [tank(X,LX),tank(Y,LY)]):-
        action(refill(X,Y)),
        fluent(tank(X,LX)),
        fluent(tank(Y,LY)),
        capacity(K),
        K-LY >= LX.
causes(refill(X,Y), tank(Y,LYnew), [tank(X,LX),tank(Y,LY)]):-
        action(refill(X,Y)),
        fluent(tank(X,LX)),
        fluent(tank(Y,LY)),
        capacity(K),
        K-LY >= LX,
        LYnew is LX + LY.
causes(refill(X,Y), tank(X,LXnew), [tank(X,LX),tank(Y,LY)]):-
        action(refill(X,Y)),
        fluent(tank(X,LX)),
        fluent(tank(Y,LY)),
        capacity(K),
        LX >= K-LY,
        LXnew is LX-K+LY.
causes(refill(X,Y), tank(Y,K), [tank(X,LX),tank(Y,LY)]):-
        action(refill(X,Y)),
        fluent(tank(X,LX)),
        fluent(tank(Y,LY)),
        capacity(K),
        LX >= K-LY.
        
%%%%%% Initial State

initially(tank(X,K)) :-
    capacity(K), car(X).

initially(distance(X,0)) :-
    car(X).
    
%%%%%% Completion (for ASP)

initially(neg(tank(X,Y))) :-
    capacity(K), 
    fuel(Y),
    Y < K,
    car(X).

initially(neg(distance(X,D))) :-
    car(X),
    dist(D),
    D > 0.
    
%%%%%%  Goal State

goal(distance(1,4)).

%%%%%   Static Rules (modeling fluent negation)

caused([tank(X,Y)],neg(tank(X,Z))) :-
   car(X),
   fuel(Y),
   fuel(Z),
   neq(Y,Z).
   
caused([distance(X,Y)],neg(distance(X,Z))) :-
   car(X),
   dist(Y),
   dist(Z),
   neq(Y,Z).
   
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        
%%% AUX
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        

interval(A,A,_).
interval(X,A,B) :-
  A < B, C is A + 1,
  interval(X,C,B).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        

