Skip to content

Instantly share code, notes, and snippets.

@yves-chevallier
Created December 8, 2025 07:38
Show Gist options
  • Select an option

  • Save yves-chevallier/acabea2fd6d8da76b7d1f161b4f7ad08 to your computer and use it in GitHub Desktop.

Select an option

Save yves-chevallier/acabea2fd6d8da76b7d1f161b4f7ad08 to your computer and use it in GitHub Desktop.
Fire Propagation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define GRID_SIZE 20
#define MAX_TEMP 100.0
#define MIN_IGNITE_TEMP 50.0
#define FIRE_PROB_AT_100 0.5
typedef struct {
double cells[GRID_SIZE][GRID_SIZE];
} Grid;
typedef struct {
int r, g, b;
} RGB;
static double clamp(double value, double min, double max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
// Quadratic curve between 50 (0%) and 100 (50%).
// Using a squared term makes higher temperatures disproportionately more dangerous.
static double ignition_probability(double temp) {
if (temp < MIN_IGNITE_TEMP) return 0.0;
double norm = (temp - MIN_IGNITE_TEMP) / (MAX_TEMP - MIN_IGNITE_TEMP); // 0..1
double curved = norm * norm; // non-linear ramp-up
return FIRE_PROB_AT_100 * curved;
}
static void read_initial_fires(Grid *grid) {
int x, y;
while (scanf("%d %d", &x, &y) == 2) {
if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE) {
grid->cells[y][x] = MAX_TEMP;
}
}
}
static void diffuse_heat(const Grid *current, Grid *next) {
memcpy(next, current, sizeof(Grid));
for (int r = 0; r < GRID_SIZE; ++r) {
for (int c = 0; c < GRID_SIZE; ++c) {
if (current->cells[r][c] <= 0.0) continue;
for (int dr = -1; dr <= 1; ++dr) {
for (int dc = -1; dc <= 1; ++dc) {
if (dr == 0 && dc == 0) continue;
int nr = r + dr;
int nc = c + dc;
if (nr < 0 || nr >= GRID_SIZE || nc < 0 || nc >= GRID_SIZE) continue;
next->cells[nr][nc] = clamp(next->cells[nr][nc] + 1.0, 0.0, MAX_TEMP);
}
}
}
}
}
static void ignite(Grid *grid) {
for (int r = 0; r < GRID_SIZE; ++r) {
for (int c = 0; c < GRID_SIZE; ++c) {
if (grid->cells[r][c] >= MAX_TEMP) {
grid->cells[r][c] = MAX_TEMP;
continue;
}
double p = ignition_probability(grid->cells[r][c]);
double roll = rand() / (double)RAND_MAX;
if (roll < p) {
grid->cells[r][c] = MAX_TEMP;
}
}
}
}
// Truecolor matplotlib-like \"hot\": red ramps to 1 by 0.3, green 0.3->0.6, blue 0.6->1.0.
static RGB pick_color(double temp) {
double x = clamp(temp / MAX_TEMP, 0.0, 1.0);
double r = (x < 0.3) ? (x / 0.3) : 1.0;
double g = (x < 0.3) ? 0.0 : (x < 0.6 ? (x - 0.3) / 0.3 : 1.0);
double b = (x < 0.6) ? 0.0 : (x - 0.6) / 0.4;
RGB rgb = {
.r = (int)(r * 255.0 + 0.5),
.g = (int)(g * 255.0 + 0.5),
.b = (int)(b * 255.0 + 0.5)
};
return rgb;
}
static void render_simple(const Grid *grid) {
for (int r = 0; r < GRID_SIZE; ++r) {
for (int c = 0; c < GRID_SIZE; ++c) {
printf("%3d ", (int)(grid->cells[r][c] + 0.5));
}
puts("");
}
}
static void render_ansi(const Grid *grid) {
for (int r = 0; r < GRID_SIZE; ++r) {
for (int c = 0; c < GRID_SIZE; ++c) {
RGB rgb = pick_color(grid->cells[r][c]);
printf("\x1b[48;2;%d;%d;%dm \x1b[0m", rgb.r, rgb.g, rgb.b);
}
puts("");
}
}
static void step(const Grid *current, Grid *next) {
diffuse_heat(current, next);
ignite(next);
}
static void usage(const char *prog) {
fprintf(stderr, "Usage: %s [-s steps] [--ansi]\n", prog);
fprintf(stderr, "Provide initial fire coordinates on stdin as 'x y' pairs (0-%d).\n", GRID_SIZE - 1);
}
int main(int argc, char *argv[]) {
int steps = 20;
int use_ansi = 0;
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--steps") == 0) {
if (i + 1 >= argc) {
usage(argv[0]);
return 1;
}
steps = atoi(argv[++i]);
} else if (strcmp(argv[i], "--ansi") == 0) {
use_ansi = 1;
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
usage(argv[0]);
return 0;
} else {
usage(argv[0]);
return 1;
}
}
srand((unsigned int)time(NULL));
Grid grid = {0};
read_initial_fires(&grid);
Grid next = {0};
for (int t = 0; t < steps; ++t) {
step(&grid, &next);
grid = next;
}
if (use_ansi) {
render_ansi(&grid);
} else {
render_simple(&grid);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment