gol

Implementation of Conway's Game of Life writen in C
git clone git://git.dimitrijedobrota.com/gol.git
Log | Files | Refs | README

logic.c (7943B)


      1 /**
      2  * @file logic.c
      3  * @author Mateja Marsenic
      4  * @date 30 May 2022
      5  * @brief This file contains functions used in games logic.
      6  */
      7 
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 
     11 #include "game.h"
     12 #include "logic.h"
     13 #include "utils.h"
     14 
     15 Cell *hash = NULL;
     16 
     17 /**
     18  * @brief function that delets cell from hash table utilazing uthash.h
     19  */
     20 void deleter(Cell *c) {
     21   HASH_DEL(hash, c);
     22   free(c);
     23 }
     24 
     25 /**
     26  * @brief function that returns pointer to the cell in hash table at given
     27  * position.
     28  */
     29 Cell *get(int row, int col) {
     30   Cell *c, t;
     31 
     32   memset(&t, 0, sizeof(Cell));
     33   t.cord.row = row;
     34   t.cord.col = col;
     35   HASH_FIND(hh, hash, &t.cord, sizeof(Cell_cord), c);
     36 
     37   return c;
     38 }
     39 
     40 void insert(int row, int col, int val, int mod) {
     41   Cell *c;
     42 
     43   c = get(row, col);
     44   if (c == NULL) {
     45     MEM_CHECK(c = malloc(sizeof(Cell)));
     46     c->cord.row = row;
     47     c->cord.col = col;
     48     c->val = val;
     49     HASH_ADD(hh, hash, cord, sizeof(Cell_cord), c);
     50   }
     51   c->val += mod;
     52 }
     53 
     54 extern int width, height;
     55 int        isExpanding;
     56 
     57 Cell **save_cells;
     58 int    save_cells_s;
     59 int    save_cells_sm;
     60 
     61 int pos_y;
     62 int pos_x;
     63 
     64 char *evolution_names[] = {"Normal", "CoExsistance", "Predator", "Virus",
     65                            "Unknown"};
     66 int   evolution_cells[] = {2, 3, 3, 3, 3};
     67 int   evolution_size = 5;
     68 int   evolve_index;
     69 int   toggle_mod = 2;
     70 
     71 static void (*evolve)(void);
     72 static void (*addToCells)(int i, int j, int value);
     73 
     74 /**
     75  * @brief function that adds its value to neighbouring cells;
     76  */
     77 
     78 void addToCellsNormal(int i, int j, int value) {
     79   int mod = 0;
     80   switch (value & 3) {
     81   case 1:
     82     mod = 4;
     83     break;
     84   case 2:
     85     mod = 32;
     86     break;
     87   }
     88   for (int k = i - 1; k <= i + 1; k++)
     89     for (int l = j - 1; l <= j + 1; l++)
     90       if (k != i || l != j)
     91         insert(k, l, 0, mod);
     92 }
     93 
     94 /**
     95  * @brief simmilar to addToCellsNormal() with exception that it check for
     96  * corners in case of wrapping;
     97  */
     98 void addToCellsWrap(int i, int j, int value) {
     99   int mod = 0;
    100   switch (value & 3) {
    101   case 1:
    102     mod = 4;
    103     break;
    104   case 2:
    105     mod = 32;
    106     break;
    107   }
    108 
    109   for (int k = i - 1; k <= i + 1; k++)
    110     for (int l = j - 1; l <= j + 1; l++) {
    111       int a = WCLAMP(k, height);
    112       int b = WCLAMP(l, width);
    113       if (a != i || b != j)
    114         insert(a, b, 0, mod);
    115     }
    116 }
    117 
    118 void doAdditions(void) {
    119   Cell *c;
    120 
    121   Cell *buff[10000];
    122   int   size = 0;
    123   for (c = hash; c != NULL; c = c->hh.next)
    124     buff[size++] = c;
    125 
    126   for (int i = 0; i < size; i++)
    127     addToCells(buff[i]->cord.row, buff[i]->cord.col, buff[i]->val);
    128 }
    129 
    130 /**
    131  * @brief function responsible for calculation for a game mode called "Normal";
    132  */
    133 void evolveNormal(void) {
    134   Cell *c, *c_next;
    135 
    136   doAdditions();
    137   for (c = hash; c != NULL; c = c_next) {
    138     c_next = c->hh.next;
    139     switch (c->val) {
    140     case 9:
    141     case 12:
    142     case 13:
    143       c->val = 1;
    144       break;
    145     default:
    146       deleter(c);
    147     }
    148   }
    149 }
    150 
    151 /**
    152  * @brief function responsible for calculation for a game mode called "CoExist";
    153  */
    154 void evolveCoExist(void) {
    155   Cell *c, *c_next;
    156 
    157   doAdditions();
    158   int s1, s2, mod;
    159   for (c = hash; c != NULL; c = c_next) {
    160     c_next = c->hh.next;
    161     s2 = c->val >> 5;
    162     s1 = (c->val & 31) >> 2;
    163     mod = c->val & 3;
    164     if (mod == 0) {
    165       if ((s1 + s2) == 3) {
    166         if (c->val >= 64)
    167           c->val = 2;
    168         else
    169           c->val = 1;
    170         continue;
    171       }
    172     }
    173     if ((s1 + s2) < 2 || (s1 + s2) > 3) {
    174       deleter(c);
    175     }
    176     c->val = mod;
    177   }
    178 }
    179 
    180 /**
    181  * @brief function responsible for calculation for a game mode called
    182  * "Predator";
    183  */
    184 void evolvePredator(void) {
    185   Cell *c, *c_next;
    186   doAdditions();
    187   int s1, s2, mod;
    188   for (c = hash; c != NULL; c = c_next) {
    189     c_next = c->hh.next;
    190     s2 = c->val >> 5;
    191     s1 = (c->val & 31) >> 2;
    192     mod = c->val & 3;
    193     if ((s1 + s2) < 2 || (s1 + s2) > 3) {
    194       deleter(c);
    195       continue;
    196     }
    197     switch (mod) {
    198     case 0:
    199       if ((s1 + s2) == 3) {
    200         if (c->val >= 64)
    201           c->val = 2;
    202         else
    203           c->val = 1;
    204         continue;
    205       }
    206       deleter(c);
    207       break;
    208     case 1:
    209       if (s2 > 0) {
    210         deleter(c);
    211         continue;
    212       }
    213       break;
    214     }
    215     c->val = mod;
    216   }
    217 }
    218 
    219 /**
    220  * @brief function responsible for calculation for a game mode called "Virus";
    221  */
    222 void evolveVirus(void) {
    223   Cell *c, *c_next;
    224   doAdditions();
    225   int s1, s2, mod;
    226   for (c = hash; c != NULL; c = c_next) {
    227     c_next = c->hh.next;
    228     s2 = c->val >> 5;
    229     s1 = (c->val & 31) >> 2;
    230     mod = c->val & 3;
    231     if ((s1 + s2) < 2 || (s1 + s2) > 3) {
    232       deleter(c);
    233       continue;
    234     }
    235     switch (mod) {
    236     case 0:
    237       if ((s1 + s2) == 3) {
    238         if (c->val >= 64)
    239           c->val = 2;
    240         else
    241           c->val = 1;
    242         continue;
    243       }
    244       deleter(c);
    245       break;
    246     case 1:
    247       if (s2 > 0) {
    248         c->val = 2;
    249         continue;
    250       }
    251       break;
    252     }
    253     c->val = mod;
    254   }
    255 }
    256 
    257 /**
    258  * @brief function responsible for calculation for a game mode called "Unknown";
    259  */
    260 void evolveUnknown(void) { // Assumption 3 ones and 3 twos result in 50/50
    261                            // chanse of 0 becoming one of them:
    262   Cell *c, *c_next;
    263   doAdditions();
    264   int s1, s2, mod;
    265   for (c = hash; c != NULL; c = c_next) {
    266     c_next = c->hh.next;
    267     s2 = c->val >> 5;
    268     s1 = (c->val & 31) >> 2;
    269     mod = c->val & 3;
    270     switch (mod) {
    271     case 0:
    272       if (s1 == 3 && s2 == 3) {
    273         c->val = rand() % 2 + 1;
    274         continue;
    275       }
    276       if (s1 == 3) {
    277         c->val = 1;
    278         continue;
    279       }
    280       if (s2 == 3) {
    281         c->val = 2;
    282         continue;
    283       }
    284       deleter(c);
    285       break;
    286     case 1:
    287       if (s1 < 2 || s1 > 3) {
    288         deleter(c);
    289         continue;
    290       }
    291       break;
    292     case 2:
    293       if (s2 < 2 || s2 > 3) {
    294         deleter(c);
    295         continue;
    296       }
    297       break;
    298     }
    299     c->val = mod;
    300   }
    301 }
    302 
    303 /* Initializing functions */
    304 static void (*evolution_modes[])() = {
    305     evolveNormal, evolveCoExist, evolvePredator, evolveVirus, evolveUnknown};
    306 static void (*addition_modes[])(int i, int j, int value) = {addToCellsNormal,
    307                                                             addToCellsWrap};
    308 
    309 /**
    310  * @brief parent function that calls evolution;
    311  */
    312 void do_evolution(int steps) {
    313   while (steps--) {
    314     evolve();
    315   }
    316 }
    317 
    318 /**
    319  * @brief init function for game logic;
    320  */
    321 int logic_init(int isWrapping, int index) {
    322   save_cells_s = 0;
    323   save_cells_sm = 100;
    324   MEM_CHECK(save_cells = malloc(save_cells_sm * sizeof(struct Cell *)));
    325 
    326   addToCells = addition_modes[isWrapping];
    327   evolve = evolution_modes[index];
    328   evolve_index = index;
    329   toggle_mod = evolution_cells[index];
    330   return 1;
    331 }
    332 
    333 /**
    334  * @brief memory cleaner for logic.c;
    335  */
    336 int logic_free(void) {
    337   HASH_CLEAR(hh, hash);
    338   addToCells = NULL;
    339   evolve = NULL;
    340   toggle_mod = -1;
    341   free(save_cells);
    342   save_cells_s = 0;
    343   return 1;
    344 }
    345 
    346 /**
    347  * @brief function that toggles the value at coords (i,j). E.g from 0->1, 1->2
    348  * or 2->0;
    349  */
    350 int toggleAt(int i, int j) {
    351   Cell *c;
    352 
    353   if (!(c = get(i, j))) {
    354     insert(i, j, 1, 0);
    355     return 1;
    356   }
    357 
    358   int val = c->val = (c->val + 1) % toggle_mod;
    359   if (!c->val)
    360     deleter(c);
    361   return val;
    362 }
    363 
    364 /**
    365  * @brief function that destroys cell at coords(i,j);
    366  */
    367 void deleteAt(int i, int j) {
    368   Cell *c;
    369 
    370   if ((c = get(i, j)))
    371     deleter(c);
    372 }
    373 
    374 /**
    375  * @brief function that sets value(val) at coords(i,j);
    376  */
    377 void setAt(int i, int j, int val) {
    378   Cell *c;
    379 
    380   if ((c = get(i, j)) != NULL)
    381     c->val = val;
    382   else
    383     insert(i, j, val, 0);
    384 }
    385 
    386 /**
    387  * @brief functiong that returns value of a cell at given coords.
    388  */
    389 int getAt(int i, int j) {
    390   Cell *c = get(i, j);
    391   return ((c) ? c->val : 0);
    392 }
    393 
    394 void setPosition(int i, int j) {
    395   pos_y = i;
    396   pos_x = j;
    397 }
    398 
    399 void saveCell(int i, int j) {
    400   Cell *c;
    401 
    402   if ((c = get(i, j))) {
    403     if (save_cells_s == save_cells_sm) {
    404       Cell **t;
    405       save_cells_sm *= 2;
    406       MEM_CHECK(t = realloc(save_cells, save_cells_sm));
    407       save_cells = t;
    408     }
    409 
    410     save_cells[save_cells_s++] = c;
    411   }
    412 }