
%%%%%%%%%%%%%%% direttive iniziali
:- [golog_swi, util].
%%% direttive discontiguous per i fluenti
:- discontiguous atRobby/2, at/3, in/2.
%%%%%%%%%%% dichiarazione delle azioni primitive
primitive_action(go(_,_)).    
primitive_action(take(_,_)).
primitive_action(drop(_,_)).
%%%%%% Restore suppressed situation arguments.
restoreSitArg(atRobby(X),S,atRobby(X,S)).
restoreSitArg(at(X,Y),S,at(X,Y,S)).
restoreSitArg(in(X),S,in(X,S)).

%%%%%%% Action precondition axioms
poss(go(X,Y),S) :-
	atRobby(X,S),		%loc(X),
	loc(Y), not(X=Y).
poss(take(X,Y),S) :- atRobby(Y,S), at(X,Y,S).
poss(drop(X,Y),S) :- atRobby(Y,S), in(X,S).

%%%%%%% Successor state axioms
atRobby(X,do(A,S)) :-
	A = go(_,X) ;
	(atRobby(X,S), \+ A = go(X,_)).
at(X,Y,do(A,S)) :-
	A = drop(X,Y) ;
	(at(X,Y,S), \+ A=take(X,Y)).
in(X,do(A,S)) :-
	A=take(X,_) ;
	(in(X,S), \+ A=drop(X,_)).

%%%%%%% definizione di eventuali predicati statici
loc(X) :- member(X,[casa,scuola,ufficio,negozio]).
obj(X) :- member(X,[libro,penna,telefono,portatile,quaderno,bottiglia]).

%%%% Initial situation
atRobby(casa,s0).
in(bottiglia,s0).
at(quaderno,casa,s0).
at(libro,scuola,s0).
at(penna,negozio,s0).
at(telefono,ufficio,s0).
at(portatile,ufficio,s0).

%%% procedure
%% vai nel posto Loc, se gia' non ci sei
proc(goto(Loc),
    ?(atRobby(Loc)) # pi(z,go(z,Loc))).
% oppure
proc(goto_star(Loc),
     star(pi(z,go(z,Loc)))).

%% vai a prendere l'oggetto X
%% fallisce se X e' gia' nella borsa
proc(prendi(X),
     pi(y,?(at(X,y)) : goto(y) : take(X,y))).

%% porta X nel posto Y
proc(porta(X,Y),
     ?(in(X)) # prendi(X) :
    goto(Y) : drop(X,Y)).

%%% svuota la borsa nel posto in cui ti trovi
% versione con while
proc(svuota,
     pi(x, ?(atRobby(x)) :
       while(some(y,obj(y) & in(y)),
	     pi(y, ?(in(y)) : drop(y,x))))).

%% ricorsiva
%% svuota_in(Loc): svuota la borsa in Loc
%% procedura ausiliaria:
proc(svuota_in(Loc),
     ?(all(x,obj(x) => -in(x))) #
    pi(x, ?(obj(x) & in(x)) :
      drop(x,Loc) : svuota_in(Loc))).
proc(svuota_ric,
     pi(x,?(atRobby(x)) : svuota_in(x))).
% oppure
proc(svuota_star,
     pi(x,?(atRobby(x)):
       star(pi(y,drop(y,x)))) :
      ?(all(x,obj(x) => -in(x)))).

%% vai in Loc, prendi tutti gli oggetti che sono li'
% versione con while
proc(prenditutti(Loc),
     goto(Loc) :
    while(some(x,at(x,Loc)),
	  pi(x,?(at(x,Loc)): take(x,Loc)))).

%%% ricorsiva
proc(prendi_aux(Loc),
     ?(-some(x,obj(x) & at(x,Loc))) #
    pi(x,?(at(x,Loc)): take(x,Loc)) :
    prendi_aux(Loc)).
proc(prenditutti_ric(Loc),
     goto(Loc) : prendi_aux(Loc)).

% con l'uso di star
proc(prenditutti_star(Loc),
     goto(Loc) :
    star(pi(x,take(x,Loc))) :
    ?(-some(x,obj(x) & at(x,Loc)))).

%%% va a prendere tutti gli oggetti che ci sono i giro e li porta in Dest
proc(portatutti(Dest),
     %% finche' ci sono oggetti in luoghi diversi da Dest
     while(some(x,obj(x) & some(y,at(x,y) & -(y=Dest))),
	   %% scegli un posto diverso da Dest in cui ci sono oggetti
	   %% e carica la borsa
	   pi(y,?(loc(y) & some(x,at(x,y) & -(y=Dest))) :
	     prenditutti(y))) :
        %% vai in Dest e svuota la borsa
    goto(Dest) : svuota).

 %% raccoglie gli oggetti in List
proc(raccogli(List),
     svuota : raccogli_aux(List)).
proc(raccogli_aux(List),
     ?(List=[]) #
    pi(x, pi(rest, ?(List=[x|rest]) :
	    prendi(x) : raccogli_aux(rest)))).

%% porta in Dest tutti gli oggetti in List
proc(portalista(List,Dest),
     raccogli(List) : goto(Dest) : svuota).
