#include #include #include #include #include #include #include "common.c" /// This one stores, for each cells, 4 pointers to the west, south, /// north, and east cells so incrementing them is easy. typedef struct cell cell; struct cell { cell *west; cell *north; cell *south; cell *east; int height; }; static inline void fire(cell *cell) { int div, rest; div = cell->height / 4; rest = cell->height % 4; cell->height = rest; cell->west->height += div; cell->south->height += div; cell->north->height += div; cell->east->height += div; } void apply_gravity(int width, cell *cells) { bool did_something; while (1) { did_something = false; for (int x = 0; x < width*width; x++) { if (cells[x].height >= 4) { did_something = true; fire(cells+x); } } if (!did_something) return; } } cell *sandpile_new(int width, int height) { cell **terrain = calloc(width, sizeof(cell*)); cell *data = calloc(width * width, sizeof(cell)); for (int i = 0; i < width; i++) { terrain[i] = data + i * width; } terrain[width / 2][width / 2].height = height; for (int x = 0; x < width; x++) { for (int y = 0; y < width; y++) { terrain[x][y].west = &terrain[x-1][y]; terrain[x][y].south = &terrain[x][y-1]; terrain[x][y].north = &terrain[x][y+1]; terrain[x][y].east = &terrain[x+1][y]; } } return data; } int **cells_to_array(int width, cell *cells) { // Create terrain: 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; } // Organize cells in a 2d structure: cell **cell_array = calloc(width, sizeof(cell*)); for (int i = 0; i < width; i++) { cell_array[i] = cells + i * width; } // Copy cells to terrain: for (int x = 0; x < width; x++) for (int y = 0; y < width; y++) terrain[x][y] = cell_array[x][y].height; return terrain; } int main(int argc, char **argv) { args args = {0}; if (parse_args(argc, argv, &args)) return EXIT_FAILURE; int width = sandpile_width(args.height); cell *cells = sandpile_new(width, args.height); apply_gravity(width, cells); if (args.png_filename != NULL || args.print_to_stdout) { // Convert to int** for easy display: int **terrain = cells_to_array(width, cells); save_terrain(width, terrain, &args); } return EXIT_SUCCESS; }