Vous êtes sur la page 1sur 8

Mini-Projet en Prolog

1- Planification dynamique en Prolog :

Le but du mini-projet est d'explorer les aspects "dynamiques" de Prolog via l'application
classique de la planification d'actions dans le "monde des blocs".

2- Déclarer des faits dynamiques :

Le "monde des blocs" est constitué d'objets élémentaires (boîtes, cubes, boules, pyramides...)
disposés dans un espace plan. On va réaliser des actions dans ce monde (déplacer un objet
d'un endroit à un autre). Par exemple, on va passer de la situation 1 à la situation 2 :

situation 1 situation 2

Cela signifie que des faits vrais à un certain moment (le fait que le bloc a soit sur le bloc b),
deviennent faux à d'autres. Pour déclarer de tels faits, on déclare certains prédicats comme
"dynamiques".

:- dynamic(sur/2).
sur(a,b).
sur(b,c).
sur(c,table).

On ne peut déplacer qu'un objet qui est "libre", c'est-à-dire en haut d'une pile, et on ne peut le
mettre que sur la table (qui est supposée toujours "libre") ou en haut d'une autre pile. En
réalisant ce déplacement, on retire de l'ensemble des faits l'ancien positionnement du bloc
déplacé, et on ajoute son nouveau positionnement. On peut donc définir l'action de
déplacement avec les prédicats suivants :
libre(table).
libre(a).

met_sur(X,Y) :-
X \== table,
X \== Y,
libre(X),
libre(Y),
sur(X,Z),
retract(sur(X,Z)),
assert(sur(X,Y)),
assert(deplace(X,Y)). /*ajoute le déplacement comme fait*/

Dans ce code, le méta prédicat "retract(...)" retire de la base de faits ce qui ne doit plus être
considéré comme vrai, tandis que "assert(...)", lui, ajoute un nouveau fait devenu vrai. L'action
de déplacement elle-même est stockée dans le terme "deplace(X,Y)". Une fois ce code chargé,
on peut réaliser les opérations suivantes, où le méta prédicat listing(Predicat) donne toutes les
instances vraies de Predicat :

| ?- listing(libre).

libre(table).
libre(a).

true
| ?- listing(sur).

sur(a,b).
sur(b,c).
sur(c,table).

true
| ?- met_sur(a,table).

true
| ?- listing(sur).

sur(a,table).
sur(b,c).
sur(c,table).

true
| ?- listing(deplace).

deplace(a,table).

true
| ?- listing(libre).

libre(table).
libre(a).

3- Planification récursive :

Faire de la planification consiste à créer des plans, c'est-à-dire des suites d'actions, permettant
de passer d'un état à un autre. Ici, notre plan sera constitué de l'ensemble des actions de
déplacement effectuées, on le visualisera donc par l'instruction listind(deplace). Chaque action
dans un plan doit être définie en 3 étapes :
1. les préconditions : ensemble des faits qui doivent être vrais pour que l'action puisse être
réalisée
2. la suppression des faits devenus faux après l'action
3. l'ajout des nouveaux faits vrais, y compris de l'action réalisée

Dans l’exemple précédent, vous pouvez vérifier que si les pré conditions ne sont pas remplies,
l’action n’est pas effectuée:

| ?- met_sur(c,a).
false

Évidemment, pour que les pré conditions soient vérifiées, il suffit de réaliser des actions qui les
rendent vraies, ce qui peut amener à définir des actions récursives. Ecrire une version récursive
de met_sur en définissant un prédicat libere qui rend vraie la pré condition libre en réalisant
une action si besoin. Cette version récursive devrait permettre de mettre le bloc b sur le bloc a
en passant par plusieurs étapes intermédiaires.
4- Environnement de test et d'exécution :

on a utilisé l'interpréteur et EDI “SWI-Prolog” .

5- Le code entier :

/* prolog Actions et plans */

:- dynamic sur/2.

sur(a,b).
sur(b,c).
sur(c,table).

met_sur(A,B) :-
A \== table,
A \== B,
sur(A,X),
libre(A),
libre(B),
retract(sur(A,X)),
assert(sur(A,B)),
assert(deplace(A,X,B)).

libre(table).
libre(B) :-
not(sur(_X,B)).

/* ----------------------------------------------*/

r_met_sur(A,B) :-
sur(A,B).
r_met_sur(A,B) :-
not(sur(A,B)),
A \== table,
A \== B,
libere(A), /* "action" utilisé comme pré condiction */
libere(B),
sur(A,X),
retract(sur(A,X)), /*enlève un fait qui n est plus jugé comme vrai*/
assert(sur(A,B)), /*ajoute un fait qui est considéré comme vrai*/
assert(deplace(A,X,B)).

libere(table). /* c’est à dire il ya un vide sur la table */


libere(A) :- /* c’est à dire déja libre */
not(sur(_X,A)).
libere(A) :-
A \== table,
sur(X,A),
libere(X), /* recursion */
retract(sur(X,A)),
assert(sur(X,table)),
assert(deplace(X,A,table)).

do(Blist) :-

do_all(Blist,Blist).
do_all([B|R],Allgoals) :- /* déjà vrai */
call(B),
do_all(R,Allgoals),!. /* continuer avec le reste des buts */

do_all([B|_],Allgoals) :- /* il faut le traiter */


achieve(B),
do_all(Allgoals,Allgoals). /* revenir en arrière et vérifier les anciens buts */
do_all([],_Allgoals). /* finis */

achieve(sur(A,B)) :-
r_met_sur(A,B).

6- Exemple d’exécution :

?- do([sur(a,table),sur(b,a),sur(c,b)]).
true.

?- listing(deplace).
:- dynamic deplace/3.

deplace(a, b, table).
deplace(b, c, a).
deplace(c, table, b).

true.

?-

7- Conclusion :

On peut améliorer notre monde des blocs en ajoutant des formes nouvelles :
● des pyramides, qui peuvent se poser sur la table mais sur lesquelles on ne peut rien
poser
● des boules qui peuvent être mises dans des boîtes, quand elles sont vides (si les cubes
sont en fait des boîtes) mais sur lesquelles on ne peut rien poser
● des blocs allongés plus grands que les cubes, qu'on peut empiler les uns sur les autres
et sur lesquels on peut mettre des cubes ou des boîtes, mais qu'il vaut mieux ne pas
poser eux-mêmes sur des cubes ou des boîtes.