Created
May 29, 2019 14:57
-
-
Save oleglomako/512bd182feb8bc55fb63007ade67c9f8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style> | |
#canvas { | |
width: 500px; | |
height: 500px; | |
border: 2px solid black; | |
margin: 10px; | |
background-image: url(grid.png); | |
} | |
input, | |
button { | |
margin-left: 10px; | |
} | |
</style> | |
<div dir="ltr" style="text-align: left;" trbidi="on"> | |
<p> | |
<span> | |
<button id="btnRunLife">Run Life</button> | |
<button id="btnCleanGrid">Clean</button> | |
<button id="btnNewRandomGeneration">New Random Generation</button> | |
| |
Number of Generations: <span id="numberOfGenerations">0</span> | |
</span> | |
</p> | |
<canvas id="canvas" width="500" height="500"></canvas> | |
</div> | |
<script> | |
/** | |
* Oleg Lomako | |
* Wed, 8 May 2019 18:46:54 | |
*/ | |
let canvas = document.getElementById('canvas'); | |
let ctx = canvas.getContext('2d'); | |
let grid = []; // массив игрового поля | |
let newGrid = []; | |
// размеры игрового поля в пикселях | |
const WIDTH_GRID_PIXEL = 500; | |
const HEIGHT_GRID_PIXEL = 500; | |
// размеры клетки игрового поля | |
const WIDTH_CELL_PIXEL = 10; | |
const HEIGHT_CELL_PIXEL = 10; | |
// размеры игрового поля в количестве клеток | |
const WIDTH_GRID = Math.floor(WIDTH_GRID_PIXEL / WIDTH_CELL_PIXEL); //500 /10 = 50 | |
const HEIGHT_GRID = Math.floor(HEIGHT_GRID_PIXEL / WIDTH_CELL_PIXEL); //500 /10 = 50 | |
let numberOfGenerations = 0; // счетчик поколений | |
let timer; // таймер | |
const TIMEOUT = 300; | |
// при клике нарисовать живую клетку | |
canvas.onclick = function (event) { | |
// координаты клетки игрового поля | |
let x = event.offsetX; | |
let y = event.offsetY; | |
x = Math.floor(x / WIDTH_CELL_PIXEL); //500 /10 = 50 | |
y = Math.floor(y / HEIGHT_CELL_PIXEL); //500 /10 = 50 | |
//при клике отобразить закраш клетку | |
//если клетка закрашена то стереть клетку | |
if (grid[y][x] == 1) { | |
grid[y][x] = 0; | |
} else { | |
grid[y][x] = 1; | |
} | |
drawGrid(); | |
} | |
// создаем пустой массив поля и заполняем его нулями | |
function fillZeroGrid() { | |
for (let i = 0; i < HEIGHT_GRID; i++) { | |
grid[i] = []; | |
for (let j = 0; j < WIDTH_GRID; j++) { | |
grid[i][j] = 0; | |
} | |
} | |
} | |
function fillZeroNewGrid() { | |
for (let i = 0; i < HEIGHT_GRID; i++) { | |
newGrid[i] = []; | |
for (let j = 0; j < WIDTH_GRID; j++) { | |
newGrid[i][j] = 0; | |
} | |
} | |
} | |
// массив grid заполняем нулями | |
fillZeroGrid(); | |
// массив newGrid заполняем нулями | |
fillZeroNewGrid(); | |
// нарисовать игровое поле | |
function drawGrid() { | |
ctx.clearRect(0, 0, WIDTH_GRID_PIXEL, HEIGHT_GRID_PIXEL); | |
for (let i = 0; i < HEIGHT_GRID; i++) { | |
for (let j = 0; j < WIDTH_GRID; j++) { | |
if (grid[i][j] == 1) { | |
ctx.fillRect(j * 10, i * 10, 10, 10); | |
} | |
} | |
} | |
} | |
// моделирование жизни | |
function runLife() { | |
for (let i = 0; i < HEIGHT_GRID; i++) { | |
for (let j = 0; j < WIDTH_GRID; j++) { | |
newGrid[i][j] = result(grid[i][j], countNeighbors(i, j)); | |
} | |
} | |
nextStep(); // присваем след поколение текущему массиву | |
fillZeroNewGrid(); // очищаем массив след поколения | |
drawGrid(); | |
numberOfGenerations++; | |
document.getElementById('numberOfGenerations').innerHTML = numberOfGenerations; | |
timer = setTimeout(runLife, TIMEOUT); | |
} | |
// следующее поколение | |
function nextStep() { | |
for (let i = 0; i < HEIGHT_GRID; i++) { | |
for (let j = 0; j < WIDTH_GRID; j++) { | |
grid[i][j] = newGrid[i][j]; | |
} | |
} | |
} | |
// считаем соседей | |
function countNeighbors(xCell, yCell) { | |
let sumNeighbors = 0; | |
for (let i = -1; i < 2; i++) { | |
for (let j = -1; j < 2; j++) { | |
let neighborX = xCell - i; | |
let neighborY = yCell - j; | |
// игнорируем проверяемую клетку | |
if (neighborX == xCell && neighborY == yCell) continue; | |
let isValid = checkValid(neighborX, neighborY); | |
if (isValid) { | |
sumNeighbors += grid[neighborX][neighborY]; | |
} | |
} | |
} | |
return sumNeighbors; | |
} | |
// проверка выхода за границы поля | |
function checkValid(cX, cY) { | |
return (cX >= 0 && cX < WIDTH_GRID && cY >= 0 && cY < HEIGHT_GRID); | |
} | |
// принятие решения о состоянии клетки в след поколении | |
function result(cellBoard, neighbors) { | |
if (cellBoard == 0 && neighbors == 3) | |
return 1; | |
else if ((cellBoard == 1 && neighbors == 2)) | |
return 1; | |
else if ((cellBoard == 1 && neighbors == 3)) | |
return 1; | |
else if ((cellBoard == 1 && neighbors < 2)) | |
return 0; | |
else if ((cellBoard == 1 && neighbors > 3)) | |
return 0; | |
else | |
return cellBoard; | |
} | |
// сгенерировать и отобразить рандомно новое поколение | |
function newRandomGeneration() { | |
for (let i = 0; i < HEIGHT_GRID; i++) { | |
for (let j = 0; j < WIDTH_GRID; j++) { | |
grid[i][j] = randomInteger(0, 1); | |
} | |
} | |
drawGrid(); | |
} | |
// сгенерировать случайное число | |
function randomInteger(min, max) { | |
var rand = min + Math.random() * (max + 1 - min); | |
rand = Math.floor(rand); | |
return rand; | |
} | |
// остановить игру и обновить страницу | |
function refreshPage() { | |
window.location.reload(); | |
}; | |
document.getElementById('btnRunLife').onclick = runLife; | |
document.getElementById('btnNewRandomGeneration').onclick = newRandomGeneration; | |
document.getElementById('btnCleanGrid').onclick = refreshPage; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment