%% file con correzione rispetto alla versione vista in aula
%% l'errore era nell'assioma dello stato successore per holds
%% segnalato piu' in basso
%% Il programma e' stato anche completato.

%%%%% definizioni necessarie per la rappresentazione
%% di un dominio   

%%%%%%%%%%%%%%% direttive iniziali

:- [golog_swi].

%%% direttive discontiguous per i fluenti
%%% esempio
:- discontiguous onfloor/2, inbox/3, holds/3.

%%%%%%%%%%% dichiarazione delle azioni primitive
primitive_action(raccogli(_,_)).
primitive_action(lascia(_,_)).
primitive_action(metti(_,_,_)).
primitive_action(togli(_,_,_)).

%%%%%% Restore suppressed situation arguments.
%% (un fatto per ogni fluente).
restoreSitArg(onfloor(X),S,onfloor(X,S)).
restoreSitArg(inbox(X,Y),S,inbox(X,Y,S)).
restoreSitArg(holds(X,Y),S,holds(X,Y,S)).

%%%%%%% Action precondition axioms
poss(raccogli(R,X),S) :-
	robot(R), oggetto(X), 
	onfloor(X,S),
	\+ holds(R,_,S).

poss(lascia(R,X),S) :-
	robot(R), oggetto(X),
	holds(R,X,S).

poss(metti(R,X,Y),S) :-
	robot(R), oggetto(X), box(Y),
	holds(R,X,S).

poss(togli(R,X,Y),S) :-
	robot(R), oggetto(X), box(Y),
	inbox(X,Y,S),
	\+ holds(R,_,S).

%%%%%%% Successor state axioms
onfloor(X,do(A,S)) :-
	A=lascia(_,X) ;
	onfloor(X,S),
	\+ A=raccogli(_,X).

inbox(X,Y,do(A,S)) :-
	A = metti(_,X,Y) ;
	inbox(X,Y,S), \+ A = togli(_,X,Y).

%% l'errore era qui: nella parte G- c'era una virgola
%% invece di un punto e virgola
holds(R,X,do(A,S)) :-
	A= raccogli(R,X) ;
	holds(R,X,S), \+ (A=lascia(R,X) ; A=metti(R,X,_)).


%%%%%%% definizione di eventuali predicati statici
robot(pippo). robot(pluto).
oggetto(X) :- member(X,[a,b,c,d,e]).
box(X) :- member(X,[1,2,3]).
% situazione iniziale
onfloor(X,s0) :- oggetto(X).


%% procedura per inscatolare tutti gli oggetti
%% ha successo anche se all'inizio tutti gli oggetti sono
%% gia' in qualche scatola

%% sottoproc: il robot R mette in qualche scatola l'oggetto X
%% che sta sul pavimento
% fallisce se: X non sta pavimento, o R ha qualcosa in mano
% suggerita a lezione ma non usata
proc(putinbox(R,X),
     raccogli(R,X) : pi(y,metti(R,X,y))).

% tuttilasciano: tutti i robot che hanno che hanno qualche
% oggetto in mano lo mettono dentro qualche scatola
% non deve fallire mai.
proc(tuttilasciano,
     while(some(x,robot(x) & some(y,oggetto(y) & holds(x,y))),
	   pi(r,pi(x,pi(y,metti(r,x,y)))))).

% tuttiprendono: i robot prendono tutti un oggetto in mano
% finche' ci sono oggetti sul pavimento. Non fallisce mai.
proc(tuttiprendono,
     while(some(x,robot(x) & all(y,oggetto(y) => -holds(x,y))) &
	    some(x,onfloor(x)),
	   pi(r,pi(x,raccogli(r,x))))).

% imballa: fa si' che tutti gli oggetti vengano messi dentro
%% qualche scatola.
proc(imballa,
     tuttilasciano :
    star(tuttiprendono : tuttilasciano) :
    ?(all(x,oggetto(x) => - onfloor(x)))).

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

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).

