├── README.md ├── index.html ├── style.css └── gol.js /README.md: -------------------------------------------------------------------------------- 1 | # GameOfLife 2 | Emulation of Generation sequence using Cellular Automata 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Game of Life 7 | 8 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |
18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 |

28 |

GAME

29 |

OF

30 |

LIFE

31 | 32 |
33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | 41 |
42 |
43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | /* BODY */ 2 | body { 3 | background-color: #111411; 4 | min-width: max-content; 5 | height: 100%; 6 | } 7 | 8 | /* DIVS */ 9 | #main_div{ 10 | margin: 0 auto; 11 | width: 760px; 12 | 13 | } 14 | 15 | #opt_div{ 16 | float: left; 17 | width: 120px; 18 | height: 100%; 19 | } 20 | 21 | #disp_div{ 22 | float: right; 23 | width: 640px; 24 | height: 100%; 25 | } 26 | 27 | /* CANVASES */ 28 | canvas{ 29 | background-color: #000000; 30 | border-radius: 10px; 31 | transition-duration: 1000ms; 32 | } 33 | 34 | canvas:hover{ 35 | box-shadow: 0px 0px 12px 12px #070707; 36 | transition-duration: 2000ms; 37 | } 38 | 39 | #game_cnv{ 40 | margin: 0 auto; 41 | } 42 | 43 | #chart_cnv{ 44 | margin-top: 10; 45 | } 46 | 47 | #data_cnv{ 48 | margin-top: 10; 49 | margin-right: 6; 50 | } 51 | 52 | /* OPTION PANEL */ 53 | #option_panel{ 54 | text-align: center; 55 | background-color: #ff0000; 56 | border-radius: 10px; 57 | padding: 10px 0px; 58 | height: 710px; 59 | width:120px; 60 | transition-duration: 1000ms; 61 | margin-right: 10px; 62 | 63 | } 64 | 65 | #option_panel:hover{ 66 | box-shadow: 0px 0px 12px 12px #d4e2e2; 67 | transition-duration: 2000ms; 68 | 69 | } 70 | 71 | .opt_el{ 72 | color: rgb(237, 245, 237); 73 | margin: 10px 0px; 74 | width: 90px; 75 | height:20px; 76 | text-align: center; 77 | font-size: 18px; 78 | font-weight: bold; 79 | 80 | } 81 | 82 | input{ 83 | border-radius: 5px; 84 | background-color: #111411; 85 | 86 | 87 | } 88 | 89 | /* removes spinners from input boxes */ 90 | input[type=number]::-webkit-inner-spin-button, 91 | input[type=number]::-webkit-outer-spin-button { 92 | -webkit-appearance: none; 93 | margin: 0; 94 | } 95 | 96 | #restart_btn{ 97 | transition-duration: 1000ms; 98 | width:100px; 99 | height: 100px; 100 | } 101 | 102 | #restart_btn:hover{ 103 | transform: scale(1); 104 | box-shadow: 0px 0px 15px 15px #00c0fa; 105 | transition-duration: 2000ms; 106 | } 107 | 108 | #abt,#me{ 109 | background-color: #111411; 110 | border-radius: 5px; 111 | color: #ffffff; 112 | font-size: 18px; 113 | font-weight: bold; 114 | margin: 10px 0px; 115 | padding: 5px; 116 | width: 100px; 117 | height: 40px; 118 | transition-duration: 1000ms; 119 | } 120 | 121 | #abt:hover 122 | { 123 | background-color: #fae100; 124 | transition-duration: 1000ms; 125 | color:black; 126 | } 127 | #me:hover 128 | { 129 | background-color: #8100fa; 130 | transition-duration: 1000ms; 131 | } 132 | h3{ 133 | color: #ffffff; 134 | font-size: 18px;} 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /gol.js: -------------------------------------------------------------------------------- 1 | // === CONSTANTS === 2 | 3 | // canvases and other elements 4 | const game_cvs = document.getElementById("game_cnv"); 5 | const game_ctx = game_cvs.getContext("2d"); 6 | const chart_cvs = document.getElementById("chart_cnv"); 7 | const chart_ctx = chart_cvs.getContext("2d"); 8 | const data_cvs = document.getElementById("data_cnv"); 9 | const data_ctx = data_cvs.getContext("2d"); 10 | 11 | 12 | // unit of measure 13 | const unit = 4; 14 | 15 | // base values 16 | const matrix_side_length = 160; 17 | 18 | 19 | // === INPUT VARIABLES === 20 | let populate_chance; 21 | let time_per_gen; 22 | 23 | 24 | // === RUNTIME VARIABLES === 25 | let game_interval; 26 | let generation; 27 | let live_cells; 28 | 29 | 30 | // === GAME INIT === 31 | 32 | // creates empty matrix 33 | function get_empty_matrix(side_length){ 34 | 35 | var matrix = new Array(side_length); 36 | for (i = 0; i < matrix.length; i++){ 37 | matrix[i] = new Array(side_length); 38 | } 39 | return matrix; 40 | } 41 | 42 | // game matrix 43 | var matrix = get_empty_matrix(matrix_side_length); 44 | let new_gen_matrix; 45 | 46 | function init_matrix(){ 47 | for (i = 0; i < matrix_side_length; i++){ 48 | for (j = 0; j < matrix_side_length; j++){ 49 | if(Math.random() < populate_chance){ 50 | matrix[i][j] = 1; 51 | } else { 52 | matrix[i][j] = 0; 53 | } 54 | } 55 | } 56 | } 57 | 58 | 59 | 60 | 61 | // === GAME WORKINGS === 62 | 63 | // Conway's Game of Life ruleset: 64 | // 1. Any live cell with fewer than two live neighbours dies (referred to as underpopulation or exposure[1]). 65 | // 2. Any live cell with more than three live neighbours dies (referred to as overpopulation or overcrowding). 66 | // 3. Any live cell with two or three live neighbours lives, unchanged, to the next generation. 67 | // 4. Any dead cell with exactly three live neighbours will come to life. 68 | // "live cell" is represented as a "1" in the matrix 69 | // "dead cell" is represented as a "0" in the matrix 70 | 71 | // returns cell's alive status 72 | function is_live_cell(i,j){ 73 | return matrix[i][j] == 1; 74 | } 75 | 76 | // updates a single cell 77 | function update_cell(i,j){ 78 | 79 | // counts cell's alive neighbours 80 | var neighbours = 0; 81 | 82 | // iterate over all neighbours 83 | for (i_in = i-1; i_in <= i+1; i_in++){ 84 | for (j_in = j-1; j_in <= j+1; j_in++){ 85 | 86 | // skip out of matrix indexes 87 | if (i_in < 0 || j_in < 0){ 88 | continue; 89 | } 90 | if (i_in >= matrix_side_length || j_in >= matrix_side_length){ 91 | continue; 92 | } 93 | 94 | // skip current cell 95 | if (i_in == i && j_in == j){ 96 | continue; 97 | } 98 | 99 | // check neighboor status, increment count if alive 100 | if (is_live_cell(i_in,j_in)){ 101 | neighbours++; 102 | } 103 | 104 | // update this cell 105 | if(is_live_cell(i,j)){ 106 | // rule 1 107 | if(neighbours < 2){ 108 | new_gen_matrix[i][j] = 0; 109 | // rule 2 110 | } else if (neighbours > 3){ 111 | new_gen_matrix[i][j] = 0; 112 | // rule 3 113 | } else { 114 | new_gen_matrix[i][j] = 1; 115 | } 116 | } else { 117 | // rule 4 118 | if (neighbours == 3){ 119 | new_gen_matrix[i][j] = 1; 120 | } else { 121 | new_gen_matrix[i][j] = 0; 122 | } 123 | } 124 | 125 | } 126 | } 127 | 128 | } 129 | 130 | 131 | // updates all cells 132 | function update_all(){ 133 | 134 | // initiates new matrix 135 | new_gen_matrix = get_empty_matrix(matrix_side_length); 136 | var new_live_cells = 0; 137 | 138 | // updates all cells 139 | for (i = 0; i < matrix_side_length; i++){ 140 | for (j = 0; j < matrix_side_length; j++){ 141 | update_cell(i,j); 142 | // if the cell is alive in next generation, increment live cells amount 143 | if(new_gen_matrix[i][j]==1){ 144 | new_live_cells++; 145 | } 146 | } 147 | } 148 | 149 | // replaces old matrix with the new one 150 | matrix = new_gen_matrix; 151 | 152 | // increment generation 153 | generation++; 154 | 155 | // update live cells 156 | live_cells = new_live_cells; 157 | } 158 | 159 | // === GAME DISPLAY === 160 | 161 | // clears game canvas 162 | function clear_game_canvas(){ 163 | game_ctx.clearRect(0,0,unit*matrix_side_length,unit*matrix_side_length) 164 | } 165 | 166 | // draws current state of matrix 167 | function disp_curr_game_state(){ 168 | game_ctx.fillStyle = "yellow" ; 169 | for (i = 0; i < matrix_side_length; i++){ 170 | for (j = 0; j < matrix_side_length; j++){ 171 | if( matrix[i][j] == 1 ){ 172 | game_ctx.fillRect(i*unit, j*unit, unit, unit); 173 | } 174 | } 175 | } 176 | } 177 | 178 | 179 | 180 | // === DATA DISPLAY === 181 | 182 | 183 | // clears data canvas 184 | function clear_data_canvas(){ 185 | data_ctx.clearRect(0,0,110,80) 186 | } 187 | 188 | // draws current state of game data 189 | function disp_curr_data_state(){ 190 | data_ctx.fillStyle = "lightgreen" ; 191 | data_ctx.font = "16px Arial"; 192 | data_ctx.fillText('Living Cells:',5,18); 193 | data_ctx.fillText(live_cells,5,36); 194 | data_ctx.fillText('Geneation:',5,54); 195 | data_ctx.fillText(generation,5,72); 196 | } 197 | 198 | 199 | 200 | // === CHART DISPLAY === 201 | 202 | // constants 203 | const chart_max_value = 6000; 204 | const gens_per_display = 5; 205 | const gridX_spacing = 100/gens_per_display; 206 | const gridY_spacing = 80/6; 207 | 208 | 209 | // draws chart grid 210 | function init_chart_grid(){ 211 | chart_ctx.fillStyle = "skyblue" ; 212 | // vertical lines 213 | for(i = 0; i < 520; i+=gridX_spacing){ 214 | chart_ctx.fillRect(i,0,1,80); 215 | } 216 | // horisontal lines 217 | for(i = gridY_spacing; i < 80; i+=gridY_spacing){ 218 | chart_ctx.fillRect(0,i,520,1); 219 | } 220 | } 221 | 222 | // clears chart canvas 223 | function clear_chart_canvas(){ 224 | chart_ctx.clearRect(0,0,520,80) 225 | init_chart_grid(); 226 | } 227 | 228 | // draws current state of matrix 229 | function draw_to_chart(){ 230 | chart_ctx.fillStyle = "red" ; 231 | var height = live_cells/chart_max_value * 80; 232 | chart_ctx.fillRect(generation/gens_per_display, 80-height,1,80); 233 | } 234 | 235 | 236 | 237 | 238 | // draw current state to the canvas 239 | function contDraw(){ 240 | 241 | clear_game_canvas(); 242 | disp_curr_game_state(); 243 | 244 | clear_data_canvas(); 245 | disp_curr_data_state(); 246 | 247 | draw_to_chart(); 248 | 249 | update_all(); 250 | } 251 | 252 | 253 | // starts the game 254 | function run_game_of_life(vgen, gen_per_sec){ 255 | 256 | // clears existing interval (othervise restarting the game would speed it up) 257 | clearInterval(game_interval); 258 | 259 | // set input values 260 | populate_chance = vgen; 261 | time_per_gen = 1000/gen_per_sec; 262 | 263 | // reset state values 264 | generation = 1; 265 | live_cells = 0; 266 | clear_chart_canvas(); 267 | 268 | // init 269 | init_matrix(); 270 | disp_curr_game_state(); 271 | init_chart_grid(); 272 | 273 | // call draw function every {time_per_gen} ms 274 | game_interval = setInterval(contDraw,time_per_gen); 275 | } 276 | 277 | 278 | 279 | 280 | 281 | 282 | --------------------------------------------------------------------------------