bot-evolution-simulation

This program is a terrarium of little bots who undergo ruthless evolution in a 2D world with it's own rules.
Log | Files | Refs | README | LICENSE

main.pixi (11104B)


      1 include "bibl.pixi"
      2 include "field.pixi"
      3 include "gene.pixi"
      4 include "bots.pixi"
      5 
      6 
      7 // initialize the environment
      8 rand_seed(get_seconds())
      9 set_pixel_size(1)
     10 
     11 // =========================
     12 
     13 // initial (also max) active bots quantity
     14 BOTS_QTY = 64
     15 
     16 // grid size
     17 CELL_SIZE = 13
     18 
     19 // field size
     20 WINDOW_W = WINDOW_XSIZE - 350
     21 WINDOW_H = WINDOW_YSIZE - 50
     22 FIELD_W = WINDOW_W - (WINDOW_W % CELL_SIZE)
     23 FIELD_H = WINDOW_H - (WINDOW_H % CELL_SIZE)
     24 
     25 //% probability of mutation at every generation
     26 BOTS_MUT = 7
     27 
     28 // initial bot characteristics
     29 BOTS_ENERGY = BOTS_QTY / 2
     30 BOTS_THIRST = BOTS_QTY / 3
     31 
     32 // number of different genes actions
     33 BOTS_GENE_NUM = 16
     34 /* List genome actions:
     35     - move      ~ 8 
     36     - eat/drink ~ 8
     37 */
     38 // number of genes in bot's genome
     39 BOTS_GENOME_SIZE = 32
     40 
     41 // food and water generation settings
     42 WATER_SIZE = 2.3
     43 FOOD_FREQ = BOTS_QTY * 3
     44 
     45 // colors
     46 COL_BG = #343434
     47 COL_FIELD = #E3DAC9
     48 COL_GRID = #F0EAD6
     49 
     50 COL_BOT_ALIVE = #4F7942
     51 COL_BOT_DEAD= #C0C0C0
     52 COL_FOOD = #EE204E
     53 COL_WATER = #545AA7
     54 
     55 // =========================
     56 
     57 // field X position
     58 FIELD_X = FIELD_W / -2
     59 // field Y position
     60 FIELD_Y = FIELD_H / -2
     61 // number of horizontally places cells
     62 COLUMNS = FIELD_W / CELL_SIZE
     63 // number of vertically places cells
     64 ROWS = FIELD_H / CELL_SIZE
     65 
     66 // array of grid cells and their properties
     67 CELLS = new(COLUMNS * ROWS, INT)
     68 /* List of cell properties:
     69     - x_coord
     70     - y_coord
     71     - type: 0 - empty
     72             1 - bot
     73             2 - food
     74             3 - water
     75 */
     76 
     77 // array of bots and their properties
     78 BOTS = new(BOTS_QTY, INT)
     79 /* List of cell properties:
     80     - x_coord
     81     - y_coord
     82     - cell
     83     - energy
     84     - thirst
     85     - is_alive
     86     - genome
     87 */
     88 
     89 // =========================
     90 
     91 // draw the background
     92 clear(COL_BG)
     93 // draw the field
     94 fbox(FIELD_X, FIELD_Y, FIELD_W, FIELD_H, COL_FIELD)
     95 // draw the grid
     96 grid(CELL_SIZE, FIELD_X, FIELD_Y, FIELD_W, FIELD_H, COL_GRID)
     97 box(FIELD_X, FIELD_Y, FIELD_W, FIELD_H, COL_GRID)
     98 
     99 // =========================
    100 
    101 // itemize cells and set values to the default properties
    102 i = 0
    103 x = FIELD_X
    104 y = FIELD_Y
    105 while (i < COLUMNS * ROWS) {
    106     // create array of properties
    107     CELLS[i] = new()
    108     
    109     // set cell's properties
    110     CELLS[i].x_coord = x + 1
    111     CELLS[i].y_coord = y + 1
    112     // set cell's type to empty (0)
    113     CELLS[i].type = 0
    114 
    115     x = x + CELL_SIZE
    116 
    117     // if the right edge is reached
    118     if (x >= FIELD_X * -1) {
    119         x = FIELD_X
    120         y = y + CELL_SIZE
    121     } 
    122     
    123     i = i + 1
    124 }
    125 
    126 // draw water cells on the map
    127 i = 0
    128 while (i < COLUMNS * ROWS) {
    129     rand_num = rand() % (COLUMNS * ROWS)
    130     chance_num = 30
    131     bonus_num = 0
    132     
    133     // if the cell above is water
    134     // increase chances of the current cell becoming a water
    135     if (CELLS[get_cell_above(i)].type == 3) {
    136         bonus_num = COLUMNS * ROWS / WATER_SIZE
    137     }
    138     
    139     // if the cell on the left is water
    140     // increase chances of the current cell becoming a water
    141     if (CELLS[get_cell_left(i)].type == 3) {
    142         bonus_num = COLUMNS * ROWS / WATER_SIZE
    143     }
    144     
    145     // if the cell above and on the left are both water
    146     // make a 100% change of this cell becoming a water
    147     // (to prevent generation of 'islands')
    148     if (CELLS[get_cell_above(i)].type == 3) &&
    149        (CELLS[get_cell_left(i)].type == 3) {
    150         bonus_num = COLUMNS * ROWS
    151     }
    152     
    153     if (rand_num <= chance_num + bonus_num) {
    154         fbox(CELLS[i].x_coord, CELLS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1, COL_WATER)
    155         effector(EFF_SPREAD_UP, 10, COL_WATER, CELLS[i].x_coord, CELLS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1)
    156         effector(EFF_SPREAD_DOWN, 10, COL_WATER, CELLS[i].x_coord, CELLS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1)
    157         effector(EFF_SPREAD_LEFT, 10, COL_WATER, CELLS[i].x_coord, CELLS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1)
    158         effector(EFF_SPREAD_RIGHT, 10, COL_WATER, CELLS[i].x_coord, CELLS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1)
    159         
    160         // set cell's type to water (3)
    161         CELLS[i].type = 3
    162     }
    163     
    164     i = i + 1
    165 }
    166 
    167 // draw food cells on the map
    168 i = 0
    169 while (i < COLUMNS * ROWS) {
    170     rand_num = rand() % (COLUMNS * ROWS)
    171     
    172     if (rand_num <= FOOD_FREQ) && (CELLS[i].type == 0) {
    173         fbox(CELLS[i].x_coord, CELLS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1, COL_FOOD)
    174         
    175         // set cell's type to food (2)
    176         CELLS[i].type = 2
    177     }
    178     
    179     i = i + 1
    180 }
    181 
    182 // generate initial bots and draw them on the map
    183 count = 0
    184 while (count != BOTS_QTY) {
    185     rand_num = rand() % (COLUMNS * ROWS)
    186     
    187     // if selected cell is empty
    188     if (CELLS[rand_num].type == 0) {
    189         // create array of properties
    190         BOTS[count] = new()
    191         
    192         // set bot's properties
    193         BOTS[count].x_coord = CELLS[rand_num].x_coord
    194         BOTS[count].y_coord = CELLS[rand_num].y_coord
    195         BOTS[count].cell = rand_num
    196         BOTS[count].energy = BOTS_ENERGY
    197         BOTS[count].thirst = BOTS_THIRST
    198         BOTS[count].is_alive = 1
    199         
    200         // create bot's genome
    201         BOTS[count].genome = new(BOTS_GENOME_SIZE, INT)
    202         
    203         // fillin bot's genome with random genes (later actions)
    204         gene = 0
    205         while (gene < BOTS_GENOME_SIZE) {
    206             BOTS[count].genome[gene] = rand() % BOTS_GENE_NUM
    207             
    208             gene = gene + 1
    209         }
    210         
    211         // set cell's type to bot (1)
    212         CELLS[rand_num].type = 1
    213         
    214         // life indicator
    215         //indic = (BOTS[count].energy + BOTS[count].thirst) / 2
    216         
    217         fbox(BOTS[count].x_coord, BOTS[count].y_coord, CELL_SIZE - 1, CELL_SIZE - 1, COL_BOT_ALIVE)
    218         //print(n2s(indic), BOTS[count].x_coord + (CELL_SIZE / 2), BOTS[count].y_coord + (CELL_SIZE / 2), WHITE)
    219 
    220         count = count + 1
    221     }
    222     
    223     else {
    224         continue
    225     }
    226 }
    227 
    228 // =========================
    229 
    230 // current generation of bots
    231 generation = 0
    232 // expected lifetime of bots
    233 lifetime = (BOTS_ENERGY + BOTS_THIRST) / 2
    234 
    235 print("Generation:", (FIELD_W / 2) + 60, -50, WHITE)
    236 rprint(n2s(generation), (FIELD_W / 2) + 130, -50, RED, COL_BG)
    237 
    238 print("Lifetime:", (FIELD_W / 2) + 60, 50, WHITE)
    239 rprint(n2s(lifetime), (FIELD_W / 2) + 130, 50, RED, COL_BG)
    240 
    241 // start the main loop
    242 main:
    243 
    244 // number of steps before generation change
    245 steps = 0
    246 // current bot's genome
    247 bot = 0
    248 // current bot's gene
    249 gene = 0
    250 while 1 {
    251     // if more than half of bots are alive
    252     if (num_bots_alive() > (BOTS_QTY / 2)) {
    253     
    254         // if selected bot is alive
    255         if (BOTS[bot].is_alive == 1) {
    256             // perform an action that corresponds to
    257             // the current gene
    258             execute_gene(bot, gene)
    259             
    260             // update bot's life status
    261             bot_life_status(bot)
    262         }
    263             
    264         // switch controls to the next bot
    265         bot = bot + 1
    266         
    267         // reset the bot counter
    268         if (bot == BOTS_QTY) {
    269             bot = 0
    270             gene = gene + 1
    271             
    272             steps = steps + 1
    273 
    274             // reset the gene counter
    275             if (gene == BOTS_GENOME_SIZE) {
    276                 gene = 0
    277                 
    278             }
    279         }
    280         
    281 	    while get_event() { 
    282 	        if EVT[EVT_TYPE] == EVT_QUIT { 
    283 	            halt 
    284 	        }
    285 	    }
    286 	         
    287 	    frame()
    288 	}
    289 	
    290 	else {
    291 	    // new generation
    292 	    generation = generation + 1
    293 	    lifetime = steps
    294 	    
    295 	    rprint(n2s(generation), (FIELD_W / 2) + 130, -50, RED, COL_BG)
    296 	    rprint(n2s(lifetime), (FIELD_W / 2) + 130, 50, RED, COL_BG)
    297 	    
    298         goto next
    299 	}
    300 }
    301 
    302 // copy genome of all alive bots
    303 // (with a certain prob. of mutation)
    304 // and 'program' new generation of bots.
    305 next:
    306     
    307     i = 0
    308     while (i < BOTS_QTY) {
    309         // if bot is deceased
    310         if (BOTS[i].is_alive == 0) {
    311             // choose a random alive bot
    312             while 1 {
    313                 // generate random bot ID
    314                 parent_bot = rand() % BOTS_QTY
    315                 
    316                 if (BOTS[parent_bot].is_alive == 1) {
    317                     break
    318                 }
    319             }
    320             
    321             // select position of the child bot
    322             child_bot = get_child_cell(parent_bot)
    323 
    324             // set bot's properties
    325             BOTS[i].x_coord = CELLS[child_bot].x_coord
    326             BOTS[i].y_coord = CELLS[child_bot].y_coord
    327             BOTS[i].cell = child_bot
    328             BOTS[i].energy = BOTS_ENERGY
    329             BOTS[i].thirst = BOTS_THIRST
    330             BOTS[i].is_alive = 1
    331             
    332             // copy alive bot's genome
    333             gene = 0
    334             while (gene < BOTS_GENOME_SIZE) {
    335                 // chance of gene's mutation
    336                 rand_mut = rand() % 100
    337                 
    338                 // gene mutates
    339                 if (rand_mut < BOTS_MUT) {
    340                     BOTS[i].genome[gene] = rand() % BOTS_GENE_NUM
    341                 }
    342                 
    343                 // gene stays the same
    344                 else {
    345                     BOTS[i].genome[gene] = BOTS[parent_bot].genome[gene]
    346                 }
    347                 
    348                 gene = gene + 1
    349             }
    350             
    351             // set cell's type to bot (1)
    352             CELLS[child_bot].type = 1
    353             
    354             // life indicator
    355             //indic = (BOTS[i].energy + BOTS[i].thirst) / 2
    356             
    357             fbox(BOTS[i].x_coord, BOTS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1, COL_BOT_ALIVE)
    358             //print(n2s(indic), BOTS[i].x_coord + (CELL_SIZE / 2), BOTS[i].y_coord + (CELL_SIZE / 2), WHITE)
    359         }
    360         // if bot is alive
    361         else {
    362             if (BOTS[i].energy < BOTS_ENERGY) && (BOTS[i].thirst < BOTS_THIRST) {
    363                 BOTS[i].energy = BOTS_ENERGY
    364                 BOTS[i].thirst = BOTS_THIRST
    365             }
    366             
    367             // life indicator
    368             //indic = (BOTS[i].energy + BOTS[i].thirst) / 2
    369             
    370             fbox(BOTS[i].x_coord, BOTS[i].y_coord, CELL_SIZE - 1, CELL_SIZE - 1, COL_BOT_ALIVE)
    371             //print(n2s(indic), BOTS[i].x_coord + (CELL_SIZE / 2), BOTS[i].y_coord + (CELL_SIZE / 2), WHITE)
    372         }
    373         
    374         i = i + 1
    375     }
    376         
    377     goto main
    378     
    379 // =========================
    380 
    381 fn get_child_cell($bot) {
    382     $cell = BOTS[$bot].cell
    383     
    384     mov:
    385         // random movement from parent's position
    386         $rand_mov = rand() % 8
    387         
    388         if ($rand_mov == 0) {
    389             $cell = get_cell_ul_diag($cell)
    390         }
    391         
    392         if ($rand_mov == 1) {
    393             $cell = get_cell_above($cell)
    394         }
    395         
    396         if ($rand_mov == 2) {
    397             $cell = get_cell_ur_diag($cell)
    398         }
    399         
    400         if ($rand_mov == 3) {
    401             $cell = get_cell_left($cell)
    402         }
    403         
    404         if ($rand_mov == 4) {
    405             $cell = get_cell_right($cell)
    406         }
    407         
    408         if ($rand_mov == 5) {
    409             $cell = get_cell_dl_diag($cell)
    410         }
    411         
    412         if ($rand_mov == 6) {
    413             $cell = get_cell_below($cell)
    414         }
    415         
    416         if ($rand_mov == 7) {
    417             $cell = get_cell_dr_diag($cell)
    418         }
    419     
    420     // if selected cell in empty
    421     if (CELLS[$cell].type == 0) {
    422         ret($cell) 
    423     }
    424     
    425     // repeat the process
    426     else {
    427         goto mov
    428     }
    429     
    430 }