fast-abelian-sandpile/sandpile-video.c

79 lines
1.9 KiB
C

// Compile using:
// cc -W -Wall --pedantic --std=c99 -Ofast sandpile-video.c -lpng -lm -o sandpile-video
// The run it to produce png files:
// sandpile-video 2000
// Then use ffmpeg to convert to a video
// ffmpeg -pattern_type glob -i '*.png' out.mp4
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <stdio.h>
#include <math.h>
#include "common.c"
void apply_gravity(int width, int **terrain)
{
bool did_something;
int div;
while (1) {
did_something = false;
for (int x = 0; x < width; x++) {
for (int y = 0; y < width; y++) {
if (terrain[x][y] >= 4) {
did_something = true;
div = terrain[x][y] / 4;
terrain[x][y] = terrain[x][y] % 4;
terrain[x - 1][y] += div;
terrain[x + 1][y] += div;
terrain[x][y + 1] += div;
terrain[x][y - 1] += div;
}
}
}
if (!did_something)
return;
}
}
int **sandpile_new(int width)
{
int **terrain = calloc(width, sizeof(int*));
int *data = calloc(width * width, sizeof(int));
for (int i = 0; i < width; i++) {
terrain[i] = data + i * width;
}
return terrain;
}
#define STEP 100
int main(int argc, char **argv)
{
args args = {0};
if (parse_args(argc, argv, &args))
return EXIT_FAILURE;
int width = sandpile_width(args.height);
int **terrain = sandpile_new(width);
char imgname[255] = {0};
for (int i = 0; i < args.height; i += STEP) {
terrain[width / 2][width / 2] += STEP;
apply_gravity(width, terrain);
sprintf(imgname, "sandpile-%i-%010i.png", args.height, i);
if (save_terrain(width, terrain, imgname) == 0)
printf("%i/%i saved\n", i, args.height);
else
printf("Can't save terrain\n");
}
return EXIT_SUCCESS;
}