POD -- 98/99
Les Robots
1 Graphisme
La gestion de l'interface graphique du projet est construite sur un
modèle client/serveur : un serveur graphique exécute les
requêtes graphiques que lui transmettent les clients graphiques.
Un premier serveur graphique graph_server
est défini il
crée l'environnemet graphique qui traite les requêtes de façon
synchrones : simple boucle de réception et de traitement des
requêtes.
Ce serveur synchrone est étendu par un serveur asynchrone,
enhanced_graph_server
qui comporte deux boucles : une boucle de
réception et une boucle d'émission. La boucle de réception stocke
les requêtes dans une file d'attente; la boucle d'émission fait
appel aux méthode du serveur synchrone pour traiter la requête et
tête de liste. Chacune de ces boucle est un processus indépendant
(c'est un petit modéle producteur/consommateur)
1.1 Les requêtes graphiques
Les requêtes graphiques sont toutes héritières de la classe virtuelle
class virtual graph_query = object method virtual draw : unit end
Chacune des requêtes agit sur un environnement (une fenêtre)
graphique suppossé(e) présent(e) en implantant la méthode draw
1exLe module Graphic_server
fourni les requêtes
class gq_clear : object method draw : unit end|
colore la totalité de la fenêtre graphique avec la couleur de fond
courrante.
class gq_line : Graphics.color -> int * int -> int * int ->
object method draw : unit end
La méthode draw
d'un objet
new gq_line c (x1,y1) (x2,y2)
trace une ligne de couleur
c
de (x1,y1)
à (x2,y2)
class gq_disk : Graphics.color -> int * int -> int ->
object method draw : unit end
La méthode draw
d'un objet new gq_disk c (x,y) r
trace
un disque de couleur c
, de centre (x,y)
et de rayon
r
class gq_kill : unit -> object method draw : unit end
La méthode draw
d'un objet new gq_kill ()
lève
l'exception Failure("gq_kill#draw : not an usable method")
Cet objet sera, en fait utilisé pour mettre fin à une session
graphique (voir : champs kill_signal
de la classe
graph_server
)
1exIl vous est loisible de définir de nouvelle requêtes afin
d'enrichir les figures affichables.
1.2 Le serveur synchrone
Le serveur synchrone est un objet de la classe
class graph_server :
int ->
int ->
object
val mutable flag_alive : bool
val kill_signal : graph_query
val sem : Mutex.t
val sync_channel : graph_query Event.channel
method alive : bool
method exit : unit
method get_channel : graph_query Event.channel
method private treat_query : graph_query -> unit
end
Lors de la création d'un objet de cette classe, sont crées :
- un canal de communication (
sync_channel
)
- une requête particulière (
kill_signal
)
- une fenêtre graphique aux dimension données par les deux
paramètres de la classe
- un processus léger exécutant la boucle réception/traitement
L'intégrité de l'exécution des requêtes est assurée par le
sémaphore sem
géré par la méthode privée
treat_query
1.3 Le client synchrone
Un client synchrone est un objet de la classe
class graph_client :
#graph_server ->
object method send : graph_query -> unit end
qui se passe de commentaire
1.4 le serveur assynchrone
Un serveur assynchrone est un objet de la classe
class enhanced_graph_server :
int ->
int ->
object
val async_channel : graph_query Event.channel
val async_sem : Mutex.t
val async_signal : Condition.t
val mutable flag_alive : bool
val kill_signal : graph_query
val mutable query_fifo : graph_query list
val sem : Mutex.t
val sync_channel : graph_query Event.channel
method alive : bool
method exit : unit
method get_async_channel : graph_query Event.channel
method get_channel : graph_query Event.channel
method private treat_query : graph_query -> unit
end
qui hérite de graph_server
. Lors de la création d'un objet,
sont crées (outre ce qui relève de la classe mère) :
- un canal de réception des requêtes (
async_channel
)
- un sémaphore (
async_sem
) assurant l'exclusion mutuelle
entre le traitement en réception et le traitement en réémission
- un signal (
async_signa
) servant au réveil de la boucle
de traitement
- une file d'attente (
query_fifo
) pour les requêtes
- un processus léger exécutant la boucle d'attente et de
stockage des requêtes
- un second processus léger chargé de la boucle de
retransmission des requêtes
La boucle de réception exécute la séquence
- aquérir une requête;
- poser le sémaphore
async_sem
;
- stocker la requête;
- libérer le sémaphore;
- réveiller la boucle de retransmission (signal
async_signal
);
- traiter, si besoin, la requête
kill_signal
La boucle de retransmission exécute la séquence
- poser le sémaphore
async_sem
;
- attendre signal de réveil (et sémaphore) si file vide;
- prendre la requête en tête de file;
- libérer le sémaphore et mourrir si la requête est
kill-signal
,
- traiter la requête; la retirer de la file et libérer le
sémaphore, sinon
1.5 Le client assynchrone
Un client assynchrone est un objet de la classe
class enhanced_graph_client :
#enhanced_graph_server ->
object
method async_send : graph_query -> unit
method send : graph_query -> unit
end
qui se passe également de commentaire.
2 Des robots et des mondes
Le monde et ses robots vivent, a priori, dans un rapport d'interaction
complèxe qu'il faut simplifier. Nous ferons le choix suivant : les
robots sont essentiellement passifs et le monde est moteur.
1exNous vous proposons d'organiser la définiton des mondes et des
robots de la façon suivante :
- un couple de classes (virtuelles)
mondeV
/robotV
fournissant les méthodes de bases attendues des mondes et des robots
- deux classes (virtuelles)
mondeV_display
et
robotV_display
fournissant chacune une méthode d'affichage
- une classe (virtuelle)
monde
héritant à la fois
de mondeV
et mondeV_display
et une classe robot
héritant à la fois de robotV
et robotV_display
2.1 Les bases
Les classes mondeV
et robotV
seront toutes deux
paramétriques ce qui permettra de résoudre le problème
sous-classe/sous-type vu en TD à propos des aventures de Ghandi
au MacDo.
Le monde
Le monde est un ensemble de cases accessibles par
leur coordonnées (un couple d'entier) il contient un ensemble de
robots situés chacun sur une case différente appartenant au monde.
1exVous déclarez donc la classe
class virtual ['a] mondeV hi li =
object
constraint 'a = <get_pos:int*int; set_pos:int*int -> unit; .. >
.
.
.
end
où hi et li sont les dimensions du monde (hauteur et
largeur) Le paramètre 'a deviendra #robot
1exLa classe mondeV
comportera trois champs (variable d'instance) :
val h : int
contenant la hauteur du monde;
val l : int
contenant la largeur du monde;
val mutable roblist : 'a list
qui contiendra la liste des
robots.
1exElle fournira cinq méthode de classe :
method add : 'a -> unit
permettant d'ajouter un robot à la
liste;
method free_places : int * int -> (int * int) list
donnant la
liste des places libres autour d'une case donnée par l'argument de
la méthode;
method get_dim : int * int
renvoie les dimensions du monde;
method get_roblist : 'a list
renvoie la liste des robots
présents;
method is_free : int * int -> bool
indiquant si la case
donnée par l'argument est libre ou non;
1exEnfin, elle déclarera deux méthodes virtuelles :
method virtual is_legal : int * int -> bool
indiquant si oui ou
non un couple d'entier désigne une case du monde
method virtual normalize : int * int -> int * int
ramenant un
couple d'entiers à des coordonnées licites du monde
(l'implémentation dépendra de la topologie du monde et du bon
vouloir du programmeur)
Les robots
Un robot est essentiellement caractérisé
par sa position et un vecteur vitesse indiquant son
déplacement. D'une position (x,y) avec la vitesse (vx,vy) on
arrive à la case (x+vx, y+vy)
1exVous déclarerez la classe virtuelle
class virtual ['a] robotV (xi,yi) (vxi, vyi) =
object
constraint 'a = <get_roblist: 'a #robotV list ; ..>
.
.
.
end
où (xi,yi) et (vxi, vyi) donnent, respectivement, la
position et la vitesse initiales du robot. La paramètre 'a
deviendra un monde.
1exLa classe robotV
contient les quatre champs :
val mutable vx : int
vitesse en x;
val mutable vy : int
vitesse en y;
val mutable x : int
position en x;
val mutable y : int
position en y.
1exElle fournit les quatre méthodes usuelles
method get_pos : int * int
method get_speed : int * int
method set_pos : int * int -> unit
method set_speed : int * int -> unit
1exElle fournit enfin la méthode virtuelle
method virtual next_position : 'a -> int * int
qui, étant
donné un monde (le paramètre 'a) calcule une prochaine
position (de son implémentation dépendra le comportement des
divers robots : immobile, à mouvement aléatoire, à mouvement
déterministe, etc ...)
2.2 Mondes et robots affichables
Les deux (virtuelles) classes que nous proposons ici sont
essentiellement chargées de fournir une méthode d'affichage.
Ce sont encore des classes paramétrées pour contourner le
problème évoqué plus haut.
Le monde
Vous déclarez la classe
class virtual ['a] robotV_display :
object
method virtual display : unit
end
qui se passe de commentaire.
Les robots
Vous déclarez la classe
class virtual ['a] robotV_display :
object
method virtual display : unit
end
qui se passe tout autant de commentaire.
Commentaire
Pour obtenir un mode d'affichage particulier (texte ou graphique), on
procèdera par héritage en implémentant la méthode
display
Les autres méthode resteront, à ce stade
virtuelles.
2.3 Les classes finales
Les classes finales sont celles qui permettent des créer des mondes
et des robots aux caractéristiques (ie : méthodes)
complètement définies.
Le(s) monde(s)
Un monde final s'obtient en héritant à
la fois d'un monde de base (mondeV
) et d'un monde affichable
(mondeV_display
) et en implémentant les méthodes restées
virtuelles. On rajoutera également une méthode
fiat_lux : unit -> unit
chargée de donner vie aux
robots. On pourra soit choisir une boucle parcourant la liste des
robots et les activant (par appel aux méthodes idoines) tour à
tour, soit créer un processus léger pour chaque robot : il faudra
alors songer aux problème de synchronisation et utilisant, par
exemple, un mécanisme de sémaphores.
Les robots
Un robot final s'obtient par héritage
multiple de robotV
et robotV_display
en définissant sa
stratégie de mouvement (next_position
) et son mode d'affichage
(display
)
2.4 Résumé des épisodes précédents
Page initiale Maison
Page précédente POD
This document was translated from LATEX by HEVEA.