Undeyapper812

"Genetic Termites" Simulation C language

Aug 15th, 2025
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.95 KB | None | 0 0
  1. #include <SDL2/SDL.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6.  
  7. #define GRID_W 120
  8. #define GRID_H 80
  9. #define CELL_SIZE 6
  10. #define BOTTOM_BAR_H 56
  11. #define WINDOW_W (GRID_W * CELL_SIZE)
  12. #define WINDOW_H (GRID_H * CELL_SIZE + BOTTOM_BAR_H)
  13.  
  14. #define MAX_TERMITES 800
  15. #define INITIAL_TERMITES 38
  16. #define RULE_LENGTH 32
  17. #define TICKS_PER_SECOND 30
  18.  
  19. #define MUTATION_PROB 0.005f
  20.  
  21. typedef struct {
  22. int x, y;
  23. int dir;
  24. char rule[RULE_LENGTH + 1];
  25. int alive;
  26. } Termite;
  27.  
  28. static Termite termites[MAX_TERMITES];
  29. static int num_termites = 0;
  30. static unsigned char grid[GRID_H][GRID_W];
  31.  
  32. static SDL_Window *win = NULL;
  33. static SDL_Renderer *ren = NULL;
  34.  
  35. static SDL_Rect clear_button = {10, WINDOW_H - 40, 120, 30};
  36. // FIX: Adjusted pause and speed button positions to prevent hitbox overlap
  37. static SDL_Rect pause_area = {140, WINDOW_H - 40, 100, 30};
  38. static SDL_Rect speed_button = {250, WINDOW_H - 40, 120, 30};
  39.  
  40. static const int HEX_DX[6] = { 1, 0, -1, -1, 0, 1 };
  41. static const int HEX_DY[6] = {-1,-1, 0, 1, 1, 0 };
  42.  
  43. static SDL_Color STATE_COLS[RULE_LENGTH];
  44.  
  45. static int paused = 1;
  46. static int rng_seeded = 0;
  47. static int fast_mode = 0;
  48.  
  49. void init_sim(void);
  50. void reset_sim(void);
  51. void spawn_termite(int x, int y, int dir);
  52. void random_rule(char *rule);
  53. void move_all_termite(void);
  54. void crossover_rules(char *a, char *b);
  55. void handle_collisions(void);
  56. void render(void);
  57. void handle_input(SDL_Event *e);
  58. int pos_to_cell(int px, int py, int *cx, int *cy);
  59. void cleanup(void);
  60. static inline float frand(void) { return (float)rand() / ((float)RAND_MAX + 1.0f); }
  61.  
  62. int main(int argc, char **argv) {
  63. (void)argc; (void)argv;
  64. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) {
  65. fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
  66. return 1;
  67. }
  68.  
  69. win = SDL_CreateWindow("Genetic Turmites (RULE_LENGTH = 32)", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN);
  70. if (!win) { fprintf(stderr, "CreateWindow: %s\n", SDL_GetError()); cleanup(); return 2; }
  71.  
  72. ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
  73. if (!ren) { fprintf(stderr, "CreateRenderer: %s\n", SDL_GetError()); cleanup(); return 3; }
  74.  
  75. if (!rng_seeded) { srand((unsigned)time(NULL)); rng_seeded = 1; }
  76.  
  77. for (int i = 0; i < RULE_LENGTH; i++) {
  78. float t = (float)i / (RULE_LENGTH - 1);
  79. STATE_COLS[i].r = (Uint8)(255 - t * 255);
  80. STATE_COLS[i].g = (Uint8)(255 - t * 255);
  81. STATE_COLS[i].b = (Uint8)(255 - t * 127);
  82. STATE_COLS[i].a = 255;
  83. }
  84.  
  85. init_sim();
  86.  
  87. Uint32 last = SDL_GetTicks();
  88. int running = 1;
  89. SDL_Event e;
  90.  
  91. while (running) {
  92. while (SDL_PollEvent(&e)) {
  93. if (e.type == SDL_QUIT) running = 0;
  94. handle_input(&e);
  95. }
  96.  
  97. // FIX: The main loop now handles multiple updates per frame to achieve true 10x speed.
  98. Uint32 now = SDL_GetTicks();
  99. Uint32 elapsed = now - last;
  100. Uint32 update_interval = fast_mode ? (1000 / (TICKS_PER_SECOND * 10)) : (1000 / TICKS_PER_SECOND);
  101.  
  102. if (!paused) {
  103. while (elapsed >= update_interval) {
  104. move_all_termite();
  105. handle_collisions();
  106. elapsed -= update_interval;
  107. last += update_interval;
  108. }
  109. }
  110.  
  111. render();
  112. SDL_Delay(1);
  113. }
  114.  
  115. cleanup();
  116. return 0;
  117. }
  118.  
  119. void init_sim(void) {
  120. reset_sim();
  121. num_termites = 0;
  122. for (int i = 0; i < INITIAL_TERMITES; ++i) {
  123. spawn_termite(rand() % GRID_W, rand() % GRID_H, rand() % 6);
  124. }
  125. }
  126.  
  127. void reset_sim(void) {
  128. for (int y = 0; y < GRID_H; y++) {
  129. for (int x = 0; x < GRID_W; x++) {
  130. grid[y][x] = rand() % RULE_LENGTH;
  131. }
  132. }
  133.  
  134. for (int i = 0; i < MAX_TERMITES; ++i) termites[i].alive = 0;
  135. num_termites = 0;
  136. paused = 1;
  137. }
  138.  
  139. void spawn_termite(int x, int y, int dir) {
  140. if (num_termites >= MAX_TERMITES) return;
  141. termites[num_termites].x = (x % GRID_W + GRID_W) % GRID_W;
  142. termites[num_termites].y = (y % GRID_H + GRID_H) % GRID_H;
  143. termites[num_termites].dir = dir % 6;
  144. random_rule(termites[num_termites].rule);
  145. termites[num_termites].alive = 1;
  146. num_termites++;
  147. }
  148.  
  149. void random_rule(char *rule) {
  150. const char opts[3] = {'L','R','S'};
  151. for (int i = 0; i < RULE_LENGTH; ++i) rule[i] = opts[rand() % 3];
  152. rule[RULE_LENGTH] = '\0';
  153. }
  154.  
  155. void move_all_termite(void) {
  156. for (int i = 0; i < num_termites; ++i) {
  157. if (!termites[i].alive) continue;
  158. int x = termites[i].x;
  159. int y = termites[i].y;
  160. int cell = grid[y][x];
  161.  
  162. char r = termites[i].rule[cell % RULE_LENGTH];
  163. if (r == 'L') termites[i].dir = (termites[i].dir + 5) % 6;
  164. else if (r == 'R') termites[i].dir = (termites[i].dir + 1) % 6;
  165.  
  166. grid[y][x] = (grid[y][x] + 1) % RULE_LENGTH;
  167.  
  168. int nx = (x + HEX_DX[termites[i].dir] + GRID_W) % GRID_W;
  169. int ny = (y + HEX_DY[termites[i].dir] + GRID_H) % GRID_H;
  170. termites[i].x = nx;
  171. termites[i].y = ny;
  172. }
  173. }
  174.  
  175. void crossover_rules(char *a, char *b) {
  176. int cut = rand() % RULE_LENGTH;
  177. char tmp[RULE_LENGTH + 1];
  178. char tmp2[RULE_LENGTH + 1];
  179.  
  180. for (int i = 0; i < cut; ++i) tmp[i] = a[i];
  181. for (int i = cut; i < RULE_LENGTH; ++i) tmp[i] = b[i];
  182. tmp[RULE_LENGTH] = '\0';
  183.  
  184. for (int i = 0; i < cut; ++i) tmp2[i] = b[i];
  185. for (int i = cut; i < RULE_LENGTH; ++i) tmp2[i] = a[i];
  186. tmp2[RULE_LENGTH] = '\0';
  187.  
  188. memcpy(a, tmp, RULE_LENGTH + 1);
  189. memcpy(b, tmp2, RULE_LENGTH + 1);
  190.  
  191. const char opts[3] = {'L','R','S'};
  192. for (int i = 0; i < RULE_LENGTH; ++i) {
  193. if (frand() < MUTATION_PROB) a[i] = opts[rand() % 3];
  194. if (frand() < MUTATION_PROB) b[i] = opts[rand() % 3];
  195. }
  196. }
  197.  
  198. void handle_collisions(void) {
  199. for (int i = 0; i < num_termites; ++i) {
  200. if (!termites[i].alive) continue;
  201. for (int j = i + 1; j < num_termites; ++j) {
  202. if (!termites[j].alive) continue;
  203. if (termites[i].x == termites[j].x && termites[i].y == termites[j].y) {
  204. crossover_rules(termites[i].rule, termites[j].rule);
  205. }
  206. }
  207. }
  208. }
  209.  
  210. void render(void) {
  211. SDL_SetRenderDrawColor(ren, 28, 28, 28, 255);
  212. SDL_RenderClear(ren);
  213.  
  214. for (int y = 0; y < GRID_H; ++y) {
  215. for (int x = 0; x < GRID_W; ++x) {
  216. SDL_Rect r = { x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE };
  217. SDL_Color c = STATE_COLS[ grid[y][x] % RULE_LENGTH ];
  218. SDL_SetRenderDrawColor(ren, c.r, c.g, c.b, c.a);
  219. SDL_RenderFillRect(ren, &r);
  220. SDL_SetRenderDrawColor(ren, 70,70,70,50);
  221. SDL_RenderDrawRect(ren, &r);
  222. }
  223. }
  224.  
  225. for (int i = 0; i < num_termites; ++i) {
  226. if (!termites[i].alive) continue;
  227. SDL_Rect tr = { termites[i].x * CELL_SIZE + 1, termites[i].y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2 };
  228. int hue = (i * 73) % 200 + 30;
  229. SDL_SetRenderDrawColor(ren, 200, hue, 120, 255);
  230. SDL_RenderFillRect(ren, &tr);
  231.  
  232. int cx = termites[i].x * CELL_SIZE + CELL_SIZE / 2;
  233. int cy = termites[i].y * CELL_SIZE + CELL_SIZE / 2;
  234. SDL_SetRenderDrawColor(ren, 255,255,255,255);
  235. int dx = 0, dy = 0;
  236. if (termites[i].dir == 0) { dx = 0; dy = -2; }
  237. if (termites[i].dir == 1) { dx = 1; dy = -1; }
  238. if (termites[i].dir == 2) { dx = 1; dy = 1; }
  239. if (termites[i].dir == 3) { dx = 0; dy = 2; }
  240. if (termites[i].dir == 4) { dx = -1; dy = 1; }
  241. if (termites[i].dir == 5) { dx = -1; dy = -1; }
  242. SDL_RenderDrawPoint(ren, cx + dx, cy + dy);
  243. }
  244.  
  245. SDL_Rect bottom = {0, WINDOW_H - BOTTOM_BAR_H, WINDOW_W, BOTTOM_BAR_H};
  246. SDL_SetRenderDrawColor(ren, 60, 60, 60, 220);
  247. SDL_RenderFillRect(ren, &bottom);
  248.  
  249. SDL_SetRenderDrawColor(ren, 70, 130, 200, 255);
  250. SDL_RenderFillRect(ren, &clear_button);
  251. SDL_SetRenderDrawColor(ren, 90, 90, 90, 255);
  252. SDL_RenderFillRect(ren, &pause_area);
  253. SDL_SetRenderDrawColor(ren, 180, 180, 180, 255);
  254. SDL_RenderFillRect(ren, &speed_button);
  255.  
  256. SDL_SetRenderDrawColor(ren, 255,255,255,255);
  257. 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);
  258. 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);
  259.  
  260. if (paused) SDL_SetRenderDrawColor(ren, 220, 60, 60, 255);
  261. else SDL_SetRenderDrawColor(ren, 60, 220, 60, 255);
  262. SDL_Rect st = { pause_area.x + 6, pause_area.y + 6, 18, 18 };
  263. SDL_RenderFillRect(ren, &st);
  264.  
  265. SDL_RenderPresent(ren);
  266. }
  267.  
  268. int pos_to_cell(int px, int py, int *cx, int *cy) {
  269. if (px < 0 || py < 0) return 0;
  270. if (py >= GRID_H * CELL_SIZE) return 0;
  271. *cx = px / CELL_SIZE;
  272. *cy = py / CELL_SIZE;
  273. if (*cx < 0 || *cx >= GRID_W || *cy < 0 || *cy >= GRID_H) return 0;
  274. return 1;
  275. }
  276.  
  277. void handle_input(SDL_Event *e) {
  278. if (e->type == SDL_MOUSEBUTTONDOWN) {
  279. int mx = e->button.x;
  280. int my = e->button.y;
  281.  
  282. if (mx >= clear_button.x && mx <= clear_button.x + clear_button.w &&
  283. my >= clear_button.y && my <= clear_button.y + clear_button.h) {
  284. reset_sim();
  285. for (int i = 0; i < INITIAL_TERMITES; ++i) spawn_termite(rand()%GRID_W, rand()%GRID_H, rand()%6);
  286. return;
  287. }
  288.  
  289. if (mx >= pause_area.x && mx <= pause_area.x + pause_area.w &&
  290. my >= pause_area.y && my <= pause_area.y + pause_area.h) {
  291. paused = !paused;
  292. return;
  293. }
  294.  
  295. if (mx >= speed_button.x && mx <= speed_button.x + speed_button.w &&
  296. my >= speed_button.y && my <= speed_button.y + speed_button.h) {
  297. fast_mode = !fast_mode;
  298. return;
  299. }
  300.  
  301. int cx, cy;
  302. if (pos_to_cell(mx, my, &cx, &cy)) {
  303. grid[cy][cx] = (grid[cy][cx] + 1) % RULE_LENGTH;
  304. for (int i = 0; i < num_termites; ++i) {
  305. if (termites[i].alive && termites[i].x == cx && termites[i].y == cy) {
  306. printf("Termite %d rule: %s (pos %d,%d dir %d)\n", i, termites[i].rule, cx, cy, termites[i].dir);
  307. }
  308. }
  309. } else {
  310. paused = !paused;
  311. }
  312. }
  313. else if (e->type == SDL_FINGERDOWN) {
  314. int mx = (int)(e->tfinger.x * WINDOW_W);
  315. int my = (int)(e->tfinger.y * WINDOW_H);
  316.  
  317. if (mx >= clear_button.x && mx <= clear_button.x + clear_button.w &&
  318. my >= clear_button.y && my <= clear_button.y + clear_button.h) {
  319. reset_sim();
  320. for (int i = 0; i < INITIAL_TERMITES; ++i) spawn_termite(rand()%GRID_W, rand()%GRID_H, rand()%6);
  321. return;
  322. }
  323.  
  324. if (mx >= pause_area.x && mx <= pause_area.x + pause_area.w &&
  325. my >= pause_area.y && my <= pause_area.y + pause_area.h) {
  326. paused = !paused;
  327. return;
  328. }
  329.  
  330. if (mx >= speed_button.x && mx <= speed_button.x + speed_button.w &&
  331. my >= speed_button.y && my <= speed_button.y + speed_button.h) {
  332. fast_mode = !fast_mode;
  333. return;
  334. }
  335.  
  336. int cx, cy;
  337. if (pos_to_cell(mx, my, &cx, &cy)) {
  338. grid[cy][cx] = (grid[cy][cx] + 1) % RULE_LENGTH;
  339. for (int i = 0; i < num_termites; ++i) {
  340. if (termites[i].alive && termites[i].x == cx && termites[i].y == cy) {
  341. printf("Termite %d rule: %s (pos %d,%d dir %d)\n", i, termites[i].rule, cx, cy, termites[i].dir);
  342. }
  343. }
  344. } else {
  345. paused = !paused;
  346. }
  347. }
  348. }
  349.  
  350. void cleanup(void) {
  351. if (ren) SDL_DestroyRenderer(ren);
  352. if (win) SDL_DestroyWindow(win);
  353. SDL_Quit();
  354. }
  355.  
Advertisement
Add Comment
Please, Sign In to add comment