%**************************************************************************** %* Devoir de PROLOG * %* Julien Van Den Bossche / Benoît Moulin * %* cmoi@julienvdb.com / bmoulin@etu.info.unicaen.fr * %**************************************************************************** % **************************************************************** % * REPRESENTATION DE LA SCENE ET DES ACTIONS EN PROLOG * % **************************************************************** %vehicule(+Nom,+Type,+Couleur):- Un véhicule possède un Nom, un Type et une Couleur vehicule(v1, voiture, rouge). vehicule(v2, voiture, vert). vehicule(m1, moto, jaune). vehicule(m2, moto, rouge). vehicule(c1, camion, vert). %etat_courant(E):- permet de représenter l'état courant, E étant la file de vehicules :-dynamic(etat_courant/1). etat_courant([v1,vide,m1,vide,vide,v2,m2,c1,vide]). %initialisation de la file de voitures, le file est représentée par une liste de véhicules initialisation:- retract(etat_courant(_)), assertz(etat_courant([v1, vide, m1, vide, vide, v2, m2, c1])). %Affichage de l'état courant affiche([]). affiche([vide|Liste]) :- write(vide), write(' '), affiche(Liste). affiche([Debut|Liste]) :- vehicule(Debut, Type, Couleur), write('('), write((Debut, Type, Couleur)), write(') '), affiche(Liste). etat :- etat_courant(E), write('Etat courant : '), affiche(E). %vide(+Liste) :- teste si la liste Liste ne comporte que des vides vide([]). vide([vide|Liste]) :- vide(Liste). %******************************************** %* Tests de propriétés * %******************************************** %vérifie une liste de propriétés dans l'état courant. vrai(Propriete) :- etat_courant(E), vrai(E, Propriete). %vrai(Etat,Propriété):-vérifie si une propriété est respectées dans un état. vrai(_, []). %teste si un véhicule est de couleur "Couleur": on regarde si le nom du véhicule existe puis si vrai alors on regarde si la couleur du véhicule match avec la couleur demandée puis si vrai alors on teste les autres propriétés. vrai(Etat, [couleur(NomVehicule, Couleur)|L]) :- member(NomVehicule, Etat), %le véhicule doit appartenir à l'état vehicule(NomVehicule, _, Couleur), %On cherche un véhicule dont son nom et sa couleur matche avec NomVehicule et Couleur vrai(Etat, L). %on teste les autres propriétés %teste si un véhicule est de type "Type": on regarde si le nom du véhicule existe puis si vrai alors on regarde si le type du véhicule match avec le type demandé puis si vrai alors on teste les autres propriétés. vrai(Etat, [type(NomVehicule, Type)|Queue]) :- member(NomVehicule, Etat), %le véhicule doit appartenir à l'état vehicule(NomVehicule, Type, _), %On doit reconnaitre un véhicule dont son type matche avec Type(son nom aussi) vrai(Etat, Queue). %NomVehicule doit être dans la file puis tout ce qui est avant NomVehicule doit être vide et NomVehicule ne doit pas être vide. vrai(Etat, [queue_de_file(NomVehicule)|Queue]) :- NomVehicule\=vide, member(NomVehicule,Etat), append(L,[NomVehicule|_], Etat), vide(L), vrai(Etat,Queue). vrai(Etat, [tete_de_file(NomVehicule)|Queue]) :- member(NomVehicule,Etat), NomVehicule\=vide, member(NomVehicule,Etat), append(_, [NomVehicule|L], Etat), vide(L), vrai(Etat, Queue). %on cherche NomVehicule1, on prend la liste après NomVehicule1, on cherche NomVehicule2 dans cette dernière: si Vehicule2 n'est précédé que de vide avant alors vrai sinon faux vrai(Etat, [juste_derriere(NomVehicule1,NomVehicule2)|Queue]) :- NomVehicule1\=vide, NomVehicule2\=vide, member(NomVehicule1,Etat), member(NomVehicule2,Etat), append(_,[NomVehicule1|L1],Etat), append(L2,[NomVehicule2|_],L1), vide(L2), vrai(Etat, Queue). %après avoir trouvé NomVehicule1 on doit trouver NomVehicule2 vrai(Etat, [derriere(NomVehicule1,NomVehicule2)|Queue]) :- NomVehicule1\=vide, NomVehicule2\=vide, member(NomVehicule1,Etat), member(NomVehicule2,Etat), append(_,[NomVehicule1|L1],Etat), append(_,[NomVehicule2|_],L1), vrai(Etat, Queue). vrai(Etat, [devant(NomVehicule1,NomVehicule2)|Queue]) :- NomVehicule1\=vide, NomVehicule2\=vide, member(NomVehicule1,Etat), member(NomVehicule2,Etat), append(_,[NomVehicule2|L1],Etat), append(_,[NomVehicule1|_],L1), vrai(Etat, Queue). vrai(Etat, [juste_devant(NomVehicule1,NomVehicule2)|Queue]) :- NomVehicule1\=vide, NomVehicule2\=vide, member(NomVehicule1,Etat), member(NomVehicule2,Etat), append(_,[NomVehicule2|L1],Etat), append(L2,[NomVehicule1|_],L1), vide(L2), vrai(Etat, Queue). %******************************************** %* Les transitions * %******************************************** %transition(Etat,Action,Nouvel_Etat) :- Action fait passer Etat a Nouvel_Etat. Si l'action est impossible on affichera un message d'erreur. %permet d'avancer transition(Etat,avance(NomVehicule),Nouvel_Etat) :- %le véhicule ne doit pas être vide NomVehicule\=vide, %on cherche le nom du véhicule et on prend la liste des élémnts qui le succède (L1) append(Tete, [NomVehicule|L1], Etat), %On regarde si L1 commence par un vide append([vide], Reste, L1), %si c'est le cas on concaténe la liste des éléments avant NomVehicule avec la liste contenant vide append(Tete, [vide], L2), %puis on concaténe L2 avec la liste contenant le nom du véhicule et le reste de la file append(L2, [NomVehicule| Reste], Nouvel_Etat). %Quand on est en tête de file on agrandit la file transition(Etat,avance(NomVehicule),Nouvel_etat) :- NomVehicule\=vide, %on vérifie que véhicule n'est pas vide append(Tete, [NomVehicule], Etat), %on avance dans la liste jusqu'a trouver NomVehicule append(Tete, [vide, NomVehicule], Nouvel_etat). %on ajoute un vide devant NomVehicule. %permet de reculer transition(Etat,recule(NomVehicule),Nouvel_etat) :- NomVehicule\=vide, %On cherche NomVehicule, on prend la liste Debut des éléments avant NomVehicule puis la liste après : Reste append(Tete, [NomVehicule|Reste], Etat), %On cherche si Tete fini par un vide et on prend ce qui est avant le vide : L1 append(L1, [vide], Tete), %On ajoute à la fin de L1 un vide, ce qui donne L2 append(L1, [NomVehicule], L2), %On concaténe L2 un vide avec la liste Reste, ce qui donne le nouvel Etat append(L2, [vide|Reste], Nouvel_etat). %Dans le cas où NomVehicule est en queue de file, soit tête de liste transition([NomVehicule|Etat],recule(NomVehicule),Nouvel_etat) :- NomVehicule\=vide, %On construit une liste avec NomVehicule, un vide puis le reste de la liste(ce qu'il y avait après NomVehicule). append([NomVehicule, vide], Etat, Nouvel_etat). %permet de doubler : Nom1 double Nom2 transition(Etat,double(Nom1,Nom2),Nouvel_Etat) :- Nom1\=vide, %Nom1 ne doit pas être vide Nom2\=vide, %on cherche Nom1, on prend la liste qui est avant Nom1(Tete) puis celle qui est après (L1) append(Tete, [Nom1|L1], Etat), %Dans L1 on cherche Nom2 en regardant si on a une place après Nom2. On prend ce qui est avant Nom2 dans L1 : L2 append(L2, [Nom2,vide|Reste], L1), vide(L2), %L2 doit être vide %on concaténe le début de notre liste initiale (Tete) avec les espaces vides de L2 puis avec append(Tete, L2, L3), %L3 qui est la liste contenant la place libérée par Nom1 puis le vide devant Nom2 est remplacé par Nom1, %ce qui donne le nouvel état. append(L3, [vide, Nom2, Nom1|Reste], Nouvel_Etat). %Dans le cas où le véhicule à doubler est en début de file. transition(Etat,double(Nom1,Nom2),Nouvel_etat) :- Nom1\=vide, Nom2\=vide, %on prend la liste avant Nom1 : Tete puis la liste après Nom1 (L1) dans Etat append(Tete, [Nom1|L1], Etat), %On prend la liste avant Nom2 dans L1 puis les éléments qui précédent Nom2 append(L2, [Nom2], L1), %L2 doit être vide vide(L2), %on ajoute la Tete, la L2 ce qui donne L3 append(Tete, L2, L3), %Nom1 passe devant Nom2 et Nom1 libère une place vide append(L3, [vide, Nom2, Nom1], Nouvel_etat). transition(Etat,distance_de_securite,Nouvel_etat) :- %Quand il n'y a rien avant le véhicule choisi %On regarde si la queue de file commence par un vide et on récupère le reste composé d'un nom de véhicule puis d'une liste append([], [Nom1|L1], Etat), Nom1\=vide, %si le véhicule qui suit Nom1 est Nom2 alors on insère un espace entre les véhicules. append([Nom2], Queue, L1), Nom2\=vide, append([Nom1, vide, Nom2], Queue, Reste), %et on recommence avec la liste contenant les éléments suivant Nom2 transition(Reste,distance_de_securite,Nouvel_etat). transition(Etat,distance_de_securite,Nouvel_etat) :- %on cherche le premier espace vide, on crée 2 listes contenant les éléments avant et après cet espace append(Tete, [vide|L1], Etat), %Si L1 est composé de Nom1 puis Nom2, append([Nom1,Nom2], Reste, L1), Nom1\=vide, Nom2\=vide, %on prend l'espace vide et on le met entre Nom1 et Nom2 ->L2 append(Tete, [Nom1,vide,Nom2], L2), %On ajoute Reste à L2 -> Queue append(L2, Reste, Queue), %On recommence avec Reste sans revenir sur notre point de choix. transition(Queue,distance_de_securite,Nouvel_etat),!. transition(Etat,distance_de_securite,Etat). %message d'erreur si la transition n'est pas possible. %l'état après la transition est le même que l'état de départ . transition(E,Action,E) :- write(Action), write(' '), write('Action Impossible'),nl,write('Veuillez saisir une autre action'),nl. %action(+Action):- Effectue une action sur l'état courant et renvoi le nouvel etat. action(Action) :- etat_courant(E), transition(E,Action,Nouvel_Etat), retract(etat_courant(_)), assertz(etat_courant(Nouvel_Etat)), etat. % **************************************************************** % * VISUALISATION * % **************************************************************** :-consult('util_visu.pro'). %initialise l'état courant, ouvre une fenêtre, crée la route puis insére les véhicules dans la fenêtre initialisationGraphique :- initialisation, ouvre_fen, cree('RN13',_), visu. %permet de visualiser de l'état courant. visu :- etat_courant(E), visu_etat(E,0). visu_etat([],_). %si on a un vide on avance d'une place visu_etat([vide|L],Place) :- visu_etat(L,(Place + 1)). %Si on a un véhicule, on le crée, on le met à sa place dans la fenêtre et on va placer ce qui reste dans la liste. visu_etat([Nom|L],Place) :- vehicule(Nom, Type, Couleur),cree(Nom,Type,Couleur), deplace(Nom,Place), visu_etat(L,(Place + 1)). %-------------------------------------Visualisation des actions----------------------------------- %Dans cette partie on appelle les prédicats définis plus haut pour changer l'état courant, on efface les composants dans le fenêtre puis on remet les composants du nouvel état. %------------------------------------------------------------------------------------------------- visu_action(double(Nom1,Nom2)):- etat_courant(E), transition(E,double(Nom1,Nom2),Nouvel_Etat), retract(etat_courant(_)), assertz(etat_courant(Nouvel_Etat)), visu_raz,cree('RN13',_),visu. visu_action(avance(Nom1)):- etat_courant(E), transition(E,avance(Nom1),Nouvel_Etat), retract(etat_courant(_)), assertz(etat_courant(Nouvel_Etat)), visu_raz,cree('RN13',_),visu. visu_action(recule(Nom1)):- etat_courant(E), transition(E,recule(Nom1),Nouvel_Etat), retract(etat_courant(_)), assertz(etat_courant(Nouvel_Etat)),visu_raz,cree('RN13',_),visu. visu_action(distance_de_securite) :- action(distance_de_securite), visu_raz,cree('RN13',_), visu. % deboite permet de faire déboiter un véhicule. deboite(Nom,gauche) :- table_ref(Nom, B,_), get(B,x,X),get(B,y,Y), dim(largmax,N), Y1 is Y+N, send(B,move,point(X,Y1)). deboite(Nom,droite) :- table_ref(Nom, B,_), get(B,x,X),get(B,y,Y), dim(largmax,N), Y1 is (Y-N), send(B,move,point(X,Y1)).