/*
Si consideri un dominio in cui ci sono: vari carrelli, vari robot e
vari oggetti. Gli oggetti hanno un colore, che non può essere
modificato. Gli oggetti sono collocati in stanze. I robot possono
afferrare gli oggetti e posizionarli in un carrello. I robot si
possono spostare e spingere il carrello da una stanza all'altra.  

Azioni:
Il robot X prende Y che sta a terra nella stanza P
                  e lo dispone sul carrello Z.
Il robot X prende Y che sta sul carrello Z e lo mette a terra nella
                  stanza P.
Il robot X va dalla stanza Y alla stanza Z
Il robot X spinge il carrello C dalla stanza Y alla stanza Z

Fluenti:
Posizione degli oggetti: stanza o carrello.
Posizione dei robot: stanza.
Posizione dei carrelli: stanza.

Procedure:
Far caricare da qualche robot l'oggetto X sul carrello Y.
Far caricare da qualche robot l'oggetto X su qualche carrello.
Spostare tutti gli oggetti della stanza X in una stanza destinazione.
Svuotare il carrello X.
Raccogliere tutti gli oggetti del colore X e portarli nella stanza Y.
*/

:- [golog_swi].

%%% direttive discontiguous per i fluenti
:- discontiguous at/3, %posizione di oggetti/robot/carrelli nelle
                       %stanze
	on/3. % posizione degli oggetti sui carrelli



%%%%%%%%%%% dichiarazione delle azioni primitive
primitive_action(puton(_,_,_,_)). % mettere un oggetto su un carrello
primitive_action(takeoff(_,_,_,_)). % mettere un oggetto da un carrello a
                                 % terra 
primitive_action(go(_,_,_)).	% spostamento di un robot da origine a
                             % destinazine
primitive_action(move(_,_,_,_)). % un robot spinge un carrello da
                               % origine a destinazione

%%%%%% Restore suppressed situation arguments.
%% (un fatto per ogni fluente).
restoreSitArg(at(X,Y),S,at(X,Y,S)).
restoreSitArg(on(X,Y),S,on(X,Y,S)).

%%%%%%% Action precondition axioms
poss(puton(R,X,C,P),S) :- robot(R), oggetto(X), carrello(C),
	% P e' la stanza
	at(R,P,S), at(X,P,S), at(C,P,S). 
poss(takeoff(R,X,C,P),S) :- robot(R), posto(P),
	on(X,C,S), at(C,P,S), at(R,P,S).
poss(go(R,X,Y),S) :- robot(R), at(R,X,S), posto(Y), X\= Y.
poss(move(R,C,X,Y),S) :- robot(R), carrello(C), posto(Y),
	at(R,X,S), at(C,X,S), X\= Y.

%%%%%%% Successor state axioms
at(X,Y,do(A,S)) :-
	A=go(X,_,Y) ; A=move(_,X,_,Y) ; A=move(X,_,_,Y) ;
	A=takeoff(_,X,_,Y) ;
	at(X,Y,S), \+ (A=go(X,Y,_) ; A=move(_,X,Y,_);
		       A=puton(_,X,_,Y)).
on(X,Y,do(A,S)) :-
	A=puton(_,X,Y,_) ;
	on(X,Y,S), \+ A=takeoff(_,X,Y,_).

%%%%%%% definizione di eventuali predicati statici
robot(X) :- member(X,[pippo,pluto]).
oggetto(X) :- member(X,[1,2,3,4,5,6,7,8,9,10,11,12]).
carrello(X) :- member(X,[c1,c2,c3]).
posto(X) :-  member(X,[salotto,cucina,bagno,ingresso]).
colore(X,rosso) :- oggetto(X), 0 is X mod 3.
colore(X,verde) :- oggetto(X), 1 is X mod 3.
colore(X,giallo) :- oggetto(X), 2 is X mod 3.

%%%% Initial situation
at(pippo,salotto,s0). at(pluto,bagno,s0).
at(c1,salotto,s0). at(c2,cucina,s0).
at(X,cucina,s0) :- member(X,[1,2,3,4]).
at(X,ingresso,s0) :- member(X,[5,6,7,8]).
on(X,c1,s0) :-  member(X,[9,10,11,12]).

% procedure

% il robot R va nel posto P
proc(goto(R,P),
    ?(at(R,P)) #
    pi(x, go(R,x,P))).

% il robot R porta il carrello C nel posto P
% se gia' ci sta si sposta solo il robot per andare nello stesso posto
% del carrello
proc(sposta(R,C,P),
    ?(at(C,P)) : goto(R,P) #
    pi(postoC, ?(at(C,postoC)) :
      goto(R,postoC) : move(R,C,postoC,P))).

% un robot carica l'oggetto X sul carrello Y
proc(carica(X,C),
     ?(on(X,C)) #
    ?(-on(X,C)) :
    pi(postoX, ?(at(X,postoX) v some(y,on(X,y) & at(y,postoX))) :
      pi(r, % ?(robot(r)) :
	sposta(r,C,postoX) :
	(?(at(X,postoX)) # pi(y,takeoff(r,X,y,postoX))) :
	puton(r,X,C,postoX)))).

%Far caricare da qualche robot l'oggetto X su qualche carrello.
proc(caricasuqualchecarrello(X),
     pi(c,carica(X,c))).

%Svuotare il carrello X.
proc(scarica(R,C),
     pi(postoC, ?(at(C,postoC)) :
       goto(R,postoC) :
       while(some(x,oggetto(x) & on(x,C)),
	     pi(x,takeoff(R,x,C,postoC))))).

%Spostare tutti gli oggetti della stanza X in una stanza destinazione.

proc(spostatutti(From,To),
      pi(y, ?(carrello(y)) :
	scarica(y) :
	pi(r, sposta(r,y,From) :
	  while(some(x,oggetto(x) & at(x,From)),
		pi(x,puton(r,x,y,From))) :
	  sposta(r,y,To) :
	  while(some(x,oggetto(x) & on(x,y)),
		pi(x,takeoff(r,x,y,To)))))).

% portare nella stanza To tutti gli oggetti di colore Col che stanno
% nella stanza From

% sottoprocedura: carica sul carrello Y tutti gli oggetti di colore
% Col che stanno nel posto P
proc(caricacol(Col,Y,P),
     while(some(x,colore(x,Col) & -on(x,Y) &
	       (at(x,P) v some(c,on(x,c) & at(c,P)))),
	   pi(x,?(colore(x,Col) & -on(x,Y) &
		 (at(x,P) v some(c,on(x,c) & at(c,P)))) :
	     carica(x,Y)))).

proc(spostacolore(Col,From,To),
      pi(y, ?(carrello(y)) :
	pi(r,scarica(r,y) :
	  sposta(r,y,From) :
	  caricacol(Col,y,From) :
	  move(r,y,From,To) :
	  scarica(r,y)))).
    

%%% utility
%%% esegui
esegui(P,Alist) :-
	do(P,s0,S), tolist(S,Alist).

tolist(s0,[]).
tolist(do(A,S),Alist) :-
	tolist(S,Tmp),
	append(Tmp,[A],Alist).

printlist([]).
printlist([X|Rest]) :-
	writeln(X),printlist(Rest).

esegui(P) :- esegui(P,List), printlist(List).

%%% Sintassi del Golog
%%% sequenze di azioni: A1 : A2
%%% test: ?(Formula)
%%%         congiunzione: F & G
%%%         disgiunzione: F v G
%%%         implicazione: F => G
%%%         doppia implicazione: F <=> G
%%%         negazione: - F
%%%         quantificatore universale: all(V,F)
%%%         quantificatore esistenziale: some(V,F)
%%% scelta non deterministica di due azioni: A1 # A2
%%% if-then-else: if(Cond,A1,A2)
%%% ciclo: while(Cond,A)
%%% scelta non deterministica dell'argomento di un'azione:
%%%             pi(x,A)
%%% procedure: proc(Testa,Corpo)
%%%          parametri della procedura: variabili prolog