La forêt est modélisée par un tableau de SIZE x SIZE cases (typiquement 100x100). Chaque case peut être dans un des quatre états :
Les règles de transition sont :
Habituellement, les états des cellules sont représentées par des nombres entiers (par exemple 0, 1, 2, 3 dans le cas des feux de forêt). La forêt sera donc un tableau bidimensionnel d'entiers.
Le programme est graphique. Sa structure sera :
Pour ce travail, nous utiliserons la librairie EZDraw, développée par Édouard Thiel. Elle a le gros avantage
Pour tester, téléchargez la lib sur le site officiel, ou récupérez le Zip suivant [[files>ezdraw12.zip|ezdraw12.zip]].
Puis créez un projet (console), ajoutez les deux fichiers ez-draw.c
et ez-draw.h
à votre projet
et créez le programme principal suivant :
/* demo-02.c : demonstration of EZ-Draw * * Edouard.Thiel@lif.univ-mrs.fr - 02/07/2008 - version 1.2 * * Compilation on Unix : * gcc -Wall demo-02.c ez-draw.c -o demo-02 -lX11 -lXext * Compilation on Windows : * gcc -Wall demo-02.c ez-draw.c -o demo-02.exe -lgdi32 * * This program is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ #include "ez-draw.h" void win1_event (Ez_event *ev) /* Called by ez_main_loop() */ { /* for each event on win1 */ switch (ev->type) { case Expose : /* We must redraw everything */ ez_set_color (ez_red); ez_draw_text (ev->win, EZ_MC, 200, 150, "To quit, press the key 'q', or click\n" "on the Close button of the window"); break; case KeyPress : /* A key was pressed */ switch (ev->key_sym) { case XK_q : ez_quit (); break; } break; } } int main () { if (ez_init() < 0) exit(1); ez_window_create (400, 300, "Demo 02: Window and events", win1_event); ez_main_loop (); exit(0); }
Pour compiler, il faut lier, sous Windows, la bibliothèque gdi32
. Sous Unix, il faut lier X11
et Xext
.
Compilez et exécutez. Ne passez à la suite que lorsque le test fonctionne correctement.
Pour gagner un peu de temps, ne partez pas de zéro… Voici un programme de départ :
#include "ez-draw.h" #define SIZE 100 /* Taille de la forêt */ #define C 5 /* Taille d'une case à l'écran en pixels */ /* La forêt est une variable globale */ int foret[SIZE][SIZE]; /* Prend une forêt en paramètre et l'initialise avec * des arbres */ void init_foret(int f[][SIZE]) { // IL FAUT ÉCRIRE CETTE FONCTION } /* Prend une forêt en paramètre et la trace dans la * fenêtre win */ void trace_foret(int f[][SIZE], Ez_window win) { // IL FAUT ÉCRIRE CETTE FONCTION } /* Modifie le contenu de la forêt passée en paramètre * (calcul d'un pas de temps) */ void calcul_etape(int f[][SIZE]) { // IL FAUT ECRIRE CETTE FONCTION } void win_cb(Ez_event * ev) { switch(ev -> type) { case Expose: printf("Expose\n"); trace_foret(foret, ev->win); break; case KeyPress: printf("KeyPress\n"); break; case ButtonPress: printf("ButtonPress\n"); break; } } int main() { Ez_window win; if (ez_init() < 0) exit(1); init_foret(foret); win = ez_window_create(SIZE * C, SIZE * C, "Feuforet", win_cb); ez_main_loop(); exit(0); }
Étudiez attentivement le programme et voyez ce qu'il reste à faire.
Les constantes utilisées pour les états des cellules ne devront pas figurer de manière littérale
dans le code, mais seront définies à l'aide de #define
(par convention, les noms de ces constantes
sont écrits en capitales).
Dans un premier temps, créez la fonction d'initialisation de la forêt et la fonction de tracé. Assurez-vous que la forêt apparaît correctement sur l'écran.
La manière d'initialiser la forêt est importante : il peut y avoir plus ou moins d'arbres, les arbres peuvent avoir tendance à pousser par “paquets” de manière à laisser des clairières etc…. Faites le plus simple au début, vous améliorerez la modélisation d'une forêt à la fin.
Vous aurez besoin de la fonction C rand()
(cherchez comment l'utiliser), et des fonction Ez-draw :
ez_set_color
et ez_fill_rect
(cherchez dans la doc officielle de Ez-Draw).
Pour que le calcul et l'affichage se fasse en tâche de fond, nous allons utiliser les timers de Ez-Draw.
La fonction ez_start_timer
planifie l'exécution d'une fonction au bout d'un certain nombre de millisecondes
(en provoquant l'émission de l'événement TimerNotify
).
Pour exécuter une fonction de calcul et l'animation en «tâche de fond», il suffit de relancer la planification
de la fonction dès qu'elle se termine.
Écrivez la fonction de calcul, et utilisez un timer pour exécuter en permanence :
Pour provoquer le réaffichage, il suffit d'envoyer un événement Expose
ainsi :
ez_send_expose(win);
Attention à la fonction de calcul. Écrivez la proprement (découpez en sous problèmes si possible) et pensez que le changement de l'état des cellules est calculé simultanément pour toute la forêt.
Le réaffichage intempestif provoque un clignotement désagréable à l'écran. Renseignez-vous sur le double buffering et réglez ce problème.