![]() |
Apprentissage de la programmation en
P_LOGO
|
![]() |
Cette partie présente une illustration de la^utilisation des propriétés. Le programme suivant cherche à identifier un nom après une suite de questions. En cas da^ignorance, il sa^alimente des informations demandées à la^utilisateur. dans notre exemple, ca^est le nom da^un animal qui est recherché.
Pour commencer, il faut imaginer la^organisation
des connaissances comme un arbre. Il y a des n
A chaque fois, on a deux cas possibles :
On est sur un fruit : alors le programme propose le nom de la^animal.
On est sur un n
Voici un arbre à cinq noms :
deux n

Le programme doit pouvoir :
Prenons le programme procédure par procédure. La première, ca^est DEPART. Elle est chargée da^initialiser la base des connaissances (si besoin est) et de démarrer la recherche.
POUR DEPART
SI NON NOMè "PREMIER [DONNE "PREMIER "PREMNOM DPROP "PREMNOM "FINè VRAI DPROP "PREMNOM "NOMFIN [le singe]]
PROPOSE :PREMIER
FIN
Pour savoir si la base des connaissances est vide, on teste si "PREMIER est un nom. Ca^est le cas si le nom déjà été déclaré, par exemple avec un DONNE. Si la base est vide, la chose donnée à PREMIER est PREMNOM ; puis on donne au nom PREMNOM les propriétés suivantes : FINè VRAI et NOMFIN [le singe]. La propriété FINè Est vraie si le nom contient un animal, sinon, il sa^agira da^une question. La propriété NOMFIN a pour valeur une liste désignant un animal. La variable PREMIER a pour valeur le nom du premier élement de la^arbre.
La procédure exécutée est PROPOSE avec comme paramètre la chose donnée à PREMIER ca^est-à-dire le point da^entrée dans la^arbre.
POUR PROPOSE :NOM
EC []
SI RPROP :NOM "FINè [TERMINE :NOM STOP]
EC RPROP :NOM "QUESTION
EC PH "1. RPROP :NOM "ITEM1
EC PH "2. RPROP :NOM "ITEM2
PROPOSE RPROP :NOM MOT "REPONSE ATTENDREREPONSE [1 2]
FIN
Le rôle de la procédure-récursive
PROPOSE est da^identifier
sa^il sa^agit da^un fruit ou da^un n
FINè a
pour valeur FAUX,
car il ne sa^agit pas da^un fruit, mais da^un n
QUESTION a pour valeur une liste : le texte de la question à poser.
ITEM1 qui a pour valeur la première réponse possible à la question qui mène au nom désigné par la valeur de la propriété REPONSE1.
ITEM2 qui a pour valeur la seconde réponse possible à la question. Cette réponse mène à la valeur de la propriété REPONSE2.
La procédure-opération ATTENDREREPONSE rend la touche entrée au clavier par la^utilisateur. Elle prend comme argument une liste contenant les caractères permis.
POUR ATTENDREREPONSE :PARMI
SOIT "TOUCHE LISCAR
RENDS SI NON MEMBREè :TOUCHE :PARMI [ATTENDREREPONSE :PARMI] [:TOUCHE]
FIN
On stocke dans la variable locale TOUCHE le caractère entré au clavier. Ensuite, on rend soit ce caractère sa^il fait parti de la liste des caractères permis, soit le résultat de ATTENDREREPONSE sa^il sa^agit da^un mauvais caractère. Bref, on boucle jusqua^à ce que le caractère fasse parti de la liste des caractères entrée en paramètre.
La procédure suivante traite le cas où la^on se trouve sur un fruit. La^argument est le nom du fruit. Elle propose le nom de la^animal et demande confirmation à la^utilisateur. Si la^utilisateur est satisfait de la proposition, la procédure sa^achève. Sinon, la^utilisateur est invité à compléter la base des connaissances.
POUR TERMINE :NOM
EC PH PH [Est-ce] RPROP :NOM "NOMFIN [è (<O>ui/<N>on)]
SI EGALè ATTENDREREPONSE [O N] "O [STOP]
EC [Je ne connais pas ce qu'il faut trouver.]
EC [Veux-tu me l'apprendre è (<O>ui/<N>on)]
SI EGALè ATTENDREREPONSE [O N] "O [APPRENDRE :NOM] [EC [Je resterais ignorant.]]
FIN
Tout cela est relativement simple. Ces quelques procédures suffiraient si la base était déjà définie. Da^ailleurs, pour y voir encore plus clair, voici les propriétés (obtenues avec IMPROPS) correspondant au dernier la^arbre exemple (avec la vache, la^homme et le porc). Ce ne sont les seules indispensables pour le moment.
DPROP "NOM1 "FINè FAUX
DPROP "NOM1 "QUESTION [De quoi se nourrit-il è]
DPROP "NOM1 "REPONSE1 [Des plantes.]
DPROP "NOM1 "REPONSE2 [De tout.]
DPROP "NOM1 "ITEM1 "NOM2
DPROP "NOM1 "ITEM2 "NOM3
DPROP "NOM2 "FINè VRAI
DPROP "NOM2 "NOMFIN [la vache]
DPROP "NOM3 "FINè FAUX
DPROP "NOM3 "QUESTION [Sur combien de pattes marche-t-il è]
DPROP "NOM3 "REPONSE1 [Deux.]
DPROP "NOM3 "REPONSE2 [Quatre.]
DPROP "NOM3 "ITEM1 "NOM4
DPROP "NOM3 "ITEM2 "NOM5
DPROP "NOM4 "FINè VRAI
DPROP "NOM4 "NOMFIN [la^homme]
DPROP "NOM5 "FINè VRAI
DPROP "NOM5 "NOMFIN [le porc]
On remarque au passage que les noms na^ont pas da^importance. Il suffit que la variable PREMIER ait pour valeur la première entrée dans la^arbre, à savoir NOM1.
Il reste le plus compliqué, la^ajout
dans la base de nouveaux n
La procédure APPRENDRE prend un argument : le nom du fruit. Il faut rappeler qua^on exécute cette procédure lorsque la^utilisateur na^a pas été satisfait de la^animal proposé par le programme. Autrement dit, il y a un autre animal qui répond aux même questions (qui empreinte les mêmes branches) qua^il faut différencier de la^animal contenu dans la base. Imaginons que la^utilisateur a cherché le mouton et est tombé sur la vache. Il a accepté da^apprendre au programme ce nouvel animal. Le paramètre est donc "NOM2.
POUR APPRENDRE :NOM
; partie dialogue -----------------------
EC [Quel est son nom è (Ecrire en minuscules et précédé de l'article.)]
DONNE "NOUVEAU LL
EC PH PH PH PH [Quelle est la question qui permet de différencier ] RPROP :NOM "NOMFIN [de] :NOUVEAU [è (Terminer avec un point d'interrogation.)]
DONNE "QUESTION LL
EC PH PH PH PH [Quelle est la première réponse possible, et qui est vrai pour] :NOUVEAU [et fausse pour] RPROP :NOM "NOMFIN [è]
DONNE "ITEM1 LL
EC PH PH PH PH [Et enfin, quelle est la seconde réponse possible, et qui est vraie pour] RPROP :NOM "NOMFIN [et fausse pour] :NOUVEAU [è]
DONNE "ITEM2 LL
EC [Merci.]
; -------------------------------------
Suite à cette partie de dialogue entre le programme et la^utilisateur, les variables suivantes sont affectées :
NOUVEAU a pour valeur le texte du nouvel animal : [le mouton]
QUESTION
a pour valeur le texte de la question du n
ITEM1 a pour valeur le texte de la première réponse possible [Oui.]
ITEM2 a pour valeur le texte de la seconde réponse possible [Non.]
Le morceau de la^arbre qui nous intéresse ressemble à ceci :

; partie affectation ------------------
SOIT "NOUVEAUNOMFIN GENERENOM
SOIT "NOUVEAUNOMQUESTION GENERENOM
Ces deux instructions créent deux
nouveaux noms, il pour le n
DPROP :NOUVEAUNOMFIN "FINè VRAI
DPROP :NOUVEAUNOMFIN "NOMFIN :NOUVEAU
DPROP :NOUVEAUNOMFIN "PARENT :NOUVEAUNOMQUESTION
Le nouveau nom fruit a trois propriétés.
Les deux premières sont connues : FINè
pour dire que ca^est un fruit et pas un n
A gauche les noms, à droite les valeurs contenues.

Le nouveau n
DPROP :NOUVEAUNOMQUESTION "FINè FAUX
DPROP :NOUVEAUNOMQUESTION "QUESTION :QUESTION
DPROP :NOUVEAUNOMQUESTION "ITEM1 :ITEM1
DPROP :NOUVEAUNOMQUESTION "ITEM2 :ITEM2
DPROP :NOUVEAUNOMQUESTION "REPONSE1 :NOUVEAUNOMFIN
DPROP :NOUVEAUNOMQUESTION "REPONSE2 :NOM
Encore un nouveau morceau da^arbre, à partir de la nouvelle question :

Il reste à raccrocher la propriété parent à la question. Pour cela, il faut commencer par mettre en mémoire (variable locale) le nom du parent de la^ancien fruit (la vache)?E
SOIT "NOMPARENT RPROP :NOM "PARENT
?E et lui donner comme nouveau parent la nouvelle question.
DPROP :NOM "PARENT :NOUVEAUNOMQUESTION

SI VIDEè :NOMPARENT [DONNE "PREMIER :NOUVEAUNOMQUESTION STOP]
Cette dernière ligne traite le cas où le fruit précédent serait la^unique fruit de la^arbre. Dans ce cas, il na^y avait pas de parent. De plus, la nouvelle question est la nouvelle entrée dans la^arbre, da^où la^affectation de la variable PREMIER.
Occupons-nous maintenant du cas complémentaire.
DPROP :NOUVEAUNOMQUESTION "PARENT :NOMPARENT
La nouvelle question a pour parent la^ancien parent de la^ancien fruit.

Enfin, on raccroche la branche du parent allant vers la réponse.
DPROP :NOMPARENT SI EGALè RPROP :NOMPARENT "REPONSE1 :NOM ["REPONSE1] ["REPONSE2] :NOUVEAUNOMQUESTION

FIN
A la fin de cette procédure, la^arbre complet (uniquement les valeurs) est celui-ci :

Pour ceux qui connaissent, on a fonctionné
un peu comme avec des pointeurs. Vous aurez compris pourquoi il était
si important de connaître le parent da^un nom : pour pouvoir introduire
un nouveau n
Lors de la création da^un nouveau
fruit ou da^un nouveau n
POUR GENERENOM
SOIT "NOUVEAUNOM MOT "NOM HASARD 10000
RENDS SI NOMè :NOUVEAUNOM [GENERENOM] [:NOUVEAUNOM]
FIN
Le nom sera constitué des trois lettres N, O et M suivi da^un nombre entier au hasard en 0 et 10000. Si le hasard fait mal les choses et que le nom existe déjà, on recommence la génération da^un nom.
Avec les propriétés REPONSE1,
REPONSE2 et PARENT,
de na^importe quel n
Par exemple, il est possible de connaître
tous les fruits qui découlent da^un n
POUR AFFICHEDESCENDANTS :NOM
SI RPROP :NOM "FINè [EC RPROP :NOM "NOMFIN STOP]
On regarde si le nom courant (la chose de la^argument) est un fruit. Dans ce cas, on affiche le texte du fruit et on arrête, il na^y a pas da^enfant à un fruit.
Ensuite, on relance la procédure
avec chacun des deux enfants (les réponses) du n
AFFICHEDESCENDANTS RPROP :NOM "REPONSE1
AFFICHEDESCENDANTS RPROP :NOM "REPONSE2
FIN
Par exemple, voici la^effet de la commande
AFFICHEDESCENDANTS "NOM3
(qui est le n
la^homme
le porc
De même, on peut vouloir afficher
tous les n
POUR AFFICHEDETERMINENTS :NOM
SOIT "NOMPARENT RPROP :NOM "PARENT
Comme on va sa^en servir à plusieurs reprises, on donne à une variable locale le nom du parent du nom courant.
SI VIDEè :NOMPARENT [STOP]
Sa^il na^a pas de parent, on arrête, car on est arrivé à la^entrée de la^arbre (seul nom sans parent).
EC PH RPROP :NOMPARENT "QUESTION RPROP :NOMPARENT SI EGALè RPROP :NOMPARENT "REPONSE1 :NOM ["ITEM1] ["ITEM2]
La ligne précédente affiche le texte de la question du parent suivit du texte de la réponse qui a mené au nom courant.
AFFICHEDETERMINENTS :NOMPARENT
La procédure est récursive. On recommence la^opération avec comme paramètre le nom du parent du nom courant.
FIN
Voici le résultat de la commande AFFICHEDETERMINENTS "NOM4 (qui est le fruit " la^homme ").
Sur combien de pattes marche-t-il è Deux.
De quoi se nourrit-il è De tout.
Cette dernière procédure est intéressante, mais son utilisation malaisée. En effet, il faut connaître le nom du fruit. Il faudrait une procédure qui trouve le nom de fruit da^après le texte (valeur de la propriété NOMFIN du fruit). Ca^est le rôle de la procédure TROUVENOMFRUIT qui prend pour argument un mot du texte du fruit recherché.
POUR TROUVENOMFRUIT :TEXTE
TROUVENOMFRUIT1 :PREMIER :TEXTE
FIN
Cette procédure na^est là que pour ajouter en argument la^entrée de la^arbre pour la commande de TROUVENOMFRUIT1.
POUR TROUVENOMFRUIT1 :NOM :TEXTE
Cette procédure prend pour argument
un nom (n
SI MEMBREè :TEXTE RPROP :NOM "NOMFIN [RENDS :NOM STOP]
Si le texte recherché est contenu dans la valeur de la propriété NOMFIN, ca^est gagné : on rend le nom courant et on arrête.
SI RPROP :NOM "FINè [RENDS "SANS_ISSUE STOP]
Si le nom courant est un fruit, comme le texte na^a pas été trouvé, on sait que ce na^est pas une bonne branche, on arrête.
Si on continue, ca^est qua^il sa^agit da^un
n
SOIT "RECH1 TROUVENOMFRUIT1 RPROP :NOM "REPONSE1 :FRUIT
On attribue à une variable locale
le résultat de la recherche dans la sous partie de la^arbre de la première
branche du n
RENDS SI NEGALè "SANS_ISSUE :RECH1 [:RECH1] [TROUVENOMFRUIT1 RPROP :NOM "REPONSE2 :FRUIT]
Si le nom a été trouvé
dans la première branche, on rend le nom. Sinon, on cherche dans la
sous partie de la^arbre de la seconde branche du n
FIN
Par exemple, la^exécution de la commande EC TROUVENOMFRUIT "porc produit :
NOM5
Certes, ça ne sert à rien tout seul, mais associé à AFFICHEDETERMINENTS, ça devient intéressant. On peut maintenant rehcerche les déterminents du mouton, alors qua^on na^en connaît pas le nom.
AFFICHEDETERMINENTS TROUVENOMFRUIT "mouton
A-t-il de la laine è Oui.
De quoi se nourrit-il è De plantes.
Joli non è
On peut imaginer les commandes suivantes :
AFFICHEDETERMINENTS TROUVENOMANIMAL "baleine
AFFICHEDESCENDANTS RPROP TROUVENOMANIMAL "singe "PARENT
Il reste que la base est en mémoire, mais il ne faudrait pas avoir à réapprendre la^ensemble des animaux au programme à chaque fois qua^on sort et relance P_LOGO.
Il nous faut une procédure de sauvegarde de la base sur disque ainsi qua^une de son rappel.
POUR SAUVEGARDE
TAPE [Sauvegarde en cours...]
SORTIE "fiches
IMPROPS
IMNS
SORTIE 1
EC [ terminee.]
FIN
On oriente la sortie de la^affichage non plus vers la fenêtre textuelle, mais vers le fichier FICHES.LOG, on affiche toutes les définitions de variables et toutes les propriétés en mémoire, puis on dirige de nouveau la sortie vers la fenêtre textuelle.
Pour le chargement, rien de plus simple, un simple RAMENE du fichier FICHES.LOG (qui charge et interprète les commandes contenues dans le fichier) et le tour est joué.
POUR CHARGEMENT
TAPE [Récupération en cours...]
RAMENE "FICHES
EC [ terminee.]
FIN
Le petit programme est terminé. Bien entendu, des améliorations sont possibles :
On ne manque pas da^idées. Une autre encore : maintenant faisable, un arbre généalogique serait facile à faire, avec recherche des ancêtres, des descendants, des frères, des cousins?E Au travail.
Que c'est beau, le LOGO !
|
|