├── 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 |
15 |
16 |
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 |
--------------------------------------------------------------------------------