// x-run: make run #include #include #include struct cell { int origin_x, origin_y; int random_seed; enum cell_type { CELL_VOID, CELL_LIVING, CELL_DEAD } type; int timer; }; #define GET_CELL(A, X, Y) (A[((X + width) % width) + ((Y + height) % height) * width]) const int width = 400, height = 300; Color cell_get_color(struct cell *cells, int x, int y); void cell_update(struct cell *cells_old, struct cell *cells, int x, int y); int main(int argc, char **argv) { InitWindow(width * 2, height * 2, "sim/cellular_NAME"); SetTargetFPS(60); struct cell *cells = calloc(width * height, sizeof(struct cell)); struct cell *cells_old = calloc(width * height, sizeof(struct cell)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { cells[x + y * width].origin_x = x; cells[x + y * width].origin_y = y; cells[x + y * width].random_seed = rand(); cells[x + y * width].type = rand() % 100 == 0; cells[x + y * width].timer = 200; } } Image img_out = GenImageColor(width, height, BLANK); Texture2D tex_out = LoadTextureFromImage(img_out); while (!WindowShouldClose()) { memcpy(cells_old, cells, width * height * sizeof(struct cell)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { cell_update(cells_old, cells, x, y); } } BeginDrawing(); ClearBackground(BLACK); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { struct cell cell = cells[x + y * width]; ImageDrawPixel(&img_out, x, y, cell_get_color(cells, x, y)); } } UpdateTexture(tex_out, img_out.data); DrawTextureEx(tex_out, (Vector2){ 0, 0 }, 0, 2, WHITE); DrawFPS(10, 10); EndDrawing(); } UnloadTexture(tex_out); UnloadImage(img_out); } Color cell_get_color(struct cell *cells, int x, int y) { Vector3 color = ColorToHSV(WHITE); struct cell cell = cells[x + y * width]; switch (cell.type) { case CELL_VOID: color = ColorToHSV(BLACK); break; case CELL_LIVING: color = ColorToHSV(DARKGREEN); break; case CELL_DEAD: color = ColorToHSV(RED); break; } color.x += (cell.random_seed % 60) - 30; color.y *= 1.0 - 0.2 * ((float)(cell.random_seed % 100) / 100.0); /*color.z *= cell.timer / 200.0;*/ return ColorFromHSV(color.x, color.y, color.z); } void cell_update(struct cell *cells_old, struct cell *cells, int x, int y) { struct cell *old_self = &cells_old[x + y * width]; struct cell *self = &cells[x + y * width]; switch (self->type) { case CELL_LIVING: { for (int oy = -1; oy <= 1; oy++) { for (int ox = -1; ox <= 1; ox++) { struct cell old_other = GET_CELL(cells_old, x + ox, y + oy); struct cell *other = &GET_CELL(cells, x + ox, y + oy); if (old_other.type == CELL_VOID && rand() % 100 == 0) { other->type = CELL_LIVING; other->timer = 200; } else if (old_other.type == CELL_LIVING && rand() % 90 == 0) { other->type = CELL_DEAD; other->timer = rand() % 200; } } } } break; case CELL_DEAD: self->timer -= rand() % 8; if (self->timer <= 0) { self->type = CELL_VOID; } default: break; } }