fast-abelian-sandpile/sandpile_1d.c

74 lines
2.1 KiB
C

#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <stdio.h>
#include <math.h>
#include "common.c"
/// This one does not rely on pointers of pointers to represent a 2d
/// array. So no `[x][y]` access. Instead it represents the surface
/// as an 1d line, in which, if the current cell is `i`:
///
/// - the previous cell is at `surface[i - 1]`
/// - the cell in the next row is at `surface[i + width]`
/// - the cell in the previous row is at `surface[i - width]`
/// - the next cell is at `surface[i + 1]`
void apply_gravity(int width, int *terrain)
{
bool did_something;
int div;
int grid_size = width * width;
while (1) {
did_something = false;
for (int x = 0; x < grid_size; x++) {
if (terrain[x] >= 4) {
did_something = true;
div = terrain[x] / 4;
terrain[x] %= 4;
terrain[x - 1] += div;
terrain[x + 1] += div;
terrain[x - width] += div;
terrain[x + width] += div;
}
}
if (!did_something) {
#ifdef DEBUG
fprintf(stderr, "looped %i times:\n", loops);
for (int i = 0; i < 9; i++) {
fprintf(stderr, "- %"PRIu64" times to break a pile of %i grains\n", by_height[i], i);
}
fprintf(stderr, "- %"PRIu64" times to break a pile of more than 13 grains\n", by_height[9]);
fprintf(stderr, "Total %i collapses\n", collapses);
#endif
return;
}
}
}
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 = calloc(width * width, sizeof(int*));
terrain[width * (width / 2) + (width / 2)] = args.height;
apply_gravity(width, terrain);
// "convert" to 2D for printing:
int **terrain_2d = calloc(width, sizeof(int*));
for (int i = 0; i < width; i++) {
terrain_2d[i] = terrain + i * width;
}
save_terrain(width, terrain_2d, &args);
return EXIT_SUCCESS;
}