Simulation de feux de forêt

Simulation de feux de forêt #

Principe de l’automate #

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 :

  • vide
  • arbre
  • feu
  • cendre

Les règles de transition sont :

  • une case vise reste vide
  • une case en feu devient en cendre
  • une case en cendre reste en cendre
  • une case arbre devient en feu si elle a un voisin (4-voisinage) en feu et reste arbre sinon

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.

Principe du programme #

Le programme est graphique. Sa structure sera :

  • initialiser les divers éléments (forêt, fenêtre….)
  • lancer la boucle des événements pendant laquelle on va :
    • calculer la forêt à l’instant suivant
    • tracer
    • et recommencer

Librairie graphique #

Pour ce travail, nous utiliserons la librairie EZDraw, développée par Édouard Thiel. Elle a le gros avantage

  • d’être portable ;
  • d’être très légère (seuls 2 fichiers à mettre dans le projet, pas besoin de compiler la lib indépendamment) ;
  • d’être simple à prendre en main.

Pour tester, téléchargez la lib sur le site officiel, ou récupérez le Zip suivant 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.

Automate cellulaire avec Ez-draw #

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).

Lancement du calcul #

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 :
  • calcul
  • affichage

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.

Améliorations diverses #

  • Allumer un foyer d’incendie à la souris en cliquant sur un arbre
  • Modifiez la règle de transition pour l’inflammation : un arbre prend feu avec une probabilité 0.8 s’il a un 4-voisin en feu et avec une probabilité 0.5 s’il a un 8-voisin qui n’est pas un 4-voisin en feu. Attention, au calcul de la probabilité d’incendie dans le cas où plusieurs voisins sont en feu.
  • Modifiez la répartition des arbres (clairières etc…) : proposez un modèle un peu plus réaliste pour l’implantation des arbres.