/* (By F.Barbanera)
% gt : goat
% cb : cabbage
% wf : wolf
% shp: sheperd 
%
% rbc(L1,L2):  river banks configuration, the left bank containing the characters in L1 and the right bank the characters in L2
%
% admSeq(L1,L2): admissible Sequences: L1 is a sequence (a list) of river banks configuration such that the reverse of L1 appended
%                to L2 takes from the initial configuration, rbc([gt,cb,wf,shp],[]), to the final one rbc([],[gt,cb,wf,shp]
%
% safeBoatmove(RBC1,RBC2): it is possible to go from the river banks configuration RBC1 to RBS2 by means 
%                          a safe move of two characters on the boat 
%
% admSeq(RCBlist1,RCBlist2): the reverse of RCBlist1 appended to RBClist2 form an admissible solution from the initial to the final configuration.
%                            Admissible solution do not admit repeated configurations. 
% 
%
% 
% The main not elegant point in the program is that configurations are pairs of lists. They should be actually sets.
% So equality up to permutations is needed in some points.
%
*/






solution(L) :- admSeq([rbc([gt,cb,wf,shp],[])],L1),

               L=[rbc([gt,cb,wf,shp],[])|L1].








admSeq([RBC1|L1],[RBC2|L2]) :- safeBoatmove(RBC1,RBC2),                              
                               \+ presentin(RBC2,L1),
                               admSeq([RBC2,RBC1|L1],L2).


admSeq([rbc([],L)|_],[]) :- permutation(L,[gt,cb,wf,shp]).




%  presentin(RBC,RBC-list) determines whether an RBC is in a RBC-list


presentin(rbc(L1,L2),RcbList) :- member(rbc(L3,L4),RcbList), permutation(L3,L1), permutation(L4,L2).

    



safeBoatmove(RBC1,RBC2) :-  boatmove(RBC1,RBC2),
                            \+ unsafe(RBC2).


unsafe(rbc(L1,L2)) :- member(cb,L1), member(gt,L1),\+member(shp,L1);
                      member(gt,L1), member(wf,L1),\+member(shp,L1);
                      member(cb,L2), member(gt,L2),\+member(shp,L2);
                      member(gt,L2), member(wf,L2),\+member(shp,L2).


                      
                                

boatmove(rbc(L1,L2),rbc(L3,L4)) :- select(shp,L1,Rest), select(X,Rest,L3),(L4=[shp,X|L2]);
                                   select(shp,L2,Rest), select(X,Rest,L4),(L3=[shp,X|L1]);
                                   select(shp,L1,L3),(L4=[shp|L2]);
                                   select(shp,L2,L4),(L3=[shp|L1]).



permutation([], []).
permutation(List, [Element | Permutation]) :- select(Element, List, Rest),
                                              permutation(Rest, Permutation).







%%%% Soluzione alternativa. %%%%%%%%%%%


/* File: goat.pl
   Title: The goat problem

   A farmer has to cross a river with a wolf, a goat and a cabbage.
   He has a boat, but in the boat he can take just one thing.
   He cannot let the goat alone with the wolf or the goat with the cabbage. It's obvious why.

   What is the solution?

   */
   /*
   We describe the problem as Nodes in a graph and the solution means to find a path from
   the initial node to the final node.
   state = node is graph

   state(farmer(Bank),goat(Bank),cabbage(Bank),wolf(Bank)).

   Bank can be left (s) or right (d).  
   */

   start:- find(D),writelist(D),fail.

   /* fail is used here in order to force the interpreter to serach 
      for all the possible solutions (otherwise, by writing
      simply 
      start:- find(D),writelist(D). 
      we should explicitely ask the interpreter
      to look for the next solution by means of the space bar.)
   */



   /* at the beginning All are on the same bank
   */

initial(state(farmer(s),goat(s),cabbage(s),wolf(s))).
   /* at the end they have all to be on the other bank
   */
final(state(farmer(d),goat(d),cabbage(d),wolf(d))).

   /* opposite bank. A possible alternative definition is:   
   opp(Bank1,Bank2):- (Bank1=s,Bank2=d);(Bank1=d,Bank2=s).
   */

opp(s,d).  
opp(d,s).

   /* a bad state is a state to be avoided
   in this case:
   Goat cannot be left alone with wolf or cabbage
   The bank where the farmer is (T) has to be opposite
   Where the goat is together with the wolf or the cabbage
   */

bad(state(farmer(T),goat(G),cabbage(C),wolf(W))):- 
   				(G=W,opp(T,G)); (G=C,opp(T,G)).

find(Path):- initial(S),rez(S,Path).

   /* Farmer takes goat */
from(state(farmer(T),goat(T),cabbage(C),wolf(W)),
     state(farmer(T1),goat(T1),cabbage(C),wolf(W))):-opp(T,T1). 

   /* Farmer takes cabbage */
from(state(farmer(T),goat(G),cabbage(T),wolf(W)),
     state(farmer(T1),goat(G),cabbage(T1),wolf(W))):-opp(T,T1). 

   /* Farmer takes wolf */
from(state(farmer(T),goat(G),cabbage(C),wolf(T)),
     state(farmer(T1),goat(G),cabbage(C),wolf(T1))):-opp(T,T1). 

   /* Farmer goes alone */
from(state(farmer(T),goat(G),cabbage(C),wolf(W)),
     state(farmer(T1),goat(G),cabbage(C),wolf(W))):-opp(T,T1). 

rez(State,Sol):- bkt(State,[],Sol).

bkt(State,Path,[State|Path]):- final(State).
bkt(State,Path,Sol):- from(State,N1), 
                      \+bad(N1),
		      \+member(N1,Path),                    
                      bkt(N1,[State|Path],Sol).


writelist([]):- write('\n').
writelist([X|L]):- write(X),write('\n'),writelist(L).
