:- use_module(library(clpfd)).
:- dynamic pos/1 .
:- dynamic cell/2.
visu :-
	retractall(pos(_)),

	% 9 X 9 --> 52 952 inferences, 0.02 CPU
	grille_2(Hauteur, Largeur, Conditions),

	% 11 X 11 --> 15 494 026 inferences, 3.41 CPU
	% grille_1(Hauteur, Largeur, Conditions),

	% 13 X 13 --> 628 443 inferences, 0.14 CPU
	%  grille96(Hauteur, Largeur, Conditions),

	% 13 X 13 --> 1 219 359 inferences, 0.27 CPU
	% grille12(Hauteur, Largeur, Conditions),

	% 17 X 17 force 8 --> 17 544 232 inferences, 3.73 CPU
	% grille30(Hauteur, Largeur, Conditions),

	% 17 X 17 force 6 --> 10 549 305 inferences, 2.30 CPU
        % grille31(Hauteur, Largeur, Conditions),

	tmp_file(toto, Tmp),

	tell(Tmp),

	kuromasu(Hauteur, Largeur, Conditions, _Soluce),

	told,

	retractall(cell(_,_)),

	NN is Hauteur * Largeur,
	length(L, NN),
	maplist(init_box, L),
	new(D, window('Kuromasu')),
	DX is Largeur * 40 + 20,
	DY is Hauteur * 40 + 50,
	send(D, size, new(_, size(DX,DY))),

	affiche(D, L, Largeur, 0, 0),

	get(@display, size, size(H, W)),
	H1 is H / 2,
	W1 is W / 2,
	send(D, open_centered, point(H1, W1)),

	chain_list(LX, L),
	consult(Tmp),
	bagof([X,Y], cell(X,Y), LEV),

	chain_list(LEVX, LEV),
	new(G, gestionnaire(D, LX, LEVX)),
	send(D, done_message, and(message(@prolog, 'delete_object', G),
				  message(@receiver,destroy))).


% il faut arréter les timers avant de détruire la fenetre
delete_object(G) :-
	send(G?mytimer, stop).



init_box(X) :-
    new(X, box(40,40)),
    send(X, fill_pattern, colour(@default, 0, 65535, 0)).

affiche(_D, [], _, _, _).

affiche(D, T, Nb, L, Nb) :-
	L1 is L + 1,
	affiche(D, T, Nb, L1, 0).

affiche(D, [H | T], Nb, L, C) :-
	X is 40 * C + 10,
	Y is 40 * L + 40,
	send(D, display, H, point(X, Y)),
	C1 is C + 1,
	affiche(D, T, Nb, L, C1).


	% affiche_solution(Hauteur, Largeur, Soluce).

% Donnees est la liste des conditions enoncées sous la forme case(Lig, Col, N),
% N etant le nombre des cases blanches adjacentes (y compris cette case)
% Solution est la grille solution
kuromasu(Hauteur, Largeur, Donnees, Solution) :-
	%creation de la solution
	Len #= Hauteur * Largeur,
	length(Solution, Len),
	% L sera utilisee pour la recherche de connexite des cases blanches
	length(L, Len),

	% les cases ont deux valeurs possibles
	% noires -> 0
	% blanches -> 1
	Solution ins 0..1,

	%Pour l'animation
	retractall(pos(_)),
	assert(pos(0)),
	maplist(animation, Solution),

	%Etude des données
	% on fixe les visibliltés des cases blanches déclarées et
	% on s'assure que lorsqu'on place une case noire,
	% que d'autres cases noires ne sont pas adjacentes
	maplist(conditions(Solution, Hauteur, Largeur), Donnees),

	% ici les contraintes de visibilite des cases blanches
	% et de non connexité des cases noires sont respectees
	% S'il reste des cellules libres elles doivent être blanchies

	maplist(colorie_blanc(1), Solution),

	% On vérifie maintenant que toutes les cellules blanches sont connectées
	explore_grille(Solution, Hauteur, Largeur, L),

	% Il faut que toutes les variables libres de L soient noircies
	maplist(colorie(0),L),

	% le total des cases blanches dans les deux listes doit être le même
	sum(L, #=, TT),
	sum(Solution, #=, TT),

	solve(Solution).


% obtention des solutions
solve(Solution) :-
	labeling([], Solution).

% coloriage des grilles
% Ici la couleur n'existe pas encore
colorie(Couleur, Cell) :-
	var(Cell),Cell #= Couleur.

% La elle existe déjà
colorie(_Couleur, Cell) :-
	nonvar(Cell).

% coloriage des grilles
% Ici la couleur n'existe pas encore
colorie_blanc(Couleur, Cell) :-
	var(Cell),
	Cell #= Couleur.

% La elle existe déjà
colorie_blanc(_Couleur, Cell) :-
	nonvar(Cell).

% pour l'animaton des solutions
animation(Cell) :-
	retract(pos(P)),
	P1 is P + 1,
	assert(pos(P1)),
	freeze(Cell, kuromasu_value_truth(P,Cell)).


% les animations
kuromasu_value_truth(P,0) :-
	format('cell(~w, 0).~n', [P]).


kuromasu_value_truth(P,1) :-
	format('cell(~w, 1).~n', [P]).


kuromasu_value_truth(P,_) :-
	format('cell(~w, 2).~n', [P]), false.





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
conditions(Solution, Hauteur, Largeur, case(L, C, N)) :-

	  % Calcul de la position de la case dans la liste
	  P #= Largeur * L + C,
	  % Affectation de la valeur 1 à cette case.
	  V #= 1,
	  nth0(P, Solution, V),

	  % On fait la somme des nombres sur la ligne et la colonne
	  % autour de la case Cette somme est égale à N-1
	  ValMax #=  N - 1,

	  V1 #= 0,
	  C1 #= C - 1,
	  somme_ligne_gauche(Solution, Hauteur, Largeur, L, C1, V1,  Val1, ValMax),

	  L1 #= L - 1,
	  ValMax1 #= ValMax - Val1,
	  ValMax1 #>= 0,
	  somme_colonne_haut(Solution, Hauteur, Largeur, L1, C, V1, Val2, ValMax1),

	  ValMax2 #= ValMax1 - Val2,
	  ValMax2 #>= 0,
	  C2 #= C + 1,
	  somme_ligne_droite(Solution, Hauteur,  Largeur, L, C2, V1, Val3, ValMax2),

	  ValMax3 #= ValMax2 - Val3,
	  ValMax3 #>= 0,
	  L2 #= L+1,
	  somme_colonne_bas(Solution, Hauteur, Largeur, L2, C, V1, Val4, ValMax3),

	  Val1+Val2+Val3+Val4 #= ValMax.

% on rencontre un case blanche on continue
somme_ligne_gauche(Solution, Hauteur, Largeur, L, C, Val, ValF, ValMax) :-
	C #> -1,
	Val #< ValMax,
	P #= Largeur * L + C,
	V #= 1,
	nth0(P, Solution, V),

	Val1 #= Val + 1,
	C1 #= C-1,
	somme_ligne_gauche(Solution, Hauteur, Largeur, L, C1, Val1, ValF, ValMax).

% ici on rencontre une case noire, ou on en pose une
% on arrete et on s'assure que les cases adjacentes sont blanches
somme_ligne_gauche(Solution, Hauteur, Largeur, L, C, ValF, ValF, ValMax) :-
	C #> -1,
	ValF #< ValMax,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	case_haut_blanc(Solution, Largeur, L, C),
	case_gauche_blanc(Solution, Largeur, L, C),
	case_bas_blanc(Solution, Hauteur, Largeur, L, C).



% ici on a atteint le maximum possible
% on met la case en noir et on force les cases adjacentes à blanc
somme_ligne_gauche(Solution, Hauteur, Largeur, L, C, ValMax, ValMax, ValMax) :-
	C #> -1,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	% on vient de la droite, on force les cases adjacentes à blanc
	case_haut_blanc(Solution, Largeur, L, C),
	case_gauche_blanc(Solution, Largeur, L, C),
	case_bas_blanc(Solution, Hauteur, Largeur, L, C).

% ici on sort donc on arrête
somme_ligne_gauche(_Solution, _Hauteur, _Largeur, _L, C, ValF, ValF, _ValMax) :-
	C #=< -1.


% on rencontre un case blanche on continue
somme_ligne_droite(Solution, Hauteur, Largeur, L, C, Val, ValF, ValMax) :-
	C #< Largeur,
	Val #< ValMax,
	P #= Largeur * L + C,
	V #= 1,
	nth0(P, Solution, V),

	Val1 #= Val + 1,
	C1 #= C+1,
	somme_ligne_droite(Solution, Hauteur, Largeur, L, C1, Val1, ValF, ValMax).

% on rencontre une case noire, termine
somme_ligne_droite(Solution, Hauteur, Largeur, L, C, ValF, ValF, ValMax) :-
	C #< Largeur,
	ValF #< ValMax,
	P #= Largeur * L + C,
	nth0(P, Solution, V),
	V #= 0,

	case_haut_blanc(Solution, Largeur, L, C),
	case_droite_blanc(Solution, Largeur, L, C),
	case_bas_blanc(Solution, Hauteur, Largeur, L, C).


% ici on a atteint le maximum possible
% on noircit la case et on force à blanc les cases adjacentes
somme_ligne_droite(Solution, Hauteur, Largeur, L, C, ValMax, ValMax, ValMax) :-
	C #< Largeur,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	% on vient de la gauche, on force les cases adjacentes à blanc
	case_haut_blanc(Solution, Largeur, L, C),
	case_droite_blanc(Solution, Largeur, L, C),
	case_bas_blanc(Solution, Hauteur, Largeur, L, C).


% on sort de la grille
somme_ligne_droite(_Solution, _Hauteur, Largeur, _L, C, ValF, ValF, _ValMax) :-
	C #>= Largeur.


% on rencontre une case blanche on continue
somme_colonne_haut(Solution, Hauteur, Largeur, L, C, Val, ValF, ValMax) :-
	L #> -1,
	Val #< ValMax,
	P #= Largeur * L + C,
	V #= 1,
	nth0(P, Solution, V),

	Val1 #= Val + 1,
	L1 #= L-1,
	somme_colonne_haut(Solution, Hauteur, Largeur, L1, C, Val1, ValF, ValMax).

% on rencontre une case noire, on s'arrête
somme_colonne_haut(Solution, _Hauteur, Largeur, L, C, ValF, ValF, ValMax) :-
	L #> -1,
	ValF #< ValMax,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	case_haut_blanc(Solution, Largeur, L, C),
	case_gauche_blanc(Solution, Largeur, L, C),
	case_droite_blanc(Solution, Largeur, L, C).


% on a atteint le maximum
% on noircit la case, si pas possible, echec
somme_colonne_haut(Solution, _Hauteur, Largeur, L, C, ValMax, ValMax, ValMax) :-
	L #> -1,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	% on vient du bas, on force les cases adjacentes à blanc
	case_haut_blanc(Solution, Largeur, L, C),
	case_gauche_blanc(Solution, Largeur, L, C),
	case_droite_blanc(Solution, Largeur, L, C).

% on sort de la grille
somme_colonne_haut(_Solution, _Hauteur, _Largeur, L, _C, ValF, ValF, _ValMax) :-
	L #=< -1.

% on rencontre une case blanche, on continue
somme_colonne_bas(Solution, Hauteur, Largeur, L, C, Val, ValF, ValMax) :-
	L #< Hauteur,
	Val #< ValMax,
	P #= Largeur * L + C,
	V #= 1,
	nth0(P, Solution, V),

	Val1 #= Val + 1,
	L1 #= L+1,
	somme_colonne_bas(Solution, Hauteur, Largeur, L1, C, Val1, ValF, ValMax).

% ici on rencontre une case noire on arrête
somme_colonne_bas(Solution, Hauteur, Largeur, L, C, ValF, ValF, ValMax) :-
	L #< Hauteur,
	ValF #< ValMax,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	case_bas_blanc(Solution, Hauteur, Largeur, L, C),
	case_gauche_blanc(Solution, Largeur, L, C),
	case_droite_blanc(Solution, Largeur, L, C).



% ici on a atteint le maximum on noircit la case
% si pas possible, echec
somme_colonne_bas(Solution, Hauteur, Largeur, L, C, ValMax, ValMax, ValMax) :-
	L #< Hauteur,
	P #= Largeur * L + C,
	V #= 0,
	nth0(P, Solution, V),

	% on vient du haut on met les cases adjacentes en blanc
	case_bas_blanc(Solution, Hauteur, Largeur, L, C),
	case_gauche_blanc(Solution, Largeur, L, C),
	case_droite_blanc(Solution, Largeur, L, C).

% ici on sort de la grille
somme_colonne_bas(_Solution, Hauteur, _Largeur, L, _C, ValF, ValF, _ValMax) :-
	L #>= Hauteur.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% On est sur la case (L, C), on regarde celle du dessus (L-1, C)
case_haut_blanc(_Solution, _Largeur, 0, _C).
case_haut_blanc(Solution, Largeur, L, C) :-
	L #> 0,
	P #= (L-1) * Largeur + C,
	V #= 1,

	nth0(P, Solution, V).



% On est sur la case (L, C), on regarde celle de gauche (L, C-1)
case_gauche_blanc(_Solution, _Largeur, _L, 0).
case_gauche_blanc(Solution, Largeur, L, C) :-
	C #> 0,
	P #= L * Largeur + C - 1,
	V #= 1,

	nth0(P, Solution, V).


% On est sur la case (L, C), on regarde celle de dessous (L+1, C)
case_bas_blanc(_Solution, Hauteur, _Largeur, L, _C):-
	L #= Hauteur - 1.

case_bas_blanc(Solution, Hauteur, Largeur, L, C):-
	L1 #= L+1,
	L1 #< Hauteur,
	P #= L1 * Largeur + C,
	V #= 1,

	nth0(P, Solution, V).


% On est sur la case (L, C), on regarde celle de droite (L, C+1)
case_droite_blanc(_Solution, Largeur, _L, C):-
	C #= Largeur - 1.

case_droite_blanc(Solution, Largeur, L, C):-
	C1 #= C+1,
	C1 #< Largeur,
	P #= L * Largeur + C1,
	V #= 1,

	nth0(P, Solution, V).





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Parcours des cases blanches
% On est sur qu'il n'y a pas deux cases noires consécutives
%

explore_grille([H | T], Hauteur, Largeur, [H |L ]) :-
	H #= 1,
	explore([H | T], Hauteur, Largeur, [H | L], 0, 0).
explore_grille([H | T], Hauteur, Largeur, [H | L]) :-
	H #= 0,
	explore([H | T], Hauteur, Largeur, [H | L], 0, 1).

% ici la case courante est un 1
explore(Src, Hauteur, Largeur, But, L, C) :-
	% on explore dans les 4 directions,
	explore_haut(Src, Hauteur, Largeur, But, L, C),
	explore_droite(Src, Hauteur, Largeur, But, L, C),
	explore_bas(Src, Hauteur, Largeur, But, L, C),
	explore_gauche(Src, Hauteur, Largeur, But, L, C).

explore_haut(Src, Hauteur, Largeur, But, L, C) :-
	L1 #= L - 1,
	L1 #> -1,
	P #= L1 * Largeur + C,
	nth0(P, Src, V),
	V #= 1,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1,
	explore(Src, Hauteur, Largeur, But, L1, C).

explore_haut(_Src, _Hauteur, Largeur, But, L, C) :-
	L1 #= L - 1,
	L1 #> -1,
	P #= L1 * Largeur + C,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	nonvar(V1).

explore_haut(Src, _Hauteur, Largeur, But, L, C) :-
	L1 #= L - 1,
	L1 #> -1,
	P #= L1 * Largeur + C,
	nth0(P, Src, V),
	V #= 0,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1	.

explore_haut(_Src, _Hauteur, _Largeur, _But, L, _C):-
	L #=< 0.


explore_droite(Src, Hauteur, Largeur, But, L, C) :-
	C1 #= C + 1,
	C1 #< Largeur,
	P #= L * Largeur + C1,
	nth0(P, Src, V),
	V #= 1,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1,
	explore(Src, Hauteur, Largeur, But, L, C1).


explore_droite(_Src, _Hauteur, Largeur, But, L, C) :-
	C1 #= C + 1,
	C1 #< Largeur,
	P #= L * Largeur + C1,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	nonvar(V1).

explore_droite(Src, _Hauteur, Largeur, But, L, C) :-
	C1 #= C + 1,
	C1 #< Largeur,
	P #= L * Largeur + C1,
	nth0(P, Src, V),
	V #= 0,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1.


explore_droite(_Src, _Hauteur, Largeur, _But, _L, C) :-
	C #>= Largeur - 1.

explore_bas(Src, Hauteur, Largeur, But, L, C) :-
	L1 #= L + 1,
	L1 #< Hauteur,
	P #= L1 * Largeur + C,
	nth0(P, Src, V),
	V #= 1,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1,
	explore(Src, Hauteur, Largeur, But, L1, C).



explore_bas(_Src, Hauteur, Largeur, But, L, C) :-
	L1 #= L + 1,
	L1 #< Hauteur,
	P #= L1 * Largeur + C,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	nonvar(V1).

explore_bas(Src, Hauteur, Largeur, But, L, C) :-
	L1 #= L + 1,
	L1 #< Hauteur,
	P #= L1 * Largeur + C,
	nth0(P, Src, V),
	V #= 0,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1.


explore_bas(_Src, Hauteur, _Largeur,  _But, L, _C) :-
	L #>= Hauteur - 1.

explore_gauche(Src, Hauteur, Largeur, But, L, C) :-
	C1 #= C - 1,
	C1 #> -1,
	P #= L * Largeur + C1,
	nth0(P, Src, V),
	V #= 1,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1,
	explore(Src, Hauteur, Largeur, But, L, C1).


explore_gauche(_Src, _Hauteur, Largeur, But, L, C) :-
	C1 #= C - 1,
	C1 #> -1,
	P #= L * Largeur + C1,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	nonvar(V1).

explore_gauche(Src, _Hauteur, Largeur, But, L, C) :-
	C1 #= C - 1,
	C1 #> -1,
	P #= L * Largeur + C1,
	nth0(P, Src, V),
	V #= 0,
	nth0(P, But, V1),
	% si V1 est libre, c'est la première fois qu' on passe
	var(V1),
	V #= V1.


explore_gauche(_Src, _Hauteur, _Largeur, _But, _L, C) :-
	C #=< 0.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
affiche_solution(Hauteur, Largeur, Solution) :-
	new(D, window('Kuromasu')),
	DX is Largeur * 40 + 20,
	DY is Hauteur * 40 + 20,
	send(D, size, new(_, size(DX,DY))),
	send(D, open),
	affiche_solution(D, Solution, Largeur, 0, 0).

%affiche_solution(Fenetre,
%               Solution,
%		Largeur,
%               LigneCourante,
%               CaractereCourant)
affiche_solution(_D, [], _, _, _) :- !.

affiche_solution(D, Solution, Largeur, L, Largeur) :-
	L1 is L+1,
	affiche_solution(D, Solution, Largeur, L1, 0).

affiche_solution(D, [H | T], Largeur, L, C) :-
	new(B, box(40,40)),
       (   H = 0,  send(B, fill_pattern,  colour(@default, 0, 0, 0)); true),
	X is 40 * C + 10,
	Y is 40 * L + 10,
	send(D, display, B, point(X,Y)),
	C1 is C+1,
	affiche_solution(D, T, Largeur, L, C1).


grille96(13, 13, Conditions) :-
	Conditions = [case(  0,  2,  3),
		      case(  0,  6,  6),
		      case(  0,  8,  8),
		      case(  0,	10,  4),
		      case(  1,  1,  5),
		      case(  1,  3, 11),
		      case(  1,	 4,  3),
		      case(  1,  7,  6),
		      case(  1,	11,  6),
		      case(  1, 12,  4),
		      case(  2,  2, 16),
		      case(  3,  8, 12),
		      case(  4,  4,  5),
		      case(  4,  8,  8),
		      case(  5,  1,  4),
		      case(  5,	 5,  6),
		      case(  5,  7,  4),
		      case(  5,  9,  4),
		      case(  5, 10,  8),
		      case(  5, 12,  8),
		      case(  6,  0,  6),
		      case(  6,  2, 15),
		      case(  6,	 8,  8),
		      case(  7,  2, 21),
		      case(  7,  6, 19),
		      case(  7,	10, 19),
		      case(  8,  4,  7),
		      case(  8,	11, 10),
		      case(  9,  5,  5),
		      case(  9,  6,  8),
		      case(  9,  8,  4),
		      case(  9,	 9,  7),
		      case(  9,	11,  8),
		      case( 10,  2, 11),
     		      case( 11,  1,  7),
		      case( 12,  3,  9),
		      case( 12,  4, 10),
		      case( 12,  7, 10),
		      case( 12,	10,  6)].


grille12(13, 13, Conditions) :-
	Conditions = [case(  0,  3,  4),
		      case(  0,  6,  7),
		      case(  1,  2,  7),
		      case(  1,  4,  6),
		      case(  1,	 9,  4),
		      case(  1, 10,  4),
		      case(  2,  1, 12),
		      case(  2,  5, 11),
		      case(  2,  8,  5),
		      case(  2,	11,  7),
		      case(  3,  1,  8),
		      case(  3,  5,  9),
		      case(  3,  7,  6),
		      case(  3,	12,  3),
		      case(  4,  2,  7),
		      case(  4,  4,  6),
		      case(  4,	 8,  6),
		      case(  4, 11,  6),
		      case(  5,  3,  4),
		      case(  5,	 9,  3),
		      case(  5, 10,  8),
		      case(  6,  0,  4),
		      case(  6,	12,  6),
		      case(  7,  2,  7),
		      case(  7,  3, 11),
		      case(  7,  9,  4),
		      case(  8,  1,  2),
		      case(  8,  4,  6),
		      case(  8,  8,  3),
		      case(  8,	10,  6),
		      case(  9,  0,  3),
		      case(  9,  5,  4),
		      case(  9,  7,  7),
		      case(  9,	11,  4),
     		      case( 10,  1, 10),
		      case( 10,  4, 11),
		      case( 10,  7, 16),
		      case( 10,	11,  3),
     		      case( 11,  2,  7),
		      case( 11,  3,  9),
		      case( 11,  8,  4),
		      case( 11,	10,  2),
		      case( 12,  6,  7),
		      case( 12,	 9,  7)].

% force 6
grille31(17, 17, Conditions) :-
	Conditions = [case(  0,  1,  3),
		      case(  0, 15,  3),
		      case(  1,  0,  5),
		      case(  1,  3,  4),
		      case(  1,	13,  8),
		      case(  1, 16,  4),
		      case(  2,  5, 10),
		      case(  2,  8,  4),
		      case(  2,	11,  3),
		      case(  3,  1,  5),
		      case(  3,	 7,  3),
		      case(  3,	 9,  3),
		      case(  3,	15,  6),
		      case(  4,  6,  4),
		      case(  4, 10,  8),
		      case(  5,  2,  6),
		      case(  5,  7,  3),
		      case(  5,  9,  3),
		      case(  5,	14,  6),
		      case(  6,  4,  2),
		      case(  6,	12,  2),
		      case(  7,  3,  6),
		      case(  7,  5,  5),
		      case(  7,	11,  6),
		      case(  7, 13,  5),
		      case(  8,  2,  3),
		      case(  8, 14,  8),
		      case(  9,  3,  6),
		      case(  9,  5,  2),
		      case(  9,	11,  8),
		      case(  9,	13,  7),
		      case( 10,  4,  4),
		      case( 10,	12,  5),
		      case( 11,  2,  3),
		      case( 11,  7,  5),
		      case( 11,  9,  5),
		      case( 11, 14,  8),
		      case( 12,  6,  4),
		      case( 12,	10,  4),
		      case( 13,	 1,  3),
		      case( 13,	 7,  3),
		      case( 13,	 9,  3),
		      case( 13,	15,  5),
		      case( 14,	 5,  9),
		      case( 14,  8,  5),
		      case( 14,	11,  8),
		      case( 15,	 0,  3),
		      case( 15,	 3,  3),
		      case( 15,	13,  6),
		      case( 15,	16,  2),
		      case( 16,	 1,  5),
		      case( 16,	15,  2)].

% force 8
grille30(17, 17, Conditions) :-
	Conditions = [case(  0,  3,  8),
		      case(  0,  9,  7),
		      case(  0, 14,  5),
		      case(  1,  2,  4),
		      case(  1,  5,  3),
		      case(  1, 12,  5),
		      case(  2,  6,  5),
		      case(  3,  1,  2),
		      case(  3,	11,  6),
		      case(  3,	16,  4),
		      case(  4,  2,  2),
		      case(  4,  5,  5),
		      case(  4,  9,  5),
		      case(  4, 14,  4),
		      case(  5,  4,  5),
		      case(  6,  0,  6),
		      case(  6,	 8,  2),
		      case(  6,	13,  5),
		      case(  7,  1,  8),
		      case(  7,  6,  3),
		      case(  7,	11,  5),
		      case(  7, 16,  3),
		      case(  9,  0,  3),
		      case(  9,  5,  6),
		      case(  9, 10,  9),
		      case(  9,	15,  5),
		      case( 10,  3,  4),
		      case( 10,  8,  6),
		      case( 10,	16,  4),
		      case( 11, 12,  4),
		      case( 12,  2,  3),
		      case( 12,  7,  2),
		      case( 12,	11,  2),
		      case( 12,	14,  5),
		      case( 13,	 0,  6),
		      case( 13,	 5,  3),
		      case( 13,	15,  3),
		      case( 14,	10,  4),
		      case( 15,	 4,  3),
		      case( 15,	11,  5),
		      case( 15,	14,  3),
		      case( 16,	 2,  5),
		      case( 16,	 7,  2),
		      case( 16,	13,  4)].

grille_1(11,11, Conditions) :-
	Conditions = [case(  0,  2,  9),
		      case(  0,  8,  8),
		      case(  1,  8,  7),
		      case(  2,  4, 12),
		      case(  2, 10, 16),
		      case(  3,  0,  9),
		      case(  4,  1, 10),
		      case(  5,  2, 12),
		      case(  5,  4,  8),
		      case(  5,  6, 11),
		      case(  5,  8,  3),
		      case(  6,  9,  3),
		      case(  7,	10,  3),
		      case(  8,  0,  7),
		      case(  8,  6,  2),
		      case(  9,  2,  7),
		      case( 10,  2,  2),
		      case( 10,  8,  5)].

grille_2(9,9, Conditions) :-
	% une autre grille
	Conditions = [case(  0,  1,  2),
		      case(  0,  3,  4),
		      case(  0,  6,  3),
		      case(  1,  7,  3),
		      case(  2,  0,  2),
		      case(  3,  8,  3),
		      case(  4,  1,  8),
		      case(  4,  5, 10),
		      case(  6,  0,  4),
		      case(  6,	 4,  9),
		      case(  6,  6,  6),
		      case(  8,  3,  2),
		      case(  8,  7,  3)].


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Le gestionnaire d'affichage
%
:- pce_begin_class(gestionnaire(liste, fenetre, mytimer), object).
variable(liste, object,  both, "liste de boites").
variable(ev, object, both, "liste d'evenements").
variable(coups, int, both, "Nombre de coups de l'animation").
variable(fenetre, object, both, "pour afficher le nombre de déplacements").
variable(mytimer, timer, both, "attente avant lancement d'action de transvasement").

% méthode appelée lors de la destruction de l'objet
% On arrête d'abord le timer pour poursuivre ensuite
% sans problème (appel par le timer de ressources libérées)
unlink(F) :->
	send(F?mytimer, stop),
	send(F, send_super, unlink).

initialise(P, Fenetre, Liste, ListEV) :->
	send(P, coups, 0),
	send(P, fenetre, Fenetre),
	send(P, liste, Liste),
	send(P, ev, ListEV),
	send(P, mytimer, new(_, timer(0.08,message(P, my_message)))),
	send(P?mytimer, start).




% message interne envoyé par le timer
% Action principale du gestionnaire
my_message(P) :->
	%gtrace,
	get(P, ev, XL),
	chain_list(XL, L),
	(   L \= [] ,
	    L = [Q, V | T],
	    % get(P, taille, Taille),
	    get(P, coups, Coups),
	    Coups1 is Coups + 1,
	    send(P, coups, Coups1),
	    get(P, liste, XLB),
	    chain_list(XLB, LB),
	    nth0(Q, LB, B),
	    (
	    V = 0, send(B, fill_pattern, colour(@default, 0, 0, 0));
	    (	V = 1, send(B, fill_pattern, colour(@default, 65535, 65535, 65535));
	    send(B, fill_pattern, colour(@default, 0, 65535, 0)))
	    ),
	    chain_list(XT, T),
	    send(P, ev, XT)
	;
	    send(P?mytimer, stop),
	    get(P, coups, Coups),
	    sformat(Str, 'Solution trouvée en ~w étapes', [Coups]),
	    new(Str1, string(Str)),
	    new(Tx1, text(Str1?value)),
	    send(Tx1, colour(black)),
	    send(Tx1, font, font(times, bold, 14)),
	    get(P, fenetre, Fenetre),
	    send(Fenetre, display,Tx1, point(10, 10))).



:- pce_end_class.
