/* accesseurs sur ligne et colonne*/
:-use_module(library(assoc)).

colonne(1,[A,_,_,_],A).
colonne(2,[_,A,_,_],A).
colonne(3,[_,_,A,_],A).
colonne(4,[_,_,_,A],A).

ligne(1,[A,_,_,_,_],A).
ligne(2,[_,A,_,_,_],A).
ligne(3,[_,_,A,_,_],A).
ligne(4,[_,_,_,A,_],A).
ligne(5,[_,_,_,_,A],A).


/* retourne le contenu "Contenu_case" de la case  
situé à la colonne "Col" et la ligne "Lig" du jeux en cours
"Contenu_jeu" */
 
case(Lig,Col,Conf,Contenu) :- 
    ligne(Lig,Conf,Ligne),
    colonne(Col,Ligne,Contenu).

changeContenuColonne(1,X,[_,B,C,D],[X,B,C,D]).
changeContenuColonne(2,X,[A,_,C,D],[A,X,C,D]).
changeContenuColonne(3,X,[A,B,_,D],[A,B,X,D]).
changeContenuColonne(4,X,[A,B,C,_],[A,B,C,X]).

changeContenuLigne(1,X,[_,B,C,D,E],[X,B,C,D,E]).
changeContenuLigne(2,X,[A,_,C,D,E],[A,X,C,D,E]).
changeContenuLigne(3,X,[A,B,_,D,E],[A,B,X,D,E]).
changeContenuLigne(4,X,[A,B,C,_,E],[A,B,C,X,E]).
changeContenuLigne(5,X,[A,B,C,D,_],[A,B,C,D,X]).

changeContenu(Conf1,Piece,Y,X,Conf2):-
    ligne(Y,Conf1,Ligne),
    changeContenuColonne(X,Piece,Ligne,Lignep),
    changeContenuLigne(Y,Lignep,Conf1,Conf2).
    

/*
init([
    [j1,r1,ro,j1],
    [ja,ro,ro,ja],
    [n1,b1,bl,n1],
    [no,bo,bo,no],
    [ma,vi,vi,ma]]).
*/

init([
    [j1,r1,ro,j1],
    [ja,ro,ro,ja],
    [j1,b1,bl,j1],
    [ja,bo,bo,ja],
    [bo,vi,vi,bo]]).


/*
final([
    [_,_,_,_],
    [_,_,_,_],
    [_,_,_,_],
    [_,_,_,_],
    [_,b1,bl,_]]).

*/
/*
final([
    [_,_,_,_],
    [_,_,_,_],
    [_,_,_,_],
    [_,j1,j1,_],
    [_,ja,ja,_]]).
*/

final([
    [_,_,_,_],
    [_,_,_,_],
    [_,_,_,_],
    [_,r1,ro,_],
    [_,ro,ro,_]]).

/* direction */
directionh(d,1).
directionh(g,-1).
directionv(h,-1).
directionv(b,1).



/*glissement rouge*/
/* vers la droite */ 
glissement(r1,d,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,r1),
    Ligp is Lig+1,
    Colp is Col+1,
    Colpp is Col+2,
    case(Lig,Colpp,Conf1,vi),
    case(Ligp,Colpp,Conf1,vi),
    changeContenu(Conf1,r1,Lig,Colp,Conf1a),
    changeContenu(Conf1a,ro,Lig,Colpp,Conf1b),
    changeContenu(Conf1b,vi,Lig,Col,Conf1c),
    changeContenu(Conf1c,ro,Ligp,Colpp,Conf1d),
    changeContenu(Conf1d,vi,Ligp,Col,Conf2).

/*vers la gauche */
glissement(r1,g,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,r1),
    Ligp is Lig+1,
    Colm is Col-1,
    Colp is Col+1,
    case(Lig,Colm,Conf1,vi),
    case(Ligp,Colm,Conf1,vi),
    changeContenu(Conf1,r1,Lig,Colm,Conf1a),
    changeContenu(Conf1a,ro,Lig,Col,Conf1b),
    changeContenu(Conf1b,vi,Lig,Colp,Conf1c),
    changeContenu(Conf1c,ro,Ligp,Colm,Conf1d),
    changeContenu(Conf1d,vi,Ligp,Colp,Conf2).


/* vers le bas */
glissement(r1,b,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,r1),
    Ligp is Lig+1,
    Colp is Col+1,
    Ligpp is Lig+2,
    case(Ligpp,Col,Conf1,vi),
    case(Ligpp,Colp,Conf1,vi),
    changeContenu(Conf1,r1,Ligp,Col,Conf1b),
    changeContenu(Conf1b,vi,Lig,Col,Conf1c),
    changeContenu(Conf1c,ro,Ligpp,Col,Conf1d),
    changeContenu(Conf1d,ro,Ligpp,Colp,Conf1e),
    changeContenu(Conf1e,vi,Lig,Colp,Conf2).


/* vers le haut */
glissement(r1,h,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,r1),
    Ligp is Lig+1,
    Colp is Col+1,
    Ligm is Lig-1,
    case(Ligm,Col,Conf1,vi),
    case(Ligm,Colp,Conf1,vi),
    changeContenu(Conf1,r1,Ligm,Col,Conf1a),
    changeContenu(Conf1a,ro,Ligm,Colp,Conf1b),
    changeContenu(Conf1b,vi,Ligp,Col,Conf1c),
    changeContenu(Conf1c,ro,Lig,Col,Conf1d),
    changeContenu(Conf1d,vi,Ligp,Colp,Conf2).





/* glissement noire , jaune  droite ou gauche */
glissement(Pc1,D,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,Pc1),
    ((Pc1= n1, Pc2= no); (Pc1= j1, Pc2= ja)), 
    directionh(D,Delta),
    Ligp is Lig+1,
    Colp is Col+Delta,
    case(Lig,Colp,Conf1,vi),
    case(Ligp,Colp,Conf1,vi),
    changeContenu(Conf1,Pc1,Lig,Colp,Conf1a),
    changeContenu(Conf1a,Pc2,Ligp,Colp,Conf1b),
    changeContenu(Conf1b,vi,Lig,Col,Conf1c),
    changeContenu(Conf1c,vi,Ligp,Col,Conf2).




/* vers le bas */
glissement(Pc1,b,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,Pc1),
    ((Pc1= n1, Pc2= no); (Pc1= j1, Pc2= ja)), 
    Ligp is Lig+1,
    Ligpp is Lig+2,
    case(Ligpp,Col,Conf1,vi),
    changeContenu(Conf1,Pc1,Ligp,Col,Conf1a),
    changeContenu(Conf1a,Pc2,Ligpp,Col,Conf1b),
    changeContenu(Conf1b,vi,Lig,Col,Conf2).

/* vers le haut */
glissement(Pc1,h,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,Pc1),
    ((Pc1= n1, Pc2= no); (Pc1= j1, Pc2= ja)), 
    Ligp is Lig+1,
    Ligm is Lig-1,
    case(Ligm,Col,Conf1,vi),
    changeContenu(Conf1,Pc1,Ligm,Col,Conf1a),
    changeContenu(Conf1a,Pc2,Lig,Col,Conf1b),
    changeContenu(Conf1b,vi,Ligp,Col,Conf2).

/* blanc, à droite */
glissement(b1,d,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,b1),
    Colpp is Col+2,
    Colp is Col+1,
    case(Lig,Colpp,Conf1,vi),
    changeContenu(Conf1,b1,Lig,Colp,Conf1a),
    changeContenu(Conf1a,bl,Lig,Colpp,Conf1b),
    changeContenu(Conf1b,vi,Lig,Col,Conf2).

/* blanc, à gauche */
glissement(b1,g,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,b1),
    Colm is Col-1,
    Colp is Col+1,
    case(Lig,Colm,Conf1,vi),
    changeContenu(Conf1,b1,Lig,Colm,Conf1a),
    changeContenu(Conf1a,bl,Lig,Col,Conf1b),
    changeContenu(Conf1b,vi,Lig,Colp,Conf2).


/* blanc, haut ou  bas */
glissement(b1,D,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,b1),
    directionv(D,Delta),
    Ligp is Lig+Delta,
    Colp is Col+1,
    case(Ligp,Col,Conf1,vi),
    case(Ligp,Colp,Conf1,vi),
    changeContenu(Conf1,b1,Ligp,Col,Conf1a),
    changeContenu(Conf1a,bl,Ligp,Colp,Conf1b),
    changeContenu(Conf1b,vi,Lig,Col,Conf1c),
    changeContenu(Conf1c,vi,Lig,Colp,Conf2).

/* bois ou marron, gauche ou droite*/
    glissement(PC,D,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,PC),
    (PC = ma; PC = bo),
    directionh(D,Delta),
    Colp is Col+Delta,
    case(Lig,Colp,Conf1,vi),
    changeContenu(Conf1,PC,Lig,Colp,Conf1a),
    changeContenu(Conf1a,vi,Lig,Col,Conf2).


/* bois ou marron, haut ou bas*/
glissement(PC,D,Conf1,Conf2,Lig,Col):-
    case(Lig,Col,Conf1,PC),
    (PC = ma; PC = bo),
    directionv(D,Delta),
    Ligp is Lig+Delta,
    case(Ligp,Col,Conf1,vi),
    changeContenu(Conf1,PC,Ligp,Col,Conf1a),
    changeContenu(Conf1a,vi,Lig,Col,Conf2).

gl_time(P,D,Confa,Confb,Lig,Col):-
    get_time(T2),
    glissement(P,D,Confa,Confb,Lig,Col),
    get_time(T3),
    DT3 is T3 - T2,
    write('depl : '),writeln(DT3).


retour(L,Col,d,L,Cp,g):-
    Col is Cp-1.
retour(L,Col,g,L,Cp,d):-
    Col is Cp+1.
retour(Lig,C,h,Lp,C,b):-
    Lig is Lp+1.
    retour(Lig,C,b,Lp,C,h):-
    Lig is Lp-1.


gl_ok(_,P,D,Confa,Confb,Lig,Col,[]):-
    glissement(P,D,Confa,Confb,Lig,Col).
gl_ok(_,P,D,Confa,Confb,Lig,Col,[((Lp,Cp),Dp)|_]):-
    glissement(P,D,Confa,Confb,Lig,Col),
    not(retour(Lig,Col,D,Lp,Cp,Dp)).
    
    
    
    
/* Tous les successeurs d une configuration */
successeurs(Omis,Confa-Chemins,L):-
    findall(
	Confb-[((Lig,Col),D)|Chemins],
	gl_ok(Omis,_,D,Confa,Confb,Lig,Col,Chemins),
	/*glissement(_,D,Confa,Confb,Lig,Col),*/
	L).


successeurs_liste(L,Visites,Sl):-
    /*write('Visites : '),writeln(Visites),
    maplist(filtre_conf,Visites,V2),
    write('V2 :'),writeln(V2),*/
    maplist(successeurs(_),L,Lp),
    flatten(Lp,Lpp),
    list_to_assoc(Lpp,A),
    assoc_to_list(A,Sl).



/* regarde si le premier parametre appartient 
     à la liste donné en second parametre. Si c est le cas,
    retourne le chemin */


filtre_confa(X-_,X).
filtre_confb(X-_,Y):-
    equiv(X,Y).

equiv([[A1,A2,A3,A4],
       [B1,B2,B3,B4],
       [C1,C2,C3,C4],
       [D1,D2,D3,D4],
       [E1,E2,E3,E4]],
      [[A4,A3,A2,A1],
       [B4,B3,B2,B1],
       [C4,C3,C2,C1],
       [D4,D3,D2,D1],
       [E4,E3,E2,E1]]).
    

appartient(Conf1-_,[Conf1-_|_]):-!.
/*appartient(Conf1-_,[Conf1b-_|_]):-
    equiv(Conf1,Conf1b),
    !.*/
appartient(Conf1-C,[_|L]):-
    appartient(Conf1-C,L).


polit([],_,[]).
polit([Conf-_|L1],L2,Res):-
    member(Conf,L2),
    /*appartient(El,L2),*/
    !,
    polit(L1,L2,Res).
polit([El|L1],L2,[El|Res]):-
    polit(L1,L2,Res).






but([Conf-Chemin|_],Chemin):-final(Conf),!.
but([_|L],Chemin):-but(L,Chemin).


largeur(Atraiter,_,_,Res):-
    but(Atraiter,Res),
    !.
largeur(Atraiter,Visites,C,Res):-
    Cp is C+1,
    write('boucle'), writeln(C),
    maplist(filtre_confa,Atraiter,V1),
    maplist(filtre_confb,Atraiter,V2),
    append(V1,V2,V3),
    append(V3,Visites,Omis),
    successeurs_liste(Atraiter,_,Succ),
    polit(Succ,Omis,Atraiter2),
    length(Succ,SL),
    length(Atraiter2,OL),
    writeln(SL),
    writeln(OL),
    largeur(Atraiter2,Omis,Cp,Res).


    
resoud(_):-
    get_time(T0),
    init(X),
    largeur([X-[]],[],0,Res),
    writeln(Res),
    get_time(T1),
    DT1 is T1 - T0,
    write('duree : '),writeln(DT1).


