L'âne rouge est un casse-tête dont le but est d'amener l'âne à la barrière de son champ en contournant les autres animaux et en demandant à ceux-ci de se déplacer au mieux.
Ceci s'effectue en faisant glisser successivement des pièces rectangulaires (représentant les animaux) comme on le ferrait au jeu de taquin et ce, jusqu'à ce que que l'âne rouge (représenté par le grand carré rouge) se retrouve en face de l'ouverture du cadre.
Une configuration est l'état du problème à un instant donné. Vous devez définir comment vous allez mémoriser chaque configuration. On peut envisager la structure de liste contenant cinq listes :
[[ja,ro,ro,ja], [ja,ro,ro,ja], [no,bl,bl,no], [no,ma,ma,no], [or,vi,vi,or]]).
La première liste donne les carrés de 1*1 qui sont sur la ligne la plus haute, la seconde..., la dernière liste donne les carrés de 1*1 qui sont sur la ligne la plus basse.
Votre système doit évoluer itérativement de la configuration initiale (celle représentée ci-dessus) vers une configuration correspondant à un état final (l'âne rouge prêt de la barrière).
?- init(ConfInitiale),glissement(ma,b,ConfInitiale,Confb). ?- init(CI),glissement(P,D,CI,C2),glissement(P2,D2,ConfInitiale,C3).
Pour construire la liste de tous les successeurs d'une configuration, on peut utiliser le prédicat findall à trois arguments comme suit
findall(Motif,But(X1,...,Xn),Liste)
Étant donné un prédicat de But(X1,...,Xn) entre les variables X1,...,Xn et un motif Motif portant sur une partie des variables X1,...,Xn, la liste Liste contient toutes les instances de Motif qui ont rendu le but vrai. Si le But n'a pas de solution, Liste est vide.
Par exemple dans le TP sur la récursivité, le predicat inside(X,Y) était vrai si la poupée X était à l'intérieur de la poupée Y. Pour récupérer la liste de toutes les poupées à l'intérieur de katarina il suffit d'effectuer la requête :
?- findall(X,inside(X,katarina),L).
Le programme développé doit trouver un cheminement entre l'état initial et un état final. Ces déplacements peuvent être mémorisés à l'aide d'une liste de paires ((X,Y),D) où (X,Y) sont les coordonnées de la pièce qui bouge et D est la direction dans laquelle cette pièce bouge.
Les chemins peuvent être modélisés comme une liste [((Xn,Yn),Dn),...,((X3,Y3),D3),((X2,Y2),D2),((X1,Y1),D1)] qui stipule qu'on a
Le code Prolog effectuant un parcours en largeur d'abord vous est fourni ci-dessous.
Commencer par insérer en tête de votre fichier Prolog
:-use_module(library(assoc)).
Insérer à la suite le programme suivant :
/* successeurs_liste(L,Sl) est vrai si Sl est la liste
de tous les successeurs des configurations de la liste L*/ successeurs_liste(L,Sl):- maplist(successeurs,L,Lp), flatten(Lp,Lpp), list_to_assoc(Lpp,A), assoc_to_list(A,Sl).
/* list_minus(L1,L2,L3) est vrai si
L3 est la liste de tous les éléments Conf-_ de L1 dont Conf n appartient pas à L2 */ list_minus([],_,[]). list_minus([Conf-_|L1],L2,Res):- member(Conf,L2),!, list_minus(L1,L2,Res). list_minus([El|L1],L2,[El|Res]):- list_minus(L1,L2,Res). filtre_conf(X-_,X).
/* but(L,Ch) est vrai si L contient une configuration
finale et si Ch est le chemin qui a mené a cette configuration */ but([Conf-Chemin|_],Chemin):-final(Conf),!. but([_|L],Chemin):-but(L,Chemin).
/* largeur(Atraiter,Visites,C,Res) est vrai si
Atraiter est la liste des configurations-chemins qu il reste à visiter Visites est la liste des configurations déjà visités C est l entier représentant la profondeur de recherche Res est le chemin menant à une configuration finale */ largeur(Atraiter,_,_,Res):- but(Atraiter,Res),!. largeur(Atraiter,Visites,C,Res):- Cp is C+1, writef("boucle %d \n",[C]), maplist(filtre_conf,Atraiter,V1), append(V1,Visites,Omis), successeurs_liste(Atraiter,Succ), list_minus(Succ,Omis,Atraiter2), largeur(Atraiter2,Omis,Cp,Res).
/* resoud(_) est vrai si le programme trouve une solution.
Dans ce cas, la solution est affichée. */ resoud(_):- get_time(T0), init(X), largeur([X-[]],[],0,Res), writeln(Res), get_time(T1), DT1 is T1 - T0, writef('Duree : % \n',[DT1]).