(* Chèvres et moutons: version affichage graphique *) (* dans graphics.mli j'ai fini par trouver que "set_font" et autres commandes "ne font actuellement rien sur PC" , d'où l'impossibilité de représenter un mouton par un "M" qui aurait bougé*) (* un mouton va être un polygone rouge, une chèvre un polygone bleu *) (* effectif des troupeaux, au delà de 8 il y a plein de problèmes de fenêtre caml *) let troupeau=8;; type animal=chevre|mouton;; (* on initialise le chemin qui servira à savoir si l'emplacement k contient une chèvre ou un mouton *) let chemin = make_string (2*troupeau+5) `_`;; let ini_chemin()= let trtr=troupeau+troupeau in chemin.[0]<-`_`; chemin.[1]<-`_`; chemin.[trtr+3]<-`_`;chemin.[trtr+4]<-`_`; chemin.[troupeau+2]<-`_`; for k=1 to troupeau do chemin.[k+1]<- `M`; chemin.[troupeau+k+2]<- `C` done ;; (* initialisation du graphisme *) #open "graphics";; open_graph "";; (* initialisation, mode par défaut *) load_object "Ini_gr.zo";; #open "Ini_gr";; let h=20;; (* h est le "diamètre" d'un animal *) let deplace dx dy (x,y) =(x+dx,y+dy);; let mou (a,b)=[|(a,b);(a+h,b+h);(a+h,b);(a,b+h);(a,b)|];; let che (a,b)=[|(a,b);(a+h,b+h);(a,b+h);(a+h,b);(a,b)|];; (* attend sert à ralentir l'affichage *) let attend x=let rien=ref 0 in for k=1 to x/5 do rien:=x*x done;; (* ci-dessous bestiau sera mouton (red) ou chevre (blue) poly sera un polygone comme (mou p q) x y indique le déplacement *) let montre_deplace bestiau poly x y= let refp= ref poly in for k= 1 to 10 do set_color background; fill_poly !refp; refp := map_vect (deplace (x/10) (y/10)) !refp; if bestiau = mouton then set_color red else set_color blue; fill_poly !refp; attend 10000; done ;; (* un alias pour gagner du temps *) let m_d=montre_deplace ;; let dbest=40;; (* distance entre deux animaux d'un troupeau *) let sautb=2*dbest;; (* taille d'un saut *) (* j'ai fixé la ligne de base à 100 *) (* l'emplacement lieu k sera (dbest*k,100) à l'écran *) let lieu x=(dbest*(x+1),100);; (* les bestiaux sautent d'une hauteur fixe: 100, c'est plus simple *) let saute_droite bestiau poly= let refpoly= ref poly in m_d bestiau !refpoly 0 100; m_d bestiau (map_vect (deplace 0 100) !refpoly) sautb 0; m_d bestiau (map_vect (deplace sautb 100) !refpoly) 0 (-100) ;; let glisse_droite bestiau poly= let refpoly= ref poly in m_d bestiau !refpoly dbest 0; ;; let saute_gauche bestiau poly= let refpoly= ref poly in m_d bestiau !refpoly 0 100; m_d bestiau (map_vect (deplace 0 100) !refpoly) (-sautb) 0; m_d bestiau (map_vect (deplace (-sautb) 100) !refpoly) 0 (-100) ; ;; let glisse_gauche bestiau poly= let refpoly= ref poly in m_d bestiau !refpoly (-dbest) 0; ;; (* la commande montre() affiche l'état initial des troupeaux *) clear_graph();; let montre() = for k=1 to troupeau do set_color red; fill_poly (mou (lieu k)) ; set_color blue; fill_poly (che (lieu (troupeau+1+k))); done ;; (* quand bouge sera invoqué, la case cible b sera vide, éventuellement elle sera hors du chemin la lecture du type d'animal dans chemin est peu utile, on aurait pu la déduire du sens de déplacement la valeur de b est également ininterressante *) let bouge a b = if ((b>=0) & (b<=(2*troupeau+4))) then if chemin.[a+1]=`M` then begin chemin.[b+1]<-`M`; chemin.[a+1]<- `_`; if b=(a+2) then saute_droite mouton (mou (lieu a)) else glisse_droite mouton (mou (lieu a)) end else begin chemin.[b+1]<- `C`;chemin.[a+1]<- `_`; if b=(a-2) then saute_gauche chevre (che (lieu a)) else glisse_gauche chevre (che (lieu a)) end else if ((a>=0) & (a<=(2*troupeau+4))) then begin chemin.[a]<- `_`; montre() end ;; (*la ligne à entrer pour les essais en caml interactif clear_graph();;ini_chemin();;chemin;;montre();; *) (* "tout se passe ici" dans cette paire de commandes récursives *) let rec sauter_fait p i j= if p=1 then begin bouge i (i+1); bouge j (j-2) end else begin fait_sauter (p-1) (i+1) (j-1); bouge i (i+1); let k=ref (i+2) in while !k<=j do begin bouge !k (!k-2); k:=!k+2 end done end and fait_sauter p i j= if p=1 then begin bouge j (j-1); bouge i (i+2) end else begin sauter_fait (p-1) (i+1) (j-1); bouge j (j-1); let k=ref (j-2) in while !k>=i do begin bouge !k (!k+2); k:=!k-2 end done end ;; (* evacue_droite et les autres ne servent qu'au départ des troupeaux *) let evacue_droite()= for k=1 to 3 do bouge (2*troupeau+k-1) (2*troupeau+k) done; set_color background; fill_poly (mou (lieu (2*troupeau+3))) ;; (* pour une raison que j'ignore, evacue_gauche cochonne l'image après coup, n'ayant pas réussi à l'arranger, j'ai lâchement laissé les chêvres sur le terrain: la commande au_revoir est incomplète *) let evacue_gauche()= for k=3 downto 1 do bouge (k-1) k done; set_color background; fill_poly (che (lieu (-1))) ;; let au_revoir() = evacue_droite(); for l= 1 to (troupeau-1) do for k=1 to l do bouge (2*(troupeau-1-l+k)) (2*(troupeau-l+k)) done; evacue_droite() done; (* for l=1 to (troupeau-1) do evacue_gauche () done *) evacue_gauche(); for l= 1 to (troupeau-1) do for k=1 to l do bouge (2*(troupeau-1-l+k)) (2*(troupeau-l+k)) done; evacue_gauche() done; ;; let vazy() = clear_graph();ini_chemin();montre(); sauter_fait troupeau 1 (2*troupeau+1) ;; vazy();; au_revoir();; (* quand on bouge la fenêtre avec les ascenseurs pendant l'animation, les moutons deviennent fous! c'est marrant *) (*ce programme comporte une erreur très vicieuse: __il marche ..... __si, après exécution, on refait ini_chemin() .... cela remarchera. __si on veut l'éxécuter à la main (par exemple j'avais voulu tester sauter_fait 2 n (n+2);;) il marche la première fois __si on veut de nouveau l'executer à la main après ce premier test, il ne marche plus! en effet "chemin" n'a pas été passé en variable à bouge, et bouge a été compilé avec un chemin constant qui est celui du départ!!!!!! cette erreur est rectifiée dans la version C_m_text, je l'ai laissée dans le listing ci-dessus, elle est trop belle! *)