How to resolve the algorithm Forest fire step by step in the C programming language

Published on 7 June 2024 03:52 AM
#C

How to resolve the algorithm Forest fire step by step in the C programming language

Table of Contents

Problem Statement

Implement the Drossel and Schwabl definition of the forest-fire model.

It is basically a 2D   cellular automaton   where each cell can be in three distinct states (empty, tree and burning) and evolves according to the following rules (as given by Wikipedia) Neighborhood is the   Moore neighborhood;   boundary conditions are so that on the boundary the cells are always empty ("fixed" boundary condition). At the beginning, populate the lattice with empty and tree cells according to a specific probability (e.g. a cell has the probability 0.5 to be a tree). Then, let the system evolve. Task's requirements do not include graphical display or the ability to change parameters (probabilities   p   and   f )   through a graphical or command line interface.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Forest fire step by step in the C programming language

This is a C program that simulates a forest fire using a cellular automaton. The program uses two buffers to store the current and next state of the forest, and it updates the display using the SDL library.

The forest is represented by an array of cells, and each cell can be in one of three states: empty, tree, or burning. The simulation proceeds by iteratively applying the following rules to each cell in the forest:

  • If a cell is empty, it has a probability prob_p of becoming a tree.
  • If a cell is a tree, it has a probability prob_f of becoming burning.
  • If a cell is burning, it will become empty.

In addition to these rules, a cell can also become burning if it is adjacent to a burning cell. The probability of this happening is determined by the prob_tree parameter.

The program uses a mutex to protect the shared forest data from being corrupted by concurrent access from multiple threads.

The main function initializes the SDL library, creates the forest buffers, and sets up the simulation timer. The main loop then waits for events and updates the display accordingly. When the user presses the 'q' key, the program quits.

The burning_neighbor function checks if any of the eight neighboring cells are burning. The simulate function iterates over all the cells in the forest and updates their states according to the simulation rules. The show function updates the display using the SDL library.

The evolve function in the second code snippet is a simplified version of the forest fire simulation that uses a single array to store the state of the forest. The evolve function iterates over all the cells in the forest and updates their states according to the same rules as the simulate function. However, the evolve function does not use a mutex to protect the forest data from being corrupted by concurrent access from multiple threads.

Source code in the c programming language

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>

#include <SDL.h>

// defaults
#define PROB_TREE 0.55
#define PROB_F 0.00001
#define PROB_P 0.001

#define TIMERFREQ 100

#ifndef WIDTH
#  define WIDTH 640
#endif
#ifndef HEIGHT
#  define HEIGHT 480
#endif
#ifndef BPP
#  define BPP 32
#endif

#if BPP != 32
  #warning This program could not work with BPP different from 32
#endif

uint8_t *field[2], swapu;
double prob_f = PROB_F, prob_p = PROB_P, prob_tree = PROB_TREE; 

enum cell_state { 
  VOID, TREE, BURNING
};

// simplistic random func to give [0, 1)
double prand()
{
  return (double)rand() / (RAND_MAX + 1.0);
}

// initialize the field
void init_field(void)
{
  int i, j;
  swapu = 0;
  for(i = 0; i < WIDTH; i++)
  {
    for(j = 0; j < HEIGHT; j++)
    {
      *(field[0] + j*WIDTH + i) = prand() > prob_tree ? VOID : TREE;
    }
  }
}

// the "core" of the task: the "forest-fire CA"
bool burning_neighbor(int, int);
pthread_mutex_t synclock = PTHREAD_MUTEX_INITIALIZER;
static uint32_t simulate(uint32_t iv, void *p)
{
  int i, j;

  /*
    Since this is called by SDL, "likely"(*) in a separated
    thread, we try to avoid corrupted updating of the display
    (done by the show() func): show needs the "right" swapu
    i.e. the right complete field. (*) what if it is not so?
    The following is an attempt to avoid unpleasant updates.
   */
  pthread_mutex_lock(&synclock);

  for(i = 0; i < WIDTH; i++) {
    for(j = 0; j < HEIGHT; j++) {
      enum cell_state s = *(field[swapu] + j*WIDTH + i);
      switch(s)
      {
      case BURNING:
	*(field[swapu^1] + j*WIDTH + i) = VOID;
	break;
      case VOID:
	*(field[swapu^1] + j*WIDTH + i) = prand() > prob_p ? VOID : TREE;
	break;
      case TREE:
	if (burning_neighbor(i, j))
	  *(field[swapu^1] + j*WIDTH + i) = BURNING;
	else
	  *(field[swapu^1] + j*WIDTH + i) = prand() > prob_f ? TREE : BURNING;
	break;
      default:
	fprintf(stderr, "corrupted field\n");
	break;
      }
    }
  }
  swapu ^= 1;
  pthread_mutex_unlock(&synclock);
  return iv;
}

// the field is a "part" of an infinite "void" region
#define NB(I,J) (((I)<WIDTH)&&((I)>=0)&&((J)<HEIGHT)&&((J)>=0) \
		 ? (*(field[swapu] + (J)*WIDTH + (I)) == BURNING) : false)
bool burning_neighbor(int i, int j)
{
  return NB(i-1,j-1) || NB(i-1, j) || NB(i-1, j+1) ||
    NB(i, j-1) || NB(i, j+1) ||
    NB(i+1, j-1) || NB(i+1, j) || NB(i+1, j+1);
}


// "map" the field into gfx mem
// burning trees are red
// trees are green
// "voids" are black;
void show(SDL_Surface *s)
{
  int i, j;
  uint8_t *pixels = (uint8_t *)s->pixels;
  uint32_t color;
  SDL_PixelFormat *f = s->format;

  pthread_mutex_lock(&synclock);
  for(i = 0; i < WIDTH; i++) {
    for(j = 0; j < HEIGHT; j++) {
      switch(*(field[swapu] + j*WIDTH + i)) {
      case VOID:
	color = SDL_MapRGBA(f, 0,0,0,255);
	break;
      case TREE:
	color = SDL_MapRGBA(f, 0,255,0,255);
	break;
      case BURNING:
	color = SDL_MapRGBA(f, 255,0,0,255);
	break;
      }
      *(uint32_t*)(pixels + j*s->pitch + i*(BPP>>3)) = color;
    }
  }
  pthread_mutex_unlock(&synclock);
}

int main(int argc, char **argv)
{
  SDL_Surface *scr = NULL;
  SDL_Event event[1];
  bool quit = false, running = false;
  SDL_TimerID tid;

  // add variability to the simulation
  srand(time(NULL));

  // we can change prob_f and prob_p
  // prob_f prob of spontaneous ignition
  // prob_p prob of birth of a tree
  double *p;
  for(argv++, argc--; argc > 0; argc--, argv++)
  {
    if ( strcmp(*argv, "prob_f") == 0 && argc > 1 )
    {
      p = &prob_f;
    } else if ( strcmp(*argv, "prob_p") == 0 && argc > 1 ) {
      p = &prob_p;
    } else if ( strcmp(*argv, "prob_tree") == 0 && argc > 1 ) {
      p = &prob_tree;
    } else  continue;


    argv++; argc--;
    char *s = NULL;
    double t = strtod(*argv, &s);
    if (s != *argv) *p = t;
  }

  printf("prob_f %lf\nprob_p %lf\nratio %lf\nprob_tree %lf\n", 
	 prob_f, prob_p, prob_p/prob_f,
	 prob_tree);

  if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0 ) return EXIT_FAILURE;
  atexit(SDL_Quit);

  field[0] = malloc(WIDTH*HEIGHT);
  if (field[0] == NULL) exit(EXIT_FAILURE);
  field[1] = malloc(WIDTH*HEIGHT);
  if (field[1] == NULL) { free(field[0]); exit(EXIT_FAILURE); }

  scr = SDL_SetVideoMode(WIDTH, HEIGHT, BPP, SDL_HWSURFACE|SDL_DOUBLEBUF);
  if (scr == NULL) {
    fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
    free(field[0]); free(field[1]);
    exit(EXIT_FAILURE);
  }

  init_field();

  tid = SDL_AddTimer(TIMERFREQ, simulate, NULL); // suppose success
  running = true;

  event->type = SDL_VIDEOEXPOSE;
  SDL_PushEvent(event);

  while(SDL_WaitEvent(event) && !quit)
  {
    switch(event->type)
    {
    case SDL_VIDEOEXPOSE:
      while(SDL_LockSurface(scr) != 0) SDL_Delay(1);
      show(scr);
      SDL_UnlockSurface(scr);
      SDL_Flip(scr);
      event->type = SDL_VIDEOEXPOSE;
      SDL_PushEvent(event);
      break;
    case SDL_KEYDOWN:
      switch(event->key.keysym.sym)
      {
      case SDLK_q:
	quit = true;
	break;
      case SDLK_p:
	if (running)
	{
	  running = false;
	  pthread_mutex_lock(&synclock);
	  SDL_RemoveTimer(tid); // ignore failure...
	  pthread_mutex_unlock(&synclock);
	} else {
	  running = true;
	  tid = SDL_AddTimer(TIMERFREQ, simulate, NULL);
	  // suppose success...
	}
	break;
      }
    case SDL_QUIT:
      quit = true;
      break;
    }
  }

  if (running) {
    pthread_mutex_lock(&synclock);
    SDL_RemoveTimer(tid);
    pthread_mutex_unlock(&synclock);
  }
  free(field[0]); free(field[1]);
  exit(EXIT_SUCCESS);
}


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h> // For time

enum { empty = 0, tree = 1, fire = 2 };
const char *disp[] = {"  ", "\033[32m/\\\033[m", "\033[07;31m/\\\033[m"};
double tree_prob = 0.01, burn_prob = 0.0001;

#define for_x for (int x = 0; x < w; x++)
#define for_y for (int y = 0; y < h; y++)
#define for_yx for_y for_x
#define chance(x) (rand() < RAND_MAX * x)
void evolve(int w, int h)
{
	unsigned univ[h][w], new[h][w];
	for_yx new[y][x] = univ[y][x] = chance(tree_prob) ? tree : empty;

show:	printf("\033[H");
	for_y {
		for_x printf("%s",disp[univ[y][x]]);
		printf("\033[E");
	}
	fflush(stdout);

	for_yx {
		switch (univ[y][x]) {
		case fire:	new[y][x] = empty;
				break;
		case empty:	if (chance(tree_prob)) new[y][x] = tree;
				break;
		default:
			for (int y1 = y - 1; y1 <= y + 1; y1++) {
				if (y1 < 0 || y1 >= h) continue;
				for (int x1 = x - 1; x1 <= x + 1; x1++) {
					if (x1 < 0 || x1 >= w) continue;
					if (univ[y1][x1] != fire) continue;

					new[y][x] = fire;
					goto burn;
				}
			}

			burn:
			if (new[y][x] == tree && chance(burn_prob))
				new[y][x] = fire;
		}
	}

	for_yx { univ[y][x] = new[y][x]; }
	//usleep(100000);
	goto show;
}
 
int main(int c, char **v)
{
	//srand(time(0));
	int w = 0, h = 0;

	if (c > 1) w = atoi(v[1]);
	if (c > 2) h = atoi(v[2]);
	if (w <= 0) w = 30;
	if (h <= 0) h = 30;

	evolve(w, h);
}


  

You may also check:How to resolve the algorithm Semordnilap step by step in the VBScript programming language
You may also check:How to resolve the algorithm The sieve of Sundaram step by step in the Haskell programming language
You may also check:How to resolve the algorithm Range expansion step by step in the Ursala programming language
You may also check:How to resolve the algorithm Flatten a list step by step in the Perl programming language
You may also check:How to resolve the algorithm Comments step by step in the Action! programming language