Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <SDL2/SDL.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #define GRID_W 120
- #define GRID_H 80
- #define CELL_SIZE 6
- #define BOTTOM_BAR_H 56
- #define WINDOW_W (GRID_W * CELL_SIZE)
- #define WINDOW_H (GRID_H * CELL_SIZE + BOTTOM_BAR_H)
- #define MAX_TERMITES 800
- #define INITIAL_TERMITES 38
- #define RULE_LENGTH 32
- #define TICKS_PER_SECOND 30
- #define MUTATION_PROB 0.005f
- typedef struct {
- int x, y;
- int dir;
- char rule[RULE_LENGTH + 1];
- int alive;
- } Termite;
- static Termite termites[MAX_TERMITES];
- static int num_termites = 0;
- static unsigned char grid[GRID_H][GRID_W];
- static SDL_Window *win = NULL;
- static SDL_Renderer *ren = NULL;
- static SDL_Rect clear_button = {10, WINDOW_H - 40, 120, 30};
- // FIX: Adjusted pause and speed button positions to prevent hitbox overlap
- static SDL_Rect pause_area = {140, WINDOW_H - 40, 100, 30};
- static SDL_Rect speed_button = {250, WINDOW_H - 40, 120, 30};
- static const int HEX_DX[6] = { 1, 0, -1, -1, 0, 1 };
- static const int HEX_DY[6] = {-1,-1, 0, 1, 1, 0 };
- static SDL_Color STATE_COLS[RULE_LENGTH];
- static int paused = 1;
- static int rng_seeded = 0;
- static int fast_mode = 0;
- void init_sim(void);
- void reset_sim(void);
- void spawn_termite(int x, int y, int dir);
- void random_rule(char *rule);
- void move_all_termite(void);
- void crossover_rules(char *a, char *b);
- void handle_collisions(void);
- void render(void);
- void handle_input(SDL_Event *e);
- int pos_to_cell(int px, int py, int *cx, int *cy);
- void cleanup(void);
- static inline float frand(void) { return (float)rand() / ((float)RAND_MAX + 1.0f); }
- int main(int argc, char **argv) {
- (void)argc; (void)argv;
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) {
- fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
- return 1;
- }
- win = SDL_CreateWindow("Genetic Turmites (RULE_LENGTH = 32)", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN);
- if (!win) { fprintf(stderr, "CreateWindow: %s\n", SDL_GetError()); cleanup(); return 2; }
- ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
- if (!ren) { fprintf(stderr, "CreateRenderer: %s\n", SDL_GetError()); cleanup(); return 3; }
- if (!rng_seeded) { srand((unsigned)time(NULL)); rng_seeded = 1; }
- for (int i = 0; i < RULE_LENGTH; i++) {
- float t = (float)i / (RULE_LENGTH - 1);
- STATE_COLS[i].r = (Uint8)(255 - t * 255);
- STATE_COLS[i].g = (Uint8)(255 - t * 255);
- STATE_COLS[i].b = (Uint8)(255 - t * 127);
- STATE_COLS[i].a = 255;
- }
- init_sim();
- Uint32 last = SDL_GetTicks();
- int running = 1;
- SDL_Event e;
- while (running) {
- while (SDL_PollEvent(&e)) {
- if (e.type == SDL_QUIT) running = 0;
- handle_input(&e);
- }
- // FIX: The main loop now handles multiple updates per frame to achieve true 10x speed.
- Uint32 now = SDL_GetTicks();
- Uint32 elapsed = now - last;
- Uint32 update_interval = fast_mode ? (1000 / (TICKS_PER_SECOND * 10)) : (1000 / TICKS_PER_SECOND);
- if (!paused) {
- while (elapsed >= update_interval) {
- move_all_termite();
- handle_collisions();
- elapsed -= update_interval;
- last += update_interval;
- }
- }
- render();
- SDL_Delay(1);
- }
- cleanup();
- return 0;
- }
- void init_sim(void) {
- reset_sim();
- num_termites = 0;
- for (int i = 0; i < INITIAL_TERMITES; ++i) {
- spawn_termite(rand() % GRID_W, rand() % GRID_H, rand() % 6);
- }
- }
- void reset_sim(void) {
- for (int y = 0; y < GRID_H; y++) {
- for (int x = 0; x < GRID_W; x++) {
- grid[y][x] = rand() % RULE_LENGTH;
- }
- }
- for (int i = 0; i < MAX_TERMITES; ++i) termites[i].alive = 0;
- num_termites = 0;
- paused = 1;
- }
- void spawn_termite(int x, int y, int dir) {
- if (num_termites >= MAX_TERMITES) return;
- termites[num_termites].x = (x % GRID_W + GRID_W) % GRID_W;
- termites[num_termites].y = (y % GRID_H + GRID_H) % GRID_H;
- termites[num_termites].dir = dir % 6;
- random_rule(termites[num_termites].rule);
- termites[num_termites].alive = 1;
- num_termites++;
- }
- void random_rule(char *rule) {
- const char opts[3] = {'L','R','S'};
- for (int i = 0; i < RULE_LENGTH; ++i) rule[i] = opts[rand() % 3];
- rule[RULE_LENGTH] = '\0';
- }
- void move_all_termite(void) {
- for (int i = 0; i < num_termites; ++i) {
- if (!termites[i].alive) continue;
- int x = termites[i].x;
- int y = termites[i].y;
- int cell = grid[y][x];
- char r = termites[i].rule[cell % RULE_LENGTH];
- if (r == 'L') termites[i].dir = (termites[i].dir + 5) % 6;
- else if (r == 'R') termites[i].dir = (termites[i].dir + 1) % 6;
- grid[y][x] = (grid[y][x] + 1) % RULE_LENGTH;
- int nx = (x + HEX_DX[termites[i].dir] + GRID_W) % GRID_W;
- int ny = (y + HEX_DY[termites[i].dir] + GRID_H) % GRID_H;
- termites[i].x = nx;
- termites[i].y = ny;
- }
- }
- void crossover_rules(char *a, char *b) {
- int cut = rand() % RULE_LENGTH;
- char tmp[RULE_LENGTH + 1];
- char tmp2[RULE_LENGTH + 1];
- for (int i = 0; i < cut; ++i) tmp[i] = a[i];
- for (int i = cut; i < RULE_LENGTH; ++i) tmp[i] = b[i];
- tmp[RULE_LENGTH] = '\0';
- for (int i = 0; i < cut; ++i) tmp2[i] = b[i];
- for (int i = cut; i < RULE_LENGTH; ++i) tmp2[i] = a[i];
- tmp2[RULE_LENGTH] = '\0';
- memcpy(a, tmp, RULE_LENGTH + 1);
- memcpy(b, tmp2, RULE_LENGTH + 1);
- const char opts[3] = {'L','R','S'};
- for (int i = 0; i < RULE_LENGTH; ++i) {
- if (frand() < MUTATION_PROB) a[i] = opts[rand() % 3];
- if (frand() < MUTATION_PROB) b[i] = opts[rand() % 3];
- }
- }
- void handle_collisions(void) {
- for (int i = 0; i < num_termites; ++i) {
- if (!termites[i].alive) continue;
- for (int j = i + 1; j < num_termites; ++j) {
- if (!termites[j].alive) continue;
- if (termites[i].x == termites[j].x && termites[i].y == termites[j].y) {
- crossover_rules(termites[i].rule, termites[j].rule);
- }
- }
- }
- }
- void render(void) {
- SDL_SetRenderDrawColor(ren, 28, 28, 28, 255);
- SDL_RenderClear(ren);
- for (int y = 0; y < GRID_H; ++y) {
- for (int x = 0; x < GRID_W; ++x) {
- SDL_Rect r = { x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE };
- SDL_Color c = STATE_COLS[ grid[y][x] % RULE_LENGTH ];
- SDL_SetRenderDrawColor(ren, c.r, c.g, c.b, c.a);
- SDL_RenderFillRect(ren, &r);
- SDL_SetRenderDrawColor(ren, 70,70,70,50);
- SDL_RenderDrawRect(ren, &r);
- }
- }
- for (int i = 0; i < num_termites; ++i) {
- if (!termites[i].alive) continue;
- SDL_Rect tr = { termites[i].x * CELL_SIZE + 1, termites[i].y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2 };
- int hue = (i * 73) % 200 + 30;
- SDL_SetRenderDrawColor(ren, 200, hue, 120, 255);
- SDL_RenderFillRect(ren, &tr);
- int cx = termites[i].x * CELL_SIZE + CELL_SIZE / 2;
- int cy = termites[i].y * CELL_SIZE + CELL_SIZE / 2;
- SDL_SetRenderDrawColor(ren, 255,255,255,255);
- int dx = 0, dy = 0;
- if (termites[i].dir == 0) { dx = 0; dy = -2; }
- if (termites[i].dir == 1) { dx = 1; dy = -1; }
- if (termites[i].dir == 2) { dx = 1; dy = 1; }
- if (termites[i].dir == 3) { dx = 0; dy = 2; }
- if (termites[i].dir == 4) { dx = -1; dy = 1; }
- if (termites[i].dir == 5) { dx = -1; dy = -1; }
- SDL_RenderDrawPoint(ren, cx + dx, cy + dy);
- }
- SDL_Rect bottom = {0, WINDOW_H - BOTTOM_BAR_H, WINDOW_W, BOTTOM_BAR_H};
- SDL_SetRenderDrawColor(ren, 60, 60, 60, 220);
- SDL_RenderFillRect(ren, &bottom);
- SDL_SetRenderDrawColor(ren, 70, 130, 200, 255);
- SDL_RenderFillRect(ren, &clear_button);
- SDL_SetRenderDrawColor(ren, 90, 90, 90, 255);
- SDL_RenderFillRect(ren, &pause_area);
- SDL_SetRenderDrawColor(ren, 180, 180, 180, 255);
- SDL_RenderFillRect(ren, &speed_button);
- SDL_SetRenderDrawColor(ren, 255,255,255,255);
- SDL_RenderDrawLine(ren, clear_button.x + 6, clear_button.y + 6, clear_button.x + clear_button.w - 6, clear_button.y + clear_button.h - 6);
- SDL_RenderDrawLine(ren, clear_button.x + 6, clear_button.y + clear_button.h - 6, clear_button.x + clear_button.w - 6, clear_button.y + 6);
- if (paused) SDL_SetRenderDrawColor(ren, 220, 60, 60, 255);
- else SDL_SetRenderDrawColor(ren, 60, 220, 60, 255);
- SDL_Rect st = { pause_area.x + 6, pause_area.y + 6, 18, 18 };
- SDL_RenderFillRect(ren, &st);
- SDL_RenderPresent(ren);
- }
- int pos_to_cell(int px, int py, int *cx, int *cy) {
- if (px < 0 || py < 0) return 0;
- if (py >= GRID_H * CELL_SIZE) return 0;
- *cx = px / CELL_SIZE;
- *cy = py / CELL_SIZE;
- if (*cx < 0 || *cx >= GRID_W || *cy < 0 || *cy >= GRID_H) return 0;
- return 1;
- }
- void handle_input(SDL_Event *e) {
- if (e->type == SDL_MOUSEBUTTONDOWN) {
- int mx = e->button.x;
- int my = e->button.y;
- if (mx >= clear_button.x && mx <= clear_button.x + clear_button.w &&
- my >= clear_button.y && my <= clear_button.y + clear_button.h) {
- reset_sim();
- for (int i = 0; i < INITIAL_TERMITES; ++i) spawn_termite(rand()%GRID_W, rand()%GRID_H, rand()%6);
- return;
- }
- if (mx >= pause_area.x && mx <= pause_area.x + pause_area.w &&
- my >= pause_area.y && my <= pause_area.y + pause_area.h) {
- paused = !paused;
- return;
- }
- if (mx >= speed_button.x && mx <= speed_button.x + speed_button.w &&
- my >= speed_button.y && my <= speed_button.y + speed_button.h) {
- fast_mode = !fast_mode;
- return;
- }
- int cx, cy;
- if (pos_to_cell(mx, my, &cx, &cy)) {
- grid[cy][cx] = (grid[cy][cx] + 1) % RULE_LENGTH;
- for (int i = 0; i < num_termites; ++i) {
- if (termites[i].alive && termites[i].x == cx && termites[i].y == cy) {
- printf("Termite %d rule: %s (pos %d,%d dir %d)\n", i, termites[i].rule, cx, cy, termites[i].dir);
- }
- }
- } else {
- paused = !paused;
- }
- }
- else if (e->type == SDL_FINGERDOWN) {
- int mx = (int)(e->tfinger.x * WINDOW_W);
- int my = (int)(e->tfinger.y * WINDOW_H);
- if (mx >= clear_button.x && mx <= clear_button.x + clear_button.w &&
- my >= clear_button.y && my <= clear_button.y + clear_button.h) {
- reset_sim();
- for (int i = 0; i < INITIAL_TERMITES; ++i) spawn_termite(rand()%GRID_W, rand()%GRID_H, rand()%6);
- return;
- }
- if (mx >= pause_area.x && mx <= pause_area.x + pause_area.w &&
- my >= pause_area.y && my <= pause_area.y + pause_area.h) {
- paused = !paused;
- return;
- }
- if (mx >= speed_button.x && mx <= speed_button.x + speed_button.w &&
- my >= speed_button.y && my <= speed_button.y + speed_button.h) {
- fast_mode = !fast_mode;
- return;
- }
- int cx, cy;
- if (pos_to_cell(mx, my, &cx, &cy)) {
- grid[cy][cx] = (grid[cy][cx] + 1) % RULE_LENGTH;
- for (int i = 0; i < num_termites; ++i) {
- if (termites[i].alive && termites[i].x == cx && termites[i].y == cy) {
- printf("Termite %d rule: %s (pos %d,%d dir %d)\n", i, termites[i].rule, cx, cy, termites[i].dir);
- }
- }
- } else {
- paused = !paused;
- }
- }
- }
- void cleanup(void) {
- if (ren) SDL_DestroyRenderer(ren);
- if (win) SDL_DestroyWindow(win);
- SDL_Quit();
- }
Advertisement
Add Comment
Please, Sign In to add comment