/*
Consult the file left.pro or the file right.pro
before you start testing your program.
The file left.pro includes a KB with statements
about the left scene (right.pro - about the right scene)
given in your assignment.
*/

chain(C,road).
chain(C,river).
chain(C,shore).
region(R,land).
region(R,water).

/* use the helping predicate bothRivers(X,Y) to formulate the constraint */
crossListValid([]).
crossListValid([H | T]) :- H=[L1,L2], not bothRivers(L1,L2),
                           /*  other conditions ... */ 
                           crossListValid(T).
bothRivers(L1,L2) :- L1=river, L2=river.

/* Write here your implementation for all other constraints. You can 
   introduce new helping predicates and use predicates defined in class. */
%
% besideListValid(BesideListOfLabels) :-
%                 
% joinListValid(JoinListOfLabels) :-
%
/* In the following predicate, the first argument is the list of 
   tentative labels chosen to all four chains */
% loopListValid([ChainLab1,ChainLab2,ChainLab3,ChainLab4], LoopListOfLabels) :- 
%
% listInsideOutsideValid(InLabels,OutLabels) :-
%
 

/* -----------------  USE THIS PROGRAM IN THE PART 3 OF YOUR ASSIGNMENT --------- */

solve([CL1,CL2,CL3,CL4,RL1,RL2,RL3]) :-
        chain(c1,CL1), chain(c2,CL2), chain(c3,CL3), chain(c4,CL4),
        region(r1,RL1), region(r2,RL2), region(r3,RL3),
        crosslist(C), convertToLabels(C,[CL1,CL2,CL3,CL4,RL1,RL2,RL3],CLabels),
        crossListValid(CLabels),
        besidelist(B), convertToLabels(B,[CL1,CL2,CL3,CL4,RL1,RL2,RL3],BLabels),
        besideListValid(BLabels),
        joinlist(J), convertToLabels(J,[CL1,CL2,CL3,CL4,RL1,RL2,RL3],JLabels),
        joinListValid(JLabels),
        looplist(L), convertToLabels(L,[CL1,CL2,CL3,CL4,RL1,RL2,RL3],LLabels),
        loopListValid([CL1,CL2,CL3,CL4], LLabels),
        insidelist(In), convertToLabels(In,[CL1,CL2,CL3,CL4,RL1,RL2,RL3],InLabels),
        outsidelist(Out), convertToLabels(Out,[CL1,CL2,CL3,CL4,RL1,RL2,RL3],OutLabels),
        listInsideOutsideValid(InLabels,OutLabels).

/*      Note that you have to implement yourself the predicate "myprint"    */

print_solution :- 
              solve([CL1,CL2,CL3,CL4,RL1,RL2,RL3]),
              nl, write('  The following interpretation of scene is valid: '), nl,
              myprint([CL1,CL2,CL3,CL4,RL1,RL2,RL3]).

/*
 The predicate 
    convertToLabels(GivenList, [Ch1,Ch2,Ch3,Ch4,Reg1,Reg2,Reg3], ListToBeComputed)
  is true if for a given list of chains and regions, and the list of labels 
  for all chains and regions on the map, ListToBeComputed is the list of labels
  assigned to those chains and regions which occur in GivenList.
  For example, the query 
  ? - convertToLabels([[c1,r2],[c4,r3]], [road,shore,shore,river, water,land,water], ListToBeComputed)
  succeeds and finds that ListToBeComputed=[[road,land],[river,water]], because
  chain c1 is labeled as a road, chain c4 is labeled as a river, 
  regions r2 is labeled as a land, region r3 is labeled as a water.    
*/
convertToLabels(ListOfPairs, [CL1,CL2,CL3,CL4,RL1,RL2,RL3], Labels) :-
     substitute(c1,CL1,ListOfPairs,CLabels1),
     substitute(c2,CL2,CLabels1,CLabels2),
     substitute(c3,CL3,CLabels2,CLabels3),
     substitute(c4,CL4,CLabels3,CLabels4),
     substitute(r1,RL1,CLabels4,RLabels1),
     substitute(r2,RL2,RLabels1,RLabels2),
     substitute(r3,RL3,RLabels2,Labels).

/* The predicate  substitute(X,Y,List1,List2) is true if List2 is the list of 
   pairs (i.e., each pair is the list of two elements) such that all occurrences of X
   in the first or in the second element of any pair in the List1 are raplaced by Y.
   To do the actual replacement this predicate calls two helping predicates.
*/
substitute(X,Y,ListOfPairs1,ListOfPairs2) :-
     replaceAll1(X,Y,ListOfPairs1,ListTemp),
     replaceAll2(X,Y,ListTemp,ListOfPairs2).

/* The FIRST predicate   replaceAll1(X,Y,ListOfPairs1,ListOfPairs2)  is true 
   if the second list is the result of replacing all occurrences X in 
   *the FIRST element* of any pair from the first list by Y.
   The SECOND predicate  replaceAll2(X,Y,ListOfPairs1,ListOfPairs2) is true 
   if the second list is the result of replacing all occurrences X in 
   *the SECOND element* of any pair from the first list by Y.  
   You can find an example of a similar (but simpler) predicate in the handout.
*/
replaceAll1(X, Y, [ ], [ ]).
replaceAll1(X, Y, [[X,W] | L1], [[Y,W] | L2]) :- replaceAll1(X, Y, L1, L2).
replaceAll1(X, Y, [[Z,Q] | L1], [[Z,Q] | L2]) :- not X = Z, replaceAll1(X, Y, L1, L2).

replaceAll2(X, Y, [ ], [ ]).
replaceAll2(X, Y, [[W,X] | L1], [[W,Y] | L2]) :- replaceAll2(X, Y, L1, L2).
replaceAll2(X, Y, [[Q,Z] | L1], [[Q,Z] | L2]) :- not X = Z, replaceAll2(X, Y, L1, L2).

member(X, [X | List]).
member(X, [ _ | List] ) :-  member(X,List).
