Шлычков курсовая

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск

Игра "Жизнь" Джона Конвея.

Выполнено Шлычковым Никитой на языке программирования JavaScript.

Правила

  • Место действия этой игры — «вселенная» — это размеченная на клетки поверхность или плоскость — безграничная, ограниченная, или замкнутая (в пределе — бесконечная плоскость).
  • Каждая клетка на этой поверхности может находиться в двух состояниях: быть «живой» (заполненной) или быть «мёртвой» (пустой). Клетка имеет восемь соседей, окружающих её.
  • Распределение живых клеток в начале игры называется первым поколением. Каждое следующее поколение рассчитывается на основе предыдущего по таким правилам:
    • в пустой (мёртвой) клетке, рядом с которой ровно три живые клетки, зарождается жизнь;
    • если у живой клетки есть две или три живые соседки, то эта клетка продолжает жить; в противном случае, если соседей меньше двух или больше трёх, клетка умирает («от одиночества» или «от перенаселённости»)

"Вселенная" игры

Код программы

Код программы на языке JavaScript:
  1 const directions = document.createElement('span');
  2 const panel = document.getElementById('panel');
  3 const birth = document.createElement('INPUT');
  4 const survival = document.createElement('INPUT');
  5 const directions2 = document.createElement('SPAN');
  6 const submit_button = document.createElement('input');
  7 const space = document.createElement('span');
  8 const nextbutton = document.createElement('input');
  9 const togglebutton = document.createElement('input');
 10 const speedslide = document.createElement('input');
 11 const button1 = document.createElement('input');
 12 const button2 = document.createElement('input');
 13 var birt = birth.value;
 14 var surv = survival.value;
 15 var birt_array = [];
 16 var surv_array = [];
 17 var meaninglessvariable = 0;
 18 var birtl = 0;
 19 var survl = 0;
 20 const canvas = document.getElementById('canbas');
 21 const ctx = canvas.getContext('2d');
 22 const h = canvas.height;
 23 const w = canvas.width;
 24 const gridinterval = 800/40;
 25 var cells_array = [];
 26 var next_cells_array = [];
 27 var mousex = 0;
 28 var mousey = 0;
 29 var neighbours = [];
 30 ctx.fillStyle = 'black';
 31 ctx.strokeStyle = 'grey';
 32 var cellnum = w*h/Math.pow(gridinterval, 2);
 33 var neighbours_alive = 0;
 34 var auto = false;
 35 
 36 var Cell = function(x, y, alive){
 37 	this.x = x;
 38 	this.y = y;
 39 	this.alive = alive;
 40 }
 41 
 42 var current_cell = new Cell(gridinterval/2, gridinterval/2, false);
 43 
 44 
 45 window.addEventListener('load', createControlBar1, false);
 46 
 47 
 48 function createControlBar1(){
 49 	panel.innerHTML = '';
 50 	console.log('Creating rules panel', performance.now());
 51 	panel.appendChild(directions);
 52 	directions.innerHTML = 'Введите условия рождения и выживания клетки: B';
 53 	panel.appendChild(birth);
 54 	birth.setAttribute('size', '5');
 55 	birth.setAttribute('maxlength', '8');
 56 	birth.setAttribute('value', '3');
 57 	panel.appendChild(directions2);
 58 	directions2.innerHTML = '/S';	
 59 	panel.appendChild(survival);
 60 	survival.setAttribute('size', '5');
 61 	survival.setAttribute('maxlength', '8');
 62 	survival.setAttribute('value', '23');
 63 	panel.appendChild(space);
 64 	space.innerHTML = '       ';
 65 	panel.appendChild(submit_button);
 66 	submit_button.setAttribute('type', 'button');
 67 	submit_button.setAttribute('value', 'Подтвердить');
 68 	submit_button.setAttribute('onclick', 'readRules()');	
 69 	console.log('Rules panel created', performance.now());
 70 }
 71 
 72 function readRules() {
 73 	if (birth.value != '' && survival.value != ''){
 74 		console.log('Setting rules', performance.now());
 75 		birtl = birth.value.length;
 76 		survl = survival.value.length;
 77 		birt = parseInt(birth.value);
 78 		surv = parseInt(survival.value);
 79 		console.log('b', birt, 's', surv);
 80 		getRules();
 81 		createCells();
 82 		createControlBar2();
 83 		drawgrid();
 84 	} else {
 85 		alert('Ты чёрт');
 86 	}
 87 }
 88 
 89 function getRules() {
 90 	for (i = 0; i<birtl; i++){
 91 		let meaninglessvariable = birt % 10;
 92 		if (birt_array.indexOf(meaninglessvariable, 0) == -1){
 93 			birt_array.push(meaninglessvariable);
 94 			console.log('Birth condition ', i, ': ', meaninglessvariable);
 95 		}
 96 		birt = parseInt((birt - meaninglessvariable)/10);
 97 	}
 98 	for (i = 0; i<survl; i++){
 99 		let meaninglessvariable = surv % 10;
100 		if (surv_array.indexOf(meaninglessvariable, 0) == -1){
101 			surv_array.push(meaninglessvariable);
102 			console.log('Survival condition ', i, ': ', meaninglessvariable);
103 		}
104 		surv = parseInt((surv - meaninglessvariable)/10);
105 	}
106 	console.log('Rules set', performance.now());
107 }
108 
109 function createControlBar2() {
110 	panel.innerHTML = '';
111 	canvas.setAttribute('onclick', 'toggleCell()');
112 	panel.appendChild(button1);
113 	button1.setAttribute('type', 'button');
114 	button1.setAttribute('value', 'Restart');
115 	button1.setAttribute('onclick', 'restart()');
116 	panel.appendChild(button2);
117 	button2.setAttribute('type', 'button');
118 	button2.setAttribute('value', 'Generate');
119 	button2.setAttribute('onclick', 'pregen()');
120 	panel.appendChild(nextbutton);
121 	nextbutton.setAttribute('type', 'button');
122 	nextbutton.setAttribute('value', 'Next');
123 	nextbutton.setAttribute('onclick', 'stepp()');
124 	panel.appendChild(togglebutton);
125 	togglebutton.setAttribute('type', 'button');
126 	togglebutton.setAttribute('value', 'Start');
127 	togglebutton.setAttribute('onclick', 'autostep()');
128 	panel.appendChild(directions);
129 	directions.innerHTML = '  Speed';
130 	panel.appendChild(speedslide);
131 	speedslide.setAttribute('type', 'range');
132 	speedslide.setAttribute('min', '10');
133 	speedslide.setAttribute('max', '500');
134 	speedslide.setAttribute('value', '100');
135 	
136 }
137 
138 function drawgrid() {
139 	for (var i=0; i<w/gridinterval; i++){		
140 		ctx.beginPath();
141 		ctx.moveTo(gridinterval*i, 0);
142 		ctx.lineTo(gridinterval*i, h);
143 		ctx.stroke();
144 		ctx.beginPath();
145 		ctx.moveTo(0, gridinterval*i);
146 		ctx.lineTo(w, gridinterval*i);
147 		ctx.stroke();		
148 	}
149 }
150 
151 function createCells() {
152 	cells_array = [];
153 	console.log('Filling cells array', performance.now());
154 	for (j=0; j<h/gridinterval; j++) {
155 		for (i=0; i<w/gridinterval; i++){
156 			let cell = new Cell((i+0.5)*gridinterval, (j+0.5)*gridinterval, false);
157 			cells_array.push(cell);
158 		}
159 	}
160 	for (j=0; j<h/gridinterval; j++) {
161 		for (i=0; i<w/gridinterval; i++){
162 			let cell = new Cell((i+0.5)*gridinterval, (j+0.5)*gridinterval, false);
163 			next_cells_array.push(cell);
164 		}
165 	}
166 	console.log('Cells array filled', performance.now());
167 }
168 
169 function getMouseCoords() {
170 	mousex = event.clientX - canvas.getBoundingClientRect().left;
171 	mousey = event.clientY - canvas.getBoundingClientRect().top;
172 }
173 
174 function toggleCell() {
175 	getMouseCoords();
176 	let cellx = (mousex - (mousex % gridinterval)) + gridinterval/2;
177 	let celly = (mousey - (mousey % gridinterval)) + gridinterval/2;
178 	let cell_num = (celly/gridinterval - 0.5)*w/gridinterval + (cellx/gridinterval - 0.5);
179 	console.log('x', cellx, '(', mousex, ')', 'y', celly, '(', mousey, ') - ', cell_num);
180 	if (cells_array[cell_num].alive) {
181 		ctx.clearRect(cellx-gridinterval/2 + gridinterval/20, celly-gridinterval/2 + gridinterval/20, gridinterval - gridinterval/10, gridinterval - gridinterval/10)
182 		cells_array[cell_num].alive = false;
183 		console.log('Kill');
184 	} else {
185 		ctx.beginPath();
186 		ctx.arc(cellx, celly, gridinterval*0.4, 0, 2*Math.PI);
187 		ctx.fill();
188 		cells_array[cell_num].alive = true;
189 		console.log('Spare');
190 	}
191 }
192 
193 function life(a) {
194 	neighbours = [];
195 	neighbours_alive = 0;
196 	if (cells_array[a].y == gridinterval/2) {  //Верхняя строка
197 		if (cells_array[a].x == gridinterval/2) {
198 			neighbours.push(cells_array[cellnum-1]);
199 			neighbours.push(cells_array[cellnum-w/gridinterval]);
200 			neighbours.push(cells_array[cellnum-w/gridinterval+1]);
201 			neighbours.push(cells_array[a+1]);
202 			neighbours.push(cells_array[w/gridinterval+1]);
203 			neighbours.push(cells_array[w/gridinterval]);
204 			neighbours.push(cells_array[2*w/gridinterval-1]);
205 			neighbours.push(cells_array[w/gridinterval-1]);
206 		}
207 		if (cells_array[a].x == w - gridinterval/2) {
208 			neighbours.push(cells_array[cellnum-2]);
209 			neighbours.push(cells_array[cellnum-1]);
210 			neighbours.push(cells_array[cellnum-w/gridinterval]);
211 			neighbours.push(cells_array[0]);
212 			neighbours.push(cells_array[w/gridinterval]);
213 			neighbours.push(cells_array[a+w/gridinterval]);
214 			neighbours.push(cells_array[a+w/gridinterval-1]);
215 			neighbours.push(cells_array[a-1]);			
216 		} else {
217 			neighbours.push(cells_array[cellnum - w/gridinterval + a - 1]);
218 			neighbours.push(cells_array[cellnum - w/gridinterval + a]);
219 			neighbours.push(cells_array[cellnum - w/gridinterval + a + 1]);
220 			neighbours.push(cells_array[a+1]);
221 			neighbours.push(cells_array[a+w/gridinterval+1]);
222 			neighbours.push(cells_array[a+w/gridinterval]);
223 			neighbours.push(cells_array[a+w/gridinterval-1]);
224 			neighbours.push(cells_array[a-1]);
225 		}
226 	}
227 	if (cells_array[a].y == h - gridinterval/2) {  //Нижняя строка
228 		if (cells_array[a].x == gridinterval/2) { //Левый нижний
229 			neighbours.push(cells_array[a-1]);
230 			neighbours.push(cells_array[a-w/gridinterval]);
231 			neighbours.push(cells_array[a-w/gridinterval+1]);
232 			neighbours.push(cells_array[a+1]);
233 			neighbours.push(cells_array[1]);
234 			neighbours.push(cells_array[0]);
235 			neighbours.push(cells_array[w/gridinterval-1]);
236 			neighbours.push(cells_array[cellnum-1]);
237 		}
238 		if (cells_array[a].x == w - gridinterval/2) { //Правый нижний
239 			neighbours.push(cells_array[a-w/gridinterval-1]);
240 			neighbours.push(cells_array[a-w/gridinterval]);
241 			neighbours.push(cells_array[a - 2*w/gridinterval + 1]);
242 			neighbours.push(cells_array[a-w/gridinterval+1]);
243 			neighbours.push(cells_array[0]);
244 			neighbours.push(cells_array[w/gridinterval-1]);
245 			neighbours.push(cells_array[w/gridinterval-2]);
246 			neighbours.push(cells_array[a-1]);		
247 		} else { //Не угловая клетка
248 			neighbours.push(cells_array[a-w/gridinterval-1]);
249 			neighbours.push(cells_array[a-w/gridinterval]);
250 			neighbours.push(cells_array[a-w/gridinterval+1]);
251 			neighbours.push(cells_array[a+1]);
252 			neighbours.push(cells_array[w/gridinterval-(cellnum-a)+1]);
253 			neighbours.push(cells_array[w/gridinterval-(cellnum-a)]);
254 			neighbours.push(cells_array[w/gridinterval-(cellnum-a)-1]);
255 			neighbours.push(cells_array[a-1]);
256 		}
257 	}
258 	if (cells_array[a].x == gridinterval/2) {  //Левый столбец
259 		neighbours.push(cells_array[a-1]);
260 		neighbours.push(cells_array[a-w/gridinterval]);
261 		neighbours.push(cells_array[a-w/gridinterval+1]);
262 		neighbours.push(cells_array[a+1]);
263 		neighbours.push(cells_array[a+w/gridinterval+1]);
264 		neighbours.push(cells_array[a+w/gridinterval]);
265 		neighbours.push(cells_array[a+2*w/gridinterval-1]);
266 		neighbours.push(cells_array[a+w/gridinterval-1]);		
267 	}
268 	if (cells_array[a].x == w - gridinterval/2) {  //Правый столбец
269 		neighbours.push(cells_array[a-w/gridinterval-1]);
270 		neighbours.push(cells_array[a-w/gridinterval]);
271 		neighbours.push(cells_array[a-2*w/gridinterval+1]);
272 		neighbours.push(cells_array[a-w/gridinterval+1]);
273 		neighbours.push(cells_array[a+1]);
274 		neighbours.push(cells_array[a+w/gridinterval]);
275 		neighbours.push(cells_array[a+w/gridinterval-1]);
276 		neighbours.push(cells_array[a-1]);		
277 	} else {
278 		neighbours.push(cells_array[a-w/gridinterval-1]);
279 		neighbours.push(cells_array[a-w/gridinterval]);
280 		neighbours.push(cells_array[a-w/gridinterval+1]);
281 		neighbours.push(cells_array[a+1]);
282 		neighbours.push(cells_array[a+w/gridinterval+1]);
283 		neighbours.push(cells_array[a+w/gridinterval]);
284 		neighbours.push(cells_array[a+w/gridinterval-1]);
285 		neighbours.push(cells_array[a-1]);
286 	}
287 	
288 	for (it=0; it<8; it++) {
289 		if (neighbours[it].alive) { neighbours_alive++ }
290 	}		
291 	
292 	if (cells_array[a].alive){
293 		if (surv_array.indexOf(neighbours_alive) == -1) { 
294 			next_cells_array[a].alive = false; 
295 		} else {
296 			next_cells_array[a].alive = true;
297 		}
298 	}
299 	if (cells_array[a].alive == false){
300 		if (birt_array.indexOf(neighbours_alive) != -1){ next_cells_array[a].alive = true; }
301 	}
302 }
303 
304 function devMarkNeigh(a) {
305 	life(a);
306 	for (i=0; i<8; i++){
307 		ctx.beginPath();
308 		ctx.arc(neighbours[i].x, neighbours[i].y, 0.2*gridinterval, 0, 2*Math.PI);
309 		ctx.fill();
310 	}
311 }
312 
313 function draw(a) {
314 	if (next_cells_array[a].alive) {
315 		ctx.beginPath();
316 		ctx.arc(next_cells_array[a].x, next_cells_array[a].y, 0.4*gridinterval, 0, 2*Math.PI);
317 		ctx.fill();
318 	} else {
319 		ctx.clearRect(next_cells_array[a].x-gridinterval/2 + gridinterval/20, next_cells_array[a].y-gridinterval/2 + gridinterval/20, gridinterval - gridinterval/10, gridinterval - gridinterval/10);
320 	}
321 }
322 
323 function change(a) {
324 	cells_array[a].alive = next_cells_array[a].alive;
325 }
326 
327 function stepp() {
328 	for (i=0; i<cellnum; i++){
329 		life(i);
330 	}
331 	for (i=0; i<cellnum; i++){
332 		draw(i);
333 	}
334 	for (i=0; i<cellnum; i++){
335 		change(i);
336 	}
337 	if (auto) {
338 		clearInterval(fps);
339 		fps = setInterval(stepp, 100*100/speedslide.value)
340 	}
341 }
342 
343 function autostep() {
344 	if (auto) {
345 		clearInterval(fps);
346 		auto = false;
347 		togglebutton.setAttribute('value', 'Start');	
348 	} else {
349 		fps = setInterval(stepp, 100*100/speedslide.value)
350 		auto = true;
351 		togglebutton.setAttribute('value', 'Stop');	
352 	}
353 }
354 
355 function pregen() {
356 	for (i = 0; i<cellnum; i++) {
357 		let v = Math.random();
358 		if (v < 0.1) {
359 			ctx.beginPath();
360 			ctx.arc(cells_array[i].x, cells_array[i].y, gridinterval*0.4, 0, 2*Math.PI);
361 			ctx.fill();
362 			cells_array[i].alive = true;
363 		}
364 	}
365 }
366 
367 function restart() {
368 	clearInterval(fps);
369 	auto = false;
370 	ctx.clearRect(0, 0, w, h);
371 	createControlBar1();	
372 }
373 
374 // Да, "Restart" звучит лучше, чем "Перезапуск", так что я позволил себе посреди программы поменять язык, простите