Voici une version simplissime du monde des robots utilisant des processus légers.
Le principe est le suivant : les robots vivent tous dans le même monde et ce sont les principaux acteurs. Chaque robot est un processus léger vivant en parallèle avec ses commensaux. Chaque robot calcule donc un déplacement en tenant compte de l'occupation du monde et effectue lui-même ce déplacement lorsqu'il est licite. Pour garantir la cohérence du monde, le calcul d'un déplacement et le mouvement effectif, affichage compris, est protégé par une section critique.
Source dûement commenté du programme
(* == Du monde en general Un monde est une matrice. On appelle une case de la matrice : 'position'. Certaines positions sont occupees, d'autres non. Un monde est donc caracterise par : - une largeur et une hauteur - une liste de robots presents (qui contiennent leur position) Un monde sait : - accepter un nouvel arrivant - dire si une position est libre ou non - dire si un couple d'entiers est une position (licite) ou non - donner la liste des positions libres autour d'une position donnee Enfin, un monde possede - un semaphore, a toutes fins utile *) class virtual world l0 h0 = object (* Largeur *) val l = (l0:int) (* Hauteur *) val h = (h0:int) (* Habitants *) val mutable robots = ([] : robot list) (* Un semaphore pour tous *) val m = Mutex.create() (* No comment *) method get_m = m (* No comment *) method get_robots = robots (* Ajout d'un habitant *) method add_robot r = robots <- r::robots (* Predicat position libre ? *) method is_free p = List.for_all (fun r -> r#get_pos <> p) robots (* Predicat : position licite du monde ? *) method virtual is_legal : (int * int) -> bool (* Listes des positions libres autour d'une position *) method virtual free_places : (int * int) -> (int * int) list end (* == Des robots en general Un robot est essentiellement une position. On lui donne egalement une largeur d'affichage (en pixel) Un robot sait : - fournir sa position - calculer une nouvelle position en fonction d'un monde donne - s'afficher sur une fenetre graphique implicite - s'effacer d'une fenetre graphique implicite - commencer a vivre (voire les instances 'robot_fix', 'robot_fou', etc ) - s'arreter (mais pas mourrir) *) and virtual robot i0 j0 = object (* Position *) val mutable i = (i0:int) val mutable j = (j0:int) (* Largeur (en pixels) du carre d'affichage *) val w = 15 (* No comment *) method get_pos = (i,j) (* Calcul prochaine position *) method virtual next_position : world -> (int * int) (* Affichage *) method virtual display : unit -> unit (* Disparition *) method virtual erase : unit -> unit (* Mise en mouvement *) method virtual run : world -> Thread.t (* Arret *) method virtual stop : unit -> unit end ;; (* == Un monde clos *) class closed_world l0 h0 = object(self) inherit world l0 h0 (* Predicat : position licite du monde ? *) method is_legal (i,j) = (0<=i) & (i(* Listes des positions libres autour d'une position *) method free_places (i,j)= let ijs = ref ([]:(int*int)list) in for di=(-1) to 1 do for dj=(-1) to 1 do let ij = (i+di, j+dj) in if (self#is_legal ij) & (self#is_free ij) then ijs := ij::!ijs done done; !ijs end ;; (* == Le robot fixe *) class robot_fix i0 j0 = object(self) inherit robot i0 j0 val c = Graphics.green method display () = Graphics.set_color c; Graphics.fill_rect (i*w) (j*w) w w method erase () = let fg' = Graphics.foreground in Graphics.set_color(Graphics.background); Graphics.fill_rect (i*w) (j*w) w w; Graphics.set_color(fg') method next_position (w:world) = i,j method run (w:world) = Thread.create self#display () method stop () = () end;; (* == Le robot fou *) class robot_fou i0 j0 = object(self) inherit robot i0 j0 val icone = let o, x = Graphics.white, Graphics.red in Graphics.make_image [|[|o;o;o;o;x;o;o;o;o;o;x;o;o;o;o|]; [|o;o;o;o;x;o;x;o;x;o;o;o;o;o;o|]; [|o;o;o;o;o;o;x;o;x;o;o;o;o;o;o|]; [|o;o;o;o;o;x;x;o;x;x;o;o;o;o;o|]; [|o;o;o;o;o;o;x;x;x;o;o;o;o;o;o|]; [|o;o;x;x;o;o;o;x;o;o;o;x;x;o;o|]; [|o;o;o;o;x;o;x;o;x;o;x;o;o;o;o|]; [|o;o;o;o;o;x;o;x;o;x;o;o;o;o;o|]; [|o;o;o;o;x;x;o;x;o;x;x;o;o;o;o|]; [|o;o;o;x;o;x;o;x;o;x;o;x;o;o;o|]; [|o;o;x;o;o;x;o;x;o;x;o;o;x;o;o|]; [|o;o;o;o;x;o;x;o;x;o;x;o;o;o;o|]; [|o;o;o;x;o;o;x;x;x;o;o;x;o;o;o|]; [|o;o;o;x;o;o;o;x;o;o;o;x;o;o;o|]; [|o;o;o;o;o;o;o;o;o;o;o;o;o;o;o|]|] val c = Graphics.red val mutable ttl = true method private set_ttl b = ttl <- b method display () = Graphics.set_color c; Graphics.draw_image icone (i*w) (j*w) method erase () = let fg' = Graphics.foreground in Graphics.set_color(Graphics.background); Graphics.fill_rect (i*w) (j*w) w w; Graphics.set_color(fg') method next_position (w:world) = let si,di = Random.int 2, Random.int 2 in let sj,dj = Random.int 2, Random.int 2 in let i' = if si= 0 then i+di else i-di in let j' = if sj= 0 then j+dj else j-dj in if List.mem (i',j') (w#free_places (i,j)) then (i',j') else (i,j) method private set_next_pos (i',j') = i <- i'; j <- j' method run (w:world) = let robot_fun () = while ttl do Mutex.lock w#get_m; self#erase(); self#set_next_pos (self#next_position w); self#display(); Mutex.unlock w#get_m; Thread.delay(Random.float(0.3)) done in Thread.create robot_fun () method stop () = ttl <- false end;; (* == Programme principal let l0,h0 = 20, 20;; let w = 15;; let geom = (" "^string_of_int (l0*w))^"x"^(string_of_int (h0*w));; Graphics.open_graph geom;; let w = new closed_world l0 h0;; let r1 = new robot_fix 10 10;; w#add_robot (r1:robot);; r1#run w;; let r2 = new robot_fix 17 10;; w#add_robot (r2:robot);; r2#run w;; let r3 = new robot_fix 10 17;; w#add_robot (r3:robot);; r3#run w;; let r4 = new robot_fix 17 17;; w#add_robot (r4:robot);; r4#run w;; let r5 = new robot_fou 5 5;; w#add_robot (r5:robot);; r5#run w;; let r6 = new robot_fou 5 5;; w#add_robot (r6:robot);; r6#run w;; let r7 = new robot_fou 5 5;; w#add_robot (r7:robot);; r7#run w;; r5#stop();; let r8 = new robot_fou 5 5;; w#add_robot (r8:robot);; r8#run w;; == Fin du programme principal *)