Task: Forest fire

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

#include <SDL.h>


#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
};


double prand()
{
  return (double)rand() / (RAND_MAX + 1.0);
}


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;
    }
  }
}


bool burning_neighbor(int, int);
pthread_mutex_t synclock = PTHREAD_MUTEX_INITIALIZER;
static uint32_t simulate(uint32_t iv, void *p)
{
  int i, j;

  
  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;
}


#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);
}






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;

  
  srand(time(NULL));

  
  
  
  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); 
  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); 
	  pthread_mutex_unlock(&synclock);
	} else {
	  running = true;
	  tid = SDL_AddTimer(TIMERFREQ, simulate, NULL);
	  
	}
	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);
}








VB: Public Class ForestFire
    Private _forest(,) As ForestState
    Private _isBuilding As Boolean
    Private _bm As Bitmap
    Private _gen As Integer
    Private _sw As Stopwatch

    Private Const _treeStart As Double = 0.5
    Private Const _f As Double = 0.00001
    Private Const _p As Double = 0.001

    Private Const _winWidth As Integer = 300
    Private Const _winHeight As Integer = 300

    Private Enum ForestState
        Empty
        Burning
        Tree
    End Enum

    Private Sub ForestFire_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(_winWidth, _winHeight)
        ReDim _forest(_winWidth, _winHeight)

        Dim rnd As New Random()
        For i As Integer = 0 To _winHeight - 1
            For j As Integer = 0 To _winWidth - 1
                _forest(j, i) = IIf(rnd.NextDouble <= _treeStart, ForestState.Tree, ForestState.Empty)
            Next
        Next

        _sw = New Stopwatch
        _sw.Start()
        DrawForest()
        Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        If _isBuilding Then Exit Sub

        _isBuilding = True
        GetNextGeneration()

        DrawForest()
        _isBuilding = False
    End Sub

    Private Sub GetNextGeneration()
        Dim forestCache(_winWidth, _winHeight) As ForestState
        Dim rnd As New Random()

        For i As Integer = 0 To _winHeight - 1
            For j As Integer = 0 To _winWidth - 1
                Select Case _forest(j, i)
                    Case ForestState.Tree
                        If forestCache(j, i) <> ForestState.Burning Then
                            forestCache(j, i) = IIf(rnd.NextDouble <= _f, ForestState.Burning, ForestState.Tree)
                        End If

                    Case ForestState.Burning
                        For i2 As Integer = i - 1 To i + 1
                            If i2 = -1 OrElse i2 >= _winHeight Then Continue For
                            For j2 As Integer = j - 1 To j + 1
                                If j2 = -1 OrElse i2 >= _winWidth Then Continue For
                                If _forest(j2, i2) = ForestState.Tree Then forestCache(j2, i2) = ForestState.Burning
                            Next
                        Next
                        forestCache(j, i) = ForestState.Empty

                    Case Else
                        forestCache(j, i) = IIf(rnd.NextDouble <= _p, ForestState.Tree, ForestState.Empty)
                End Select
            Next
        Next

        _forest = forestCache
        _gen += 1
    End Sub

    Private Sub DrawForest()
        Dim bmCache As New Bitmap(_winWidth, _winHeight)

        For i As Integer = 0 To _winHeight - 1
            For j As Integer = 0 To _winWidth - 1
                Select Case _forest(j, i)
                    Case ForestState.Tree
                        bmCache.SetPixel(j, i, Color.Green)

                    Case ForestState.Burning
                        bmCache.SetPixel(j, i, Color.Red)
                End Select
            Next
        Next

        _bm = bmCache
        Me.Refresh()
    End Sub

    Private Sub ForestFire_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        e.Graphics.DrawImage(_bm, 0, 0)

        Me.Text = "Gen " & _gen.ToString() & " @ " & (_gen / (_sw.ElapsedMilliseconds / 1000)).ToString("F02") & " FPS: Forest Fire"
    End Sub
End Class