Initial commit
This commit is contained in:
commit
f79dad09fd
5 changed files with 967 additions and 0 deletions
107
tp1/aetoile.pl
Normal file
107
tp1/aetoile.pl
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
:- include('avl.pl'). % predicats pour gerer des arbres bin. de recherche
|
||||||
|
:- include('taquin.pl'). % predicats definissant le systeme a etudier
|
||||||
|
|
||||||
|
main :-
|
||||||
|
% Calcul de H pour la situation de départ
|
||||||
|
initial_state(U0),
|
||||||
|
heuristique(U0, H0),
|
||||||
|
|
||||||
|
% initialisations Pf, Pu et Q
|
||||||
|
insert([ [H0, H0, 0], U0 ], nil, Pf),
|
||||||
|
insert([U0, [H0, H0, 0], nil, nil], nil, Pu),
|
||||||
|
empty(Q),
|
||||||
|
!,
|
||||||
|
|
||||||
|
% lancement de Aetoile
|
||||||
|
aetoile(Pf, Pu, Q).
|
||||||
|
|
||||||
|
%*******************************************************************************
|
||||||
|
|
||||||
|
afficher_solution(_, nil).
|
||||||
|
|
||||||
|
afficher_solution(Q, S) :-
|
||||||
|
belongs([S, [_,_,G], Pere, Action], Q),
|
||||||
|
!,
|
||||||
|
write_state(S),
|
||||||
|
print(Action),
|
||||||
|
print(' ('),
|
||||||
|
print(G),
|
||||||
|
print(')'),
|
||||||
|
nl, nl,
|
||||||
|
afficher_solution(Q, Pere).
|
||||||
|
|
||||||
|
%*******************************************************************************
|
||||||
|
|
||||||
|
% Cas arbres vides -> plus d'état à développer -> pas de solution
|
||||||
|
aetoile(Pf, _, _) :-
|
||||||
|
empty(Pf),
|
||||||
|
!,
|
||||||
|
print('Pas de solution : l\'état final n\'est pas atteignable !\n').
|
||||||
|
|
||||||
|
% Cas état final -> solution trouvée
|
||||||
|
aetoile(Pf, Pu, Q) :-
|
||||||
|
suppress_min([[F, H, G], Sf], Pf, _),
|
||||||
|
final_state(Sf),
|
||||||
|
!,
|
||||||
|
suppress([Sf, [F, H, G], Pere, A], Pu, _),
|
||||||
|
insert([Sf, [F, H, G], Pere, A], Q, Q1),
|
||||||
|
print('Solution trouvée :\n'),
|
||||||
|
afficher_solution(Q1, Sf).
|
||||||
|
|
||||||
|
aetoile(Pf, Pu, Q) :-
|
||||||
|
suppress_min([[F, H, G], S], Pf, Pf1),
|
||||||
|
suppress([S, [F, H, G], Pere, A], Pu, Pu1),
|
||||||
|
expand(S, G, Successors),
|
||||||
|
loop_successors(Successors, S, Pf1, Pu1, Q, Pf2, Pu2),
|
||||||
|
insert([S, [F, H, G], Pere, A], Q, Q1),
|
||||||
|
aetoile(Pf2, Pu2, Q1).
|
||||||
|
|
||||||
|
%*******************************************************************************
|
||||||
|
|
||||||
|
expand(S, Gs, Successors) :-
|
||||||
|
findall([Successor, [F, H, G], Action], (
|
||||||
|
rule(Action, Cost, S, Successor),
|
||||||
|
G is Gs + Cost,
|
||||||
|
heuristique(Successor, H),
|
||||||
|
F is G + H
|
||||||
|
), Successors).
|
||||||
|
|
||||||
|
%*******************************************************************************
|
||||||
|
|
||||||
|
% Cas pas de successseurs
|
||||||
|
loop_successors([], _,Pf, Pu, _, Pf, Pu) :- !.
|
||||||
|
|
||||||
|
% Cas successeur déjà traité : on ignore
|
||||||
|
loop_successors([[S,_,_] | Rest], Pere, Pf, Pu, Q, Pf_new, Pu_new) :-
|
||||||
|
belongs([S,_,_,_], Q),
|
||||||
|
%!,
|
||||||
|
loop_successors(Rest, Pere, Pf, Pu, Q, Pf_new, Pu_new),
|
||||||
|
!.
|
||||||
|
|
||||||
|
% Cas successeur déjà connu : on met à jour le coût
|
||||||
|
loop_successors([[S, [F, H, G], Action] | Rest], Pere, Pf, Pu, Q, Pf_new, Pu_new) :-
|
||||||
|
belongs([S, [F_old,_,_], _, _], Pu),
|
||||||
|
%!,
|
||||||
|
update_trees(S, H, [F, G, Pere, Action], F_old, Pf, Pf1, Pu, Pu1),
|
||||||
|
loop_successors(Rest, Pere, Pf1, Pu1, Q, Pf_new, Pu_new),
|
||||||
|
!.
|
||||||
|
|
||||||
|
% Cas successeur inconnu : on l'ajoute à P
|
||||||
|
loop_successors([[S, [F, H, G], Action] | Rest], Pere, Pf, Pu, Q, Pf_new, Pu_new) :-
|
||||||
|
insert([S, [F, H, G], Pere, Action], Pu, Pu1),
|
||||||
|
insert([[F, H, G], S], Pf, Pf1),
|
||||||
|
loop_successors(Rest, Pere, Pf1, Pu1, Q, Pf_new, Pu_new).
|
||||||
|
|
||||||
|
%*******************************************************************************
|
||||||
|
|
||||||
|
% Mise à jour des coûts et des parents seulement si plus faible
|
||||||
|
update_trees(S, H, [F, G, Pere, Action], F_old, Pf, Pf2, Pu, Pu2) :-
|
||||||
|
(F_old is min(F, F_old) ->
|
||||||
|
Pf = Pf2,
|
||||||
|
Pu = Pu2
|
||||||
|
;
|
||||||
|
suppress([S,_,_,_], Pu, Pu1),
|
||||||
|
insert([S, [F, H, G], Pere, Action], Pu1, Pu2),
|
||||||
|
suppress([[F_old,_,_], S], Pf, Pf1),
|
||||||
|
insert([[F, H, G], S], Pf1, Pf2)
|
||||||
|
).
|
367
tp1/avl.pl
Normal file
367
tp1/avl.pl
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
%***************************
|
||||||
|
% Gestion d'un AVL en Prolog
|
||||||
|
%***************************
|
||||||
|
|
||||||
|
%***************************
|
||||||
|
% INSA TOULOUSE - P.ESQUIROL
|
||||||
|
% mars 2017
|
||||||
|
%***************************
|
||||||
|
|
||||||
|
%*************************
|
||||||
|
% unit tests : OK
|
||||||
|
% integration aetoile : OK
|
||||||
|
%*************************
|
||||||
|
|
||||||
|
% Les AVL sont des arbres BINAIRES DE RECHERCHE H-EQUILIBRES :
|
||||||
|
% La hauteur de l'avl A est définie par :
|
||||||
|
% -1, si A est vide (A=nil)
|
||||||
|
% 1 + max( hauteur(ss_arbre_gauche(A)), hauteur(ss_arbre_droitee(A)) ) sinon
|
||||||
|
|
||||||
|
% Tout noeud de l'arbre est soit :
|
||||||
|
% - une feuille
|
||||||
|
% - un noeud interne tel que la différence de hauteur entre le sous-arbre droit
|
||||||
|
% et le sous-arbre gauche appartient à [-1,0,+1]
|
||||||
|
|
||||||
|
|
||||||
|
%***********************************************
|
||||||
|
% PREDICATS EXPORTES ET COMPLEXITE ALGORITHMIQUE
|
||||||
|
%***********************************************
|
||||||
|
% soit N = nombre de noeuds de l'arbre % UTILITE POUR A*
|
||||||
|
% % ----------------
|
||||||
|
% empty(?Avl) O(1) %<<< initialisation de P et Q
|
||||||
|
% height(+Avl, ?Height) O(1)
|
||||||
|
% put_flat(+Avl) O(N)
|
||||||
|
% put_90(+Avl) O(N)
|
||||||
|
% belongs(+Elem, +Avl) O(log N) %<<< appartenance d'un noeud à Q
|
||||||
|
% subtree(+Elem, +Avl, Ss_Avl) O(log N)
|
||||||
|
% insert(+Elem, +Avant, ?Apres) O(log N) %<<< insertion d'un nouveau noeud dans P ou dans Q
|
||||||
|
% suppress(+Elem,+Avant,?Apres) O(log N) %<<< mise à jour <=> suppression puis insertion
|
||||||
|
% suppress_min(?Min,+Avant,?Apres) O(log N) %<<< supression du noeud minimal
|
||||||
|
% suppress_max(?Max,+Avant,?Apres) O(log N)
|
||||||
|
|
||||||
|
%****************************
|
||||||
|
% Prédicats internes (prives)
|
||||||
|
%****************************
|
||||||
|
|
||||||
|
% left_rotate(+Avant, ?Apres) O(1)
|
||||||
|
% right_rotate(+Avant, ?Apres) O(1)
|
||||||
|
% left_balance(+Avant, ?Apres) O(1)
|
||||||
|
% right_balance(+Avant, ?Apres) O(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%------------------------------
|
||||||
|
% Constructeur et test AVL vide
|
||||||
|
%------------------------------
|
||||||
|
|
||||||
|
empty(nil).
|
||||||
|
|
||||||
|
%-----------------
|
||||||
|
% Hauteur d'un AVL
|
||||||
|
%-----------------
|
||||||
|
% par convention, un avl vide a une hauteur de -1
|
||||||
|
% sinon la hauteur est enregistree au meme niveau que la racine de l'avl
|
||||||
|
% elle n'est pas calculee recursivement "from scratch"
|
||||||
|
% elle est mise à jour de façon incrémentale, apres chaque insertion ou suppression
|
||||||
|
% d'ou sa complexité en O(1) :-)
|
||||||
|
|
||||||
|
height(nil, -1).
|
||||||
|
height(avl(_G,_R,_D, H), H).
|
||||||
|
|
||||||
|
%-------------------
|
||||||
|
% Affichage d'un AVL
|
||||||
|
%-------------------
|
||||||
|
% dans l'ordre croissant (lexicographique)
|
||||||
|
|
||||||
|
put_flat(nil).
|
||||||
|
put_flat(avl(G,R,D,_H)) :-
|
||||||
|
put_flat(G),
|
||||||
|
nl, write(R),
|
||||||
|
put_flat(D).
|
||||||
|
|
||||||
|
%----------------------------
|
||||||
|
% Affichage (couché) d'un AVL
|
||||||
|
%----------------------------
|
||||||
|
|
||||||
|
put_90(Avl) :-
|
||||||
|
nl, writeln('----------------------------------'),
|
||||||
|
put_90(Avl,"").
|
||||||
|
|
||||||
|
put_90(nil,Str) :-
|
||||||
|
write(Str), write('.').
|
||||||
|
put_90(avl(G,R,D,_H),Str) :-
|
||||||
|
append_strings(Str, " ", Str2),
|
||||||
|
put_90(D,Str2),
|
||||||
|
nl, write(Str), write(R),nl,
|
||||||
|
put_90(G,Str2).
|
||||||
|
|
||||||
|
%-----------------------------------------
|
||||||
|
% Appartenance d'un element donne a un AVL
|
||||||
|
%-----------------------------------------
|
||||||
|
|
||||||
|
belongs(Elem, avl(G,Racine,D,_Hauteur)) :-
|
||||||
|
(Elem = Racine ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
(Elem @< Racine ->
|
||||||
|
belongs(Elem, G)
|
||||||
|
;
|
||||||
|
belongs(Elem, D) %Racine @< Elem
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
%------------------------------------------------------------
|
||||||
|
% Recherche du sous-arbre qui a comme racine un element donne
|
||||||
|
%------------------------------------------------------------
|
||||||
|
|
||||||
|
subtree(Elem, avl(G,Racine,D,H), A) :-
|
||||||
|
(Elem = Racine ->
|
||||||
|
A = avl(G,Racine,D,H)
|
||||||
|
;
|
||||||
|
(Elem @< Racine ->
|
||||||
|
subtree(Elem,G,A)
|
||||||
|
;
|
||||||
|
subtree(Elem,D,A) %Racine @< Elem
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
%----------------------
|
||||||
|
% Rotations dans un avl
|
||||||
|
%----------------------
|
||||||
|
% Les rotations ci-dessous décrivent uniquement les cas ou la rotation est possible.
|
||||||
|
% Dans les autres cas, ces relations échouent ; plus précisément :
|
||||||
|
% a/ si l'arbre est un avl vide, alors aucune rotation n'est possible ;
|
||||||
|
% b/ si l'arbre est un avl non vide mais si son ss-arbre gauche est un avl vide
|
||||||
|
% alors la rotation droite n'est pas possible ;
|
||||||
|
% c/ si l'arbre est un avl non vide mais si son ss-arbre droite est un avl vide
|
||||||
|
% alors la rotation gauche n'est pas possible.
|
||||||
|
|
||||||
|
right_rotate(avl(G,R,D,_H), A_Apres) :-
|
||||||
|
height(D,HD),
|
||||||
|
G = avl(SG,RG,SD,_HG),
|
||||||
|
height(SD,HSD),
|
||||||
|
H_Inter is 1 + max(HSD, HD),
|
||||||
|
Inter = avl(SD,R,D,H_Inter),
|
||||||
|
height(SG,HSG),
|
||||||
|
H_Apres is 1 + max(HSG,H_Inter),
|
||||||
|
A_Apres = avl(SG,RG,Inter,H_Apres).
|
||||||
|
|
||||||
|
left_rotate(avl(G,R,D,_), A_Apres) :-
|
||||||
|
height(G,HG),
|
||||||
|
D = avl(SG,RD,SD,_),
|
||||||
|
height(SG,HSG),
|
||||||
|
H_Inter is 1 + max(HSG, HG),
|
||||||
|
Inter = avl(G,R,SG,H_Inter),
|
||||||
|
height(SD,HSD),
|
||||||
|
H_Apres is 1 + max(H_Inter,HSD),
|
||||||
|
A_Apres = avl(Inter,RD,SD,H_Apres).
|
||||||
|
|
||||||
|
%---------------------------------
|
||||||
|
% Insertion equilibree dans un avl
|
||||||
|
%---------------------------------
|
||||||
|
% On suppose que l'arbre avant insertion est equilibré (difference de hauteur
|
||||||
|
% entre les ss-arbres gauche et droite de 1 au maximum)
|
||||||
|
% L'insertion doit assurer qu'apres insertion l'arbre est toujours equilibre
|
||||||
|
% sinon les rotations necessaires sont effectuees.
|
||||||
|
|
||||||
|
% On suppose que les noeuds contiennent des informations que l'on peut comparer
|
||||||
|
% a l'aide d'une relation d'ordre lexicographique (la cle c'est l'info elle-meme)
|
||||||
|
% En prolog, c'est la relation '@<'
|
||||||
|
% On peut comparer par exemple des integer, des string, des constantes,
|
||||||
|
% des listes d'entiers, des listes de constantes, etc ... bref, des termes clos
|
||||||
|
% T1 @< T2 est vrai si T1 est lexicographiquement inférieur a T2.
|
||||||
|
|
||||||
|
insert(Elem, nil, avl(nil,Elem,nil,0)).
|
||||||
|
insert(Elem, AVL, NEW_AVL) :-
|
||||||
|
AVL = avl(Gauche,Racine,Droite,_Hauteur),
|
||||||
|
(Elem = Racine ->
|
||||||
|
% l'élément est déjà present, pas d'insertion possible
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
(Elem @< Racine ->
|
||||||
|
% insertion dans le ss-arbre gauche
|
||||||
|
insert(Elem, Gauche, New_Gauche),
|
||||||
|
height(New_Gauche, New_HG),
|
||||||
|
height(Droite, HD),
|
||||||
|
H_Int is 1+max(New_HG, HD),
|
||||||
|
AVL_INT = avl(New_Gauche, Racine, Droite, H_Int),
|
||||||
|
right_balance(AVL_INT, NEW_AVL)
|
||||||
|
;
|
||||||
|
% Elem @> Racine
|
||||||
|
% insertion dans le ss-arbre droite
|
||||||
|
insert(Elem, Droite, New_Droite),
|
||||||
|
height(New_Droite, New_HD),
|
||||||
|
height(Gauche, HG),
|
||||||
|
H_Int is 1+max(New_HD, HG),
|
||||||
|
AVL_INT =avl(Gauche, Racine,New_Droite, H_Int),
|
||||||
|
left_balance(AVL_INT, NEW_AVL)
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
%------------------------------------------------
|
||||||
|
% Suppression d'un element quelconque dans un avl
|
||||||
|
%------------------------------------------------
|
||||||
|
% On suppose que l'élément à supprimer appartient bien à l'AVL,
|
||||||
|
% sinon le predicat échoue (en particulier si l'AVL est vide).
|
||||||
|
|
||||||
|
suppress(Elem, AVL, NEW_AVL) :-
|
||||||
|
AVL = avl(Gauche, Racine, Droite, _Hauteur),
|
||||||
|
(Elem = Racine ->
|
||||||
|
% cas de la suppression de la racine de l'avl
|
||||||
|
(Gauche = nil -> % cas simple d'une feuille ou d'un avl sans fils gauche
|
||||||
|
NEW_AVL = Droite
|
||||||
|
;
|
||||||
|
(Droite = nil -> % cas simple d'un avl avec fils gauche mais sans fils droit
|
||||||
|
NEW_AVL = Gauche
|
||||||
|
;
|
||||||
|
% cas d'un avl avec fils gauche ET fils droit
|
||||||
|
%Gauche \= nil
|
||||||
|
%Droite \= nil
|
||||||
|
suppress_max(Max, Gauche, New_Gauche),
|
||||||
|
AVL_INT = avl(New_Gauche,Max,Droite,_),
|
||||||
|
left_balance(AVL_INT, NEW_AVL)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
% cas des suppressions d'un element autre que la racine
|
||||||
|
(Elem @< Racine ->
|
||||||
|
% suppression dans le ss-arbre gauche
|
||||||
|
suppress(Elem, Gauche, New_Gauche),
|
||||||
|
AVL_INT = avl(New_Gauche, Racine, Droite,_),
|
||||||
|
left_balance(AVL_INT, NEW_AVL)
|
||||||
|
;
|
||||||
|
%Racine @< Droite
|
||||||
|
% suppression dans le ss-arbre droite
|
||||||
|
suppress(Elem, Droite, New_Droite),
|
||||||
|
AVL_INT = avl(Gauche, Racine, New_Droite,_),
|
||||||
|
right_balance(AVL_INT, NEW_AVL)
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
%-------------------------------------------------------
|
||||||
|
% Suppression du plus petit element dans un avl non vide
|
||||||
|
%-------------------------------------------------------
|
||||||
|
% Si l'avl est vide, le prédicat échoue
|
||||||
|
|
||||||
|
suppress_min(Min, AVL, NEW_AVL) :-
|
||||||
|
AVL = avl(Gauche,Racine,Droite, _Hauteur),
|
||||||
|
(Gauche = nil ->
|
||||||
|
Min = Racine,
|
||||||
|
NEW_AVL = Droite
|
||||||
|
;
|
||||||
|
% Gauche \= nil
|
||||||
|
suppress_min(Min, Gauche, New_Gauche),
|
||||||
|
AVL_INT = avl(New_Gauche, Racine, Droite,_),
|
||||||
|
left_balance(AVL_INT, NEW_AVL)
|
||||||
|
).
|
||||||
|
|
||||||
|
%-------------------------------------------------------
|
||||||
|
% Suppression du plus grand element dans un avl non vide
|
||||||
|
%-------------------------------------------------------
|
||||||
|
% Si l'avl est vide, le prédicat échoue
|
||||||
|
|
||||||
|
suppress_max(Max, AVL, NEW_AVL) :-
|
||||||
|
AVL = avl(Gauche,Racine,Droite, _Hauteur),
|
||||||
|
(Droite = nil ->
|
||||||
|
Max = Racine,
|
||||||
|
NEW_AVL = Gauche
|
||||||
|
;
|
||||||
|
% Droite \= nil
|
||||||
|
suppress_max(Max, Droite, New_Droite),
|
||||||
|
AVL_INT = avl(Gauche, Racine, New_Droite,_),
|
||||||
|
right_balance(AVL_INT, NEW_AVL)
|
||||||
|
).
|
||||||
|
|
||||||
|
%----------------------------------------
|
||||||
|
% Re-equilibrages d'un avl vers la gauche
|
||||||
|
%----------------------------------------
|
||||||
|
% - soit apres insertion d'un element dans le sous-arbre droite
|
||||||
|
% - soit apres suppression d'un élément dans le sous-arbre gauche
|
||||||
|
%----------------------------------------------------------------
|
||||||
|
|
||||||
|
left_balance(Avl, New_Avl) :-
|
||||||
|
Avl = avl(Gauche, Racine, Droite, _Hauteur),
|
||||||
|
height(Gauche, HG),
|
||||||
|
height(Droite, HD),
|
||||||
|
(HG is HD-2 ->
|
||||||
|
% le sous-arbre droite est trop haut
|
||||||
|
Droite = avl(G_Droite, _R_Droite, D_Droite, _HD),
|
||||||
|
height(G_Droite, HGD),
|
||||||
|
height(D_Droite, HDD),
|
||||||
|
(HDD > HGD ->
|
||||||
|
% une simple rotation gauche suffit
|
||||||
|
left_rotate(Avl, New_Avl)
|
||||||
|
;
|
||||||
|
% il faut faire une rotation droite_gauche
|
||||||
|
right_rotate(Droite, New_Droite),
|
||||||
|
height(New_Droite, New_HD),
|
||||||
|
H_Int is 1+ max(HG, New_HD),
|
||||||
|
Avl_Int = avl(Gauche, Racine, New_Droite, H_Int),
|
||||||
|
left_rotate(Avl_Int, New_Avl)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
% la suppression n'a pas desequilibre l'avl
|
||||||
|
New_Hauteur is 1+max(HG,HD),
|
||||||
|
New_Avl = avl(Gauche, Racine, Droite, New_Hauteur)
|
||||||
|
).
|
||||||
|
|
||||||
|
%----------------------------------------
|
||||||
|
% Re-equilibrages d'un avl vers la droite
|
||||||
|
%----------------------------------------
|
||||||
|
% - soit apres insertion d'un element dans le sous-arbre gauche
|
||||||
|
% - soit apres suppression d'un élément dans le sous-arbre droite
|
||||||
|
%----------------------------------------------------------------
|
||||||
|
|
||||||
|
right_balance(Avl, New_Avl) :-
|
||||||
|
Avl = avl(Gauche, Racine, Droite, _Hauteur),
|
||||||
|
height(Gauche, HG),
|
||||||
|
height(Droite, HD),
|
||||||
|
(HD is HG-2 ->
|
||||||
|
% le sous-arbre gauche est trop haut
|
||||||
|
Gauche = avl(G_Gauche, _R_Gauche, D_Gauche, _HG),
|
||||||
|
height(G_Gauche, HGG),
|
||||||
|
height(D_Gauche, HDG),
|
||||||
|
(HGG > HDG ->
|
||||||
|
% une simple rotation droite suffit
|
||||||
|
right_rotate(Avl, New_Avl)
|
||||||
|
;
|
||||||
|
% il faut faire une rotation gauche_droite
|
||||||
|
left_rotate(Gauche, New_Gauche),
|
||||||
|
height(New_Gauche, New_HG),
|
||||||
|
H_Int is 1+ max(New_HG, HD),
|
||||||
|
Avl_Int = avl(New_Gauche, Racine, Droite, H_Int),
|
||||||
|
right_rotate(Avl_Int, New_Avl)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
% la suppression n'a pas desequilibre l'avl
|
||||||
|
New_Hauteur is 1+max(HG,HD),
|
||||||
|
New_Avl = avl(Gauche, Racine, Droite, New_Hauteur)
|
||||||
|
).
|
||||||
|
|
||||||
|
%-----------------------------------------
|
||||||
|
% Arbres utilises pour les tests unitaires
|
||||||
|
%-----------------------------------------
|
||||||
|
avl_test(1, nil).
|
||||||
|
avl_test(2, avl(nil, 1, nil, 0)).
|
||||||
|
avl_test(3, avl(nil, 1, avl(nil,2,nil,0), 1)).
|
||||||
|
avl_test(4, avl(avl(nil,1,nil,0),2, nil, 1)).
|
||||||
|
avl_test(5, avl(avl(nil,1,nil,0), 2, avl(nil,3,nil,0),1) ).
|
||||||
|
avl_test(6, avl(avl(nil,5,nil,0), 6, avl(nil,7,nil,0),1) ).
|
||||||
|
avl_test(7, avl(G,4,D,2)) :-
|
||||||
|
avl_test(5,G),
|
||||||
|
avl_test(6,D).
|
||||||
|
avl_test(8, avl(G,5,D,2)) :-
|
||||||
|
D = avl(nil,6,nil,0),
|
||||||
|
avl_test(3,G).
|
||||||
|
avl_test(9, avl(G,3,D,2)) :-
|
||||||
|
G = avl(nil,1,nil,0),
|
||||||
|
avl_test(4,D).
|
||||||
|
|
||||||
|
/* Test uniquement valable avec ECLiPSe
|
||||||
|
|
||||||
|
avl_test(10, Final) :-
|
||||||
|
empty(Init),
|
||||||
|
(for(I,1,20), fromto(Init,In,Out,Final) do
|
||||||
|
insert(I,In,Out)
|
||||||
|
).
|
||||||
|
*/
|
177
tp1/taquin.pl
Normal file
177
tp1/taquin.pl
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
Doit contenir au moins 4 predicats qui seront utilises par A*
|
||||||
|
etat_initial(I) % definit l'etat initial
|
||||||
|
etat_final(F) % definit l'etat final
|
||||||
|
rule(Rule_Name, Rule_Cost, Before_State, After_State) % règles applicables
|
||||||
|
heuristique(Current_State, Hval) % calcul de l'heuristique
|
||||||
|
*/
|
||||||
|
|
||||||
|
%********************
|
||||||
|
% ETAT INITIAL DU JEU
|
||||||
|
%********************
|
||||||
|
% format : initial_state(+State) ou State est une matrice (liste de listes)
|
||||||
|
|
||||||
|
/*
|
||||||
|
initial_state([ [b, h, c], % C'EST L'EXEMPLE PRIS EN COURS
|
||||||
|
[a, f, d], %
|
||||||
|
[g,vide,e] ]). % h1=4, h2=5, f*=5*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
initial_state([ [ a, b, c],
|
||||||
|
[ g, h, d],
|
||||||
|
[vide,f, e] ]). % h2=2, f*=2
|
||||||
|
|
||||||
|
initial_state([ [b, c, d],
|
||||||
|
[a,vide,g],
|
||||||
|
[f, h, e] ]). % h2=10 f*=10
|
||||||
|
|
||||||
|
initial_state([ [f, g, a],
|
||||||
|
[h,vide,b],
|
||||||
|
[d, c, e] ]). % h2=16, f*=20
|
||||||
|
initial_state([ [e, f, g],
|
||||||
|
[d,vide,h],
|
||||||
|
[c, b, a] ]). % h2=24, f*=30
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
initial_state([ [a, b, c],
|
||||||
|
[g,vide,d],
|
||||||
|
[h, f, e]]). % etat non connexe avec l'etat final (PAS DE SOLUTION)
|
||||||
|
|
||||||
|
*/
|
||||||
|
initial_state([[ d , l , n , g ],
|
||||||
|
[ vide , b , a , c ],
|
||||||
|
[ e , m , k , h ],
|
||||||
|
[ j , f , i , o]]).
|
||||||
|
|
||||||
|
%******************
|
||||||
|
% ETAT FINAL DU JEU
|
||||||
|
%******************
|
||||||
|
% format : final_state(+State) ou State est une matrice (liste de listes)
|
||||||
|
|
||||||
|
/*
|
||||||
|
final_state([ [a, b, c],
|
||||||
|
[h,vide,d],
|
||||||
|
[g, f, e]]). % etat non connexe avec l'etat final (PAS DE SOLUTION)
|
||||||
|
*/
|
||||||
|
final_state([[ a , b , c , d ],
|
||||||
|
[ e , f , g , h ],
|
||||||
|
[ i , j , k , l ],
|
||||||
|
[ m , n , o , vide]]).
|
||||||
|
|
||||||
|
%********************
|
||||||
|
% AFFICHAGE D'UN ETAT
|
||||||
|
%********************
|
||||||
|
% format : write_state(?State) ou State est une liste de lignes a afficher
|
||||||
|
write_state([]).
|
||||||
|
write_state([Line|Rest]) :-
|
||||||
|
print(Line),
|
||||||
|
nl,
|
||||||
|
write_state(Rest).
|
||||||
|
|
||||||
|
%**********************************************
|
||||||
|
% REGLES DE DEPLACEMENT (up, down, left, right)
|
||||||
|
%**********************************************
|
||||||
|
% format : rule(+Rule_Name, ?Rule_Cost, +Current_State, ?Next_State)
|
||||||
|
rule(down , 1, S1, S2) :-
|
||||||
|
vertical_permutation(_X,vide,S1,S2).
|
||||||
|
|
||||||
|
rule(up , 1, S1, S2) :-
|
||||||
|
vertical_permutation(vide,_X,S1,S2).
|
||||||
|
|
||||||
|
rule(right, 1, S1, S2) :-
|
||||||
|
horizontal_permutation(_X,vide,S1,S2).
|
||||||
|
|
||||||
|
rule(left , 1, S1, S2) :-
|
||||||
|
horizontal_permutation(vide,_X,S1,S2).
|
||||||
|
|
||||||
|
%***********************
|
||||||
|
% Deplacement horizontal
|
||||||
|
%***********************
|
||||||
|
% format : horizontal_permutation(?Piece1,?Piece2,+Current_State, ?Next_State)
|
||||||
|
horizontal_permutation(X,Y,S1,S2) :-
|
||||||
|
append(Above,[Line1|Rest], S1),
|
||||||
|
exchange(X,Y,Line1,Line2),
|
||||||
|
append(Above,[Line2|Rest], S2).
|
||||||
|
|
||||||
|
%***********************************************
|
||||||
|
% Echange de 2 objets consecutifs dans une liste
|
||||||
|
%***********************************************
|
||||||
|
exchange(X,Y,[X,Y|List], [Y,X|List]).
|
||||||
|
exchange(X,Y,[Z|List1], [Z|List2] ):-
|
||||||
|
exchange(X,Y,List1,List2).
|
||||||
|
|
||||||
|
%*********************
|
||||||
|
% Deplacement vertical
|
||||||
|
%*********************
|
||||||
|
vertical_permutation(X,Y,S1,S2) :-
|
||||||
|
append(Above, [Line1,Line2|Below], S1), % decompose S1
|
||||||
|
delete(N,X,Line1,Rest1), % enleve X en position N a Line1, donne Rest1
|
||||||
|
delete(N,Y,Line2,Rest2), % enleve Y en position N a Line2, donne Rest2
|
||||||
|
delete(N,Y,Line3,Rest1), % insere Y en position N dans Rest1 donne Line3
|
||||||
|
delete(N,X,Line4,Rest2), % insere X en position N dans Rest2 donne Line4
|
||||||
|
append(Above, [Line3,Line4|Below], S2). % recompose S2
|
||||||
|
|
||||||
|
%***********************************************************************
|
||||||
|
% Retrait d'une occurrence X en position N dans une liste L (resultat R)
|
||||||
|
%***********************************************************************
|
||||||
|
% use case 1 : delete(?N,?X,+L,?R)
|
||||||
|
% use case 2 : delete(?N,?X,?L,+R)
|
||||||
|
delete(1,X,[X|L], L).
|
||||||
|
delete(N,X,[Y|L], [Y|R]) :-
|
||||||
|
delete(N1,X,L,R),
|
||||||
|
N is N1 + 1.
|
||||||
|
|
||||||
|
%*******************************************************************
|
||||||
|
% Coordonnees X(colonne),Y(Ligne) d'une piece P dans une situation U
|
||||||
|
%*******************************************************************
|
||||||
|
% Associe un état State et une pièce P à ses coordonnées X et Y
|
||||||
|
coordonnees(State, P, X, Y) :-
|
||||||
|
nth1(Y, State, Ligne),
|
||||||
|
nth1(X, Ligne, P).
|
||||||
|
|
||||||
|
%*************
|
||||||
|
% HEURISTIQUES
|
||||||
|
%*************
|
||||||
|
heuristique(U,H) :-
|
||||||
|
heuristique2(U, H).
|
||||||
|
|
||||||
|
%****************
|
||||||
|
%HEURISTIQUE 1
|
||||||
|
%****************
|
||||||
|
% Nombre de pieces mal placees dans l'etat courant U
|
||||||
|
% par rapport a l'etat final F
|
||||||
|
heuristique1(U, H) :-
|
||||||
|
final_state(F),
|
||||||
|
findall([X, Y], meme_piece(U, F, X, Y), BienPlacees),
|
||||||
|
length(BienPlacees, NbBienPlacees),
|
||||||
|
length(U, N),
|
||||||
|
H is N*N - NbBienPlacees. % On considère que les taquins seront toujours carré
|
||||||
|
|
||||||
|
% Détermine si la pièce aux coord X,Y en S1 est la même que celle en S2
|
||||||
|
meme_piece(S1, S2, X, Y) :-
|
||||||
|
coordonnees(S1, P, X, Y),
|
||||||
|
coordonnees(S2, P, X, Y),
|
||||||
|
P \= vide,
|
||||||
|
!.
|
||||||
|
|
||||||
|
% Cas particulier : on ne compte pas 'vide'
|
||||||
|
meme_piece(S1, _, X, Y) :-
|
||||||
|
coordonnees(S1, vide, X, Y).
|
||||||
|
|
||||||
|
%****************
|
||||||
|
%HEURISTIQUE no 2
|
||||||
|
%****************
|
||||||
|
% Somme des distances de Manhattan à parcourir par chaque piece
|
||||||
|
% entre sa position courante et sa positon dans l'etat final
|
||||||
|
heuristique2(U, H) :-
|
||||||
|
final_state(F),
|
||||||
|
findall(Dist, manhattan(U, F, _, Dist), ListDist),
|
||||||
|
sum_list(ListDist, H).
|
||||||
|
|
||||||
|
manhattan(S1, S2, P, Dist) :-
|
||||||
|
coordonnees(S1, P, X1, Y1),
|
||||||
|
coordonnees(S2, P, X2, Y2),
|
||||||
|
P \= vide,
|
||||||
|
Dist is abs(X1 - X2) + abs(Y1 - Y2).
|
||||||
|
|
125
tp2/negamax.pl
Normal file
125
tp2/negamax.pl
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
:- include('tictactoe.pl').
|
||||||
|
|
||||||
|
% Algorithme MinMax avec convention Negamax. Retourne pour un joueur J donné, devant jouer dans une situation donnée Etat, de profondeur donnée P, le meilleur couple [Coup, Valeur] apres une analyse pouvant aller jusqu'à la profondeur Pmax.
|
||||||
|
|
||||||
|
% Cas 1 : Profondeur max atteinte -> éval par heuristique
|
||||||
|
negamax(J, Etat, P, Pmax, [rien, Val]) :-
|
||||||
|
P >= Pmax,
|
||||||
|
!,
|
||||||
|
heuristique(J, Etat, Val).
|
||||||
|
|
||||||
|
% Cas 2 : Aucun coup possible -> éval par heuristique
|
||||||
|
negamax(J, Etat, _, _, [rien, Val]) :-
|
||||||
|
successeurs(J, Etat, Succ),
|
||||||
|
length(Succ, 0),
|
||||||
|
!,
|
||||||
|
heuristique(J, Etat, Val).
|
||||||
|
|
||||||
|
% Cas 3 : Évaluation du sous-arbre et retour du meilleur couple [Coup, Valeur]
|
||||||
|
negamax(J, Etat, P, Pmax, [Coup, Val]) :-
|
||||||
|
successeurs(J, Etat, Succ),
|
||||||
|
!,
|
||||||
|
loop_negamax(J, P, Pmax, Succ, ListCouples),
|
||||||
|
meilleur(ListCouples, [Coup, V1]),
|
||||||
|
Val is -V1.
|
||||||
|
|
||||||
|
%*******************************************************
|
||||||
|
|
||||||
|
% retourne la liste des couples [Coup, Etat_Suivant] pour la situation Etat
|
||||||
|
successeurs(J, Etat, Succ) :-
|
||||||
|
copy_term(Etat, Etat_Suiv),
|
||||||
|
findall([Coup,Etat_Suiv],
|
||||||
|
successeur(J, Etat_Suiv, Coup),
|
||||||
|
Succ).
|
||||||
|
|
||||||
|
testSuccesseur :-
|
||||||
|
situation_initiale(S),
|
||||||
|
successeurs(x, S, LSucc),
|
||||||
|
forall(member([Coup, Succ], LSucc),
|
||||||
|
(write(Coup), nl,
|
||||||
|
printState(Succ), nl)
|
||||||
|
).
|
||||||
|
|
||||||
|
%*******************************************************
|
||||||
|
|
||||||
|
% retourne la liste des couples [Coup, Valeur_Situation_Suivante] à partir de la liste des [Coup, Situation_Suivante], en appliquant l'algorithme negamax sur chacun d'entre eux.
|
||||||
|
loop_negamax(_, _, _ ,[], []) :- !.
|
||||||
|
|
||||||
|
loop_negamax(J, P, Pmax, [[Coup, Suiv] | Succ], [[Coup, Vsuiv] | Reste_Couples]) :-
|
||||||
|
% Récursion pour traiter le reste des successeurs
|
||||||
|
loop_negamax(J, P, Pmax, Succ, Reste_Couples),
|
||||||
|
% Récupération de l'adversaire de J
|
||||||
|
adversaire(J, A),
|
||||||
|
% Incrément de la profondeur avant l'appel de négamax
|
||||||
|
Pnew is P+1,
|
||||||
|
% Calcul de la valeur de negamax pour la situation Suiv.
|
||||||
|
% On n'a pas besoin de connaitre le coup de l'adversaire en profondeur P+1 qui donne cette valeur, seul le coup de J en P nous intéresse (et on le connait déjà). D'ou le _ dans les arguments passés à negamax.
|
||||||
|
negamax(A, Suiv, Pnew, Pmax, [_, Vsuiv]).
|
||||||
|
|
||||||
|
%*******************************************************
|
||||||
|
|
||||||
|
% Retourne le couple [Coup, Valeur] dont la valeur est la plus faible (car convention negamax)
|
||||||
|
meilleur([E], E) :- !.
|
||||||
|
|
||||||
|
meilleur([[C,V] | RestCouples], [BestC, BestV]) :-
|
||||||
|
meilleur(RestCouples, [TempC, TempV]),
|
||||||
|
min([TempC,TempV], [C,V], [BestC, BestV]).
|
||||||
|
|
||||||
|
min([C1,V1], [C2,V2], [C,V]) :-
|
||||||
|
(V1 < V2) ->
|
||||||
|
V = V1,
|
||||||
|
C = C1
|
||||||
|
;
|
||||||
|
V = V2,
|
||||||
|
C = C2.
|
||||||
|
|
||||||
|
testMeilleur :-
|
||||||
|
meilleur([[[1,2], -5], [[3,2], 2], [[3,3], -6], [[1,1], 7]], [[3,3], -6]),
|
||||||
|
meilleur([[[1,2], 5]], [[1,2], 5]).
|
||||||
|
|
||||||
|
%*******************************************************
|
||||||
|
|
||||||
|
% Retourne le coup et la valeur retournés par Negamax depuis l'état initial
|
||||||
|
main(BestMove, Value, Pmax) :-
|
||||||
|
situation_initiale(S0),
|
||||||
|
joueur_initial(J),
|
||||||
|
negamax(J, S0, 1, Pmax, [BestMove, Value]).
|
||||||
|
|
||||||
|
% Bug pour I = 9
|
||||||
|
testMain :-
|
||||||
|
forall(between(1, 9, I), (
|
||||||
|
main(B, V, I),
|
||||||
|
write('I = '), write(I), nl,
|
||||||
|
write('B = '), write(B), nl,
|
||||||
|
write('V = '), write(V), nl, nl
|
||||||
|
)).
|
||||||
|
|
||||||
|
%*******************************************************
|
||||||
|
|
||||||
|
% Applique Negamax et joue le coup suggéré successivement jusqu'à remplissage de la grille
|
||||||
|
testNegamax :-
|
||||||
|
situation_initiale(S0),
|
||||||
|
joueur_initial(J),
|
||||||
|
iter(J, S0).
|
||||||
|
|
||||||
|
iter(_, S) :-
|
||||||
|
situation_terminale(S),
|
||||||
|
!,
|
||||||
|
write('Match nul !'), nl.
|
||||||
|
|
||||||
|
iter(_, S) :-
|
||||||
|
alignement(Ali, S),
|
||||||
|
alignement_gagnant(Ali, J),
|
||||||
|
!,
|
||||||
|
write(Ali), nl,
|
||||||
|
write(S), nl,
|
||||||
|
write(J), write(' a gagné !'), nl.
|
||||||
|
|
||||||
|
iter(J, S) :-
|
||||||
|
negamax(J, S, 1, 9, [BestMove, Val]),
|
||||||
|
successeur(J, S, BestMove),
|
||||||
|
write(BestMove), write(' -> '), write(Val), nl,
|
||||||
|
printState(S), nl,
|
||||||
|
adversaire(J, A),
|
||||||
|
iter(A, S).
|
||||||
|
|
191
tp2/tictactoe.pl
Normal file
191
tp2/tictactoe.pl
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
/*********************************
|
||||||
|
DESCRIPTION DU JEU DU TIC-TAC-TOE
|
||||||
|
*********************************/
|
||||||
|
|
||||||
|
situation_initiale([ [_,_,_],
|
||||||
|
[_,_,_],
|
||||||
|
[_,_,_] ]) .
|
||||||
|
|
||||||
|
% Convention (arbitraire) : c'est x qui commence
|
||||||
|
joueur_initial(x).
|
||||||
|
|
||||||
|
% Definition de la relation adversaire/2
|
||||||
|
adversaire(x,o).
|
||||||
|
adversaire(o,x).
|
||||||
|
|
||||||
|
situation_terminale(Situation) :-
|
||||||
|
ground(Situation).
|
||||||
|
|
||||||
|
/***************************
|
||||||
|
DEFINITIONS D'UN ALIGNEMENT
|
||||||
|
***************************/
|
||||||
|
alignement(L, Matrix) :- ligne(L,Matrix).
|
||||||
|
alignement(C, Matrix) :- colonne(C,Matrix).
|
||||||
|
alignement(D, Matrix) :- diagonale(D,Matrix).
|
||||||
|
|
||||||
|
ligne(L, M) :-
|
||||||
|
nth1(_, M, L).
|
||||||
|
|
||||||
|
colonne(C, M) :-
|
||||||
|
colonne(C, M, _).
|
||||||
|
|
||||||
|
colonne([E | Crest], [L | Mrest], Ncol) :-
|
||||||
|
nth1(Ncol, L, E),
|
||||||
|
colonne(Crest, Mrest, Ncol).
|
||||||
|
|
||||||
|
colonne([], [], _).
|
||||||
|
|
||||||
|
diagonale(D, M) :-
|
||||||
|
premiere_diag(1,D,M).
|
||||||
|
|
||||||
|
diagonale(D, M) :-
|
||||||
|
length(M, N),
|
||||||
|
seconde_diag(N,D,M).
|
||||||
|
|
||||||
|
premiere_diag(_, [], []).
|
||||||
|
premiere_diag(K, [E | D], [Ligne | M]) :-
|
||||||
|
nth1(K, Ligne, E),
|
||||||
|
K1 is K + 1,
|
||||||
|
premiere_diag(K1, D, M).
|
||||||
|
|
||||||
|
seconde_diag(_,[],[]).
|
||||||
|
seconde_diag(K, [E | D], [Ligne | M]) :-
|
||||||
|
nth1(K, Ligne, E),
|
||||||
|
K1 is K - 1,
|
||||||
|
seconde_diag(K1, D, M).
|
||||||
|
|
||||||
|
% Alignement potentiel possible pour le joueur J
|
||||||
|
possible([X | L], J) :- unifiable(X, J), possible(L, J), !.
|
||||||
|
possible([], _).
|
||||||
|
|
||||||
|
unifiable(X, _) :-
|
||||||
|
var(X),
|
||||||
|
!.
|
||||||
|
unifiable(_, J) :-
|
||||||
|
var(J),
|
||||||
|
!.
|
||||||
|
unifiable(X, J) :-
|
||||||
|
X == J.
|
||||||
|
|
||||||
|
% Vérifie que Ali est un alignement gagnant pour J
|
||||||
|
alignement_gagnant(Ali, J) :-
|
||||||
|
ground(Ali),
|
||||||
|
maplist(=(J), Ali).
|
||||||
|
|
||||||
|
% Un alignement perdant pour J est un alignement gagnant pour son adversaire
|
||||||
|
alignement_perdant(Ali, J) :-
|
||||||
|
adversaire(J, O),
|
||||||
|
alignement_gagnant(Ali, O).
|
||||||
|
|
||||||
|
|
||||||
|
/* ****************************
|
||||||
|
DEFINITION D'UN ETAT SUCCESSEUR
|
||||||
|
****************************** */
|
||||||
|
successeur(J, Etat, [Nl, Nc]) :-
|
||||||
|
nth1(Nl, Etat, L),
|
||||||
|
nth1(Nc, L, Current),
|
||||||
|
\+ ground(Current),
|
||||||
|
Current = J.
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
EVALUATION HEURISTIQUE D'UNE SITUATION
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
1/ l'heuristique est +infini si la situation J est gagnante pour J
|
||||||
|
2/ l'heuristique est -infini si la situation J est perdante pour J
|
||||||
|
3/ sinon, on fait la difference entre :
|
||||||
|
le nombre d'alignements possibles pour J
|
||||||
|
moins
|
||||||
|
le nombre d'alignements possibles pour l'adversaire de J
|
||||||
|
*/
|
||||||
|
|
||||||
|
%1
|
||||||
|
heuristique(J, Situation, H) :-
|
||||||
|
alignement(Alig, Situation),
|
||||||
|
alignement_gagnant(Alig, J),
|
||||||
|
H = 10000, % grand nombre approximant +infini
|
||||||
|
!.
|
||||||
|
|
||||||
|
% 2
|
||||||
|
heuristique(J, Situation, H) :-
|
||||||
|
alignement(Alig, Situation),
|
||||||
|
alignement_perdant(Alig, J),
|
||||||
|
H = -10000, % grand nombre approximant -infini
|
||||||
|
!.
|
||||||
|
|
||||||
|
% 3
|
||||||
|
heuristique(J, Situation, H) :- % cas 3
|
||||||
|
findall(Alig, alignement(Alig, Situation), L),
|
||||||
|
adversaire(J, O),
|
||||||
|
findall(AligPoss, (member(AligPoss, L), possible(AligPoss, J)), LpossJ),
|
||||||
|
findall(AligPoss, (member(AligPoss, L), possible(AligPoss, O)), LpossO),
|
||||||
|
length(LpossJ, NbJ),
|
||||||
|
length(LpossO, NbO),
|
||||||
|
H is NbJ - NbO.
|
||||||
|
|
||||||
|
% Affiche la grille
|
||||||
|
printState([]).
|
||||||
|
printState([R | Rest]) :-
|
||||||
|
printRow(R),
|
||||||
|
nl,
|
||||||
|
printState(Rest).
|
||||||
|
|
||||||
|
printRow([]).
|
||||||
|
printRow([X | Rest]) :-
|
||||||
|
(ground(X) ->
|
||||||
|
write(X)
|
||||||
|
;
|
||||||
|
write('_')
|
||||||
|
),
|
||||||
|
printRow(Rest).
|
||||||
|
|
||||||
|
|
||||||
|
% ----- Tests unitaires -----
|
||||||
|
|
||||||
|
testPossible :-
|
||||||
|
A = [_,_,_],
|
||||||
|
possible(A, x),
|
||||||
|
B = [x,_,x],
|
||||||
|
possible(B, x),
|
||||||
|
C = [_,o,x],
|
||||||
|
\+ possible(C, x).
|
||||||
|
|
||||||
|
testAlignementGagnant :-
|
||||||
|
A = [o,x,o],
|
||||||
|
B = [o,_,o],
|
||||||
|
C = [o,o,o],
|
||||||
|
\+ alignement_gagnant(A, o),
|
||||||
|
\+ alignement_gagnant(B, o),
|
||||||
|
\+ alignement_gagnant(A, _).
|
||||||
|
alignement_gagnant(C, o),
|
||||||
|
alignement_gagnant(C, J),
|
||||||
|
J == o,
|
||||||
|
|
||||||
|
testHeuristique :-
|
||||||
|
LS = [
|
||||||
|
[[[ _,_,_ ],
|
||||||
|
[ _,_,_ ],
|
||||||
|
[ _,_,_ ]], 0],
|
||||||
|
|
||||||
|
[[[ _,_,_ ],
|
||||||
|
[ _,o,_ ],
|
||||||
|
[ _,_,_ ]], 4],
|
||||||
|
|
||||||
|
[[[ x,x,o ],
|
||||||
|
[ o,o,x ],
|
||||||
|
[ x,o,x ]], 0],
|
||||||
|
|
||||||
|
[[[ x,_,_ ],
|
||||||
|
[ o,o,x ],
|
||||||
|
[ x,o,x ]], -1],
|
||||||
|
|
||||||
|
[[[ x,x,x ],
|
||||||
|
[ o,o,x ],
|
||||||
|
[ x,o,o ]], -10000]
|
||||||
|
],
|
||||||
|
forall(member([S, Ho], LS), (
|
||||||
|
heuristique(o, S, Ho),
|
||||||
|
Hx is -Ho,
|
||||||
|
heuristique(x, S, Hx)
|
||||||
|
)).
|
Loading…
Reference in a new issue