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 }