-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7b55802
commit 29f0388
Showing
4 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<link rel="stylesheet" href="./styles/main.css"/> | ||
<script src="./src/main.js" type="text/javascript" defer></script> | ||
<title>Gamek of life</title> | ||
</head> | ||
<body> | ||
<main class="main" role="main"> | ||
<div class="epocha-time-container">Epocha time: <time class="epocha-time">00:00</time></div> | ||
<div class="game-board"> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
<div class="game-cell"></div> | ||
</div> | ||
<div class="control-panel"> | ||
<button class="game-start">Start</button> | ||
<button class="game-end">Stop</button> | ||
</div> | ||
</main> | ||
</body> | ||
</html> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
const LIFE_COLOR = 'coral'; | ||
const GAME_CELL_CLASS = '.game-cell'; | ||
const GAME_BOARD_CLASS = '.game-board'; | ||
const GAME_START_BUTTON_CLASS = '.game-start'; | ||
const GAME_END_BUTTON_CLASS = '.game-end'; | ||
const EPOCHA_TIME_CLASS = '.epocha-time'; | ||
const ANIMATION_INTERVAL_SEC = 5; | ||
const SECOND_MS = 1000; | ||
const MATRIX_ROW_AMOUNT = 6; | ||
const MATRIX_COLUMN_AMOUNT = 6; | ||
|
||
const gameStart = document.querySelector(GAME_START_BUTTON_CLASS); | ||
const gameEnd = document.querySelector(GAME_END_BUTTON_CLASS); | ||
const gameBoard = document.querySelector(GAME_BOARD_CLASS); | ||
const epochaTime = document.querySelector(EPOCHA_TIME_CLASS); | ||
const gameBoardCellMatrix = getBoardCellMatrix(); | ||
|
||
gameBoard.addEventListener('click', (event) => { | ||
const gameBoardCell = event.target; | ||
if (isCellAlive(gameBoardCell)) { | ||
markCellDeath(gameBoardCell); | ||
return; | ||
} | ||
markCellAlive(gameBoardCell); | ||
}); | ||
|
||
gameStart.addEventListener('click', async (event) => { | ||
const button = event.currentTarget; | ||
if (isButtonActive(button)) { | ||
return; | ||
} | ||
button.dataset.isActive = 'true'; | ||
gameEnd.dataset.isActive = 'false'; | ||
if (!isTimerInProgress()) { | ||
await animate(); | ||
return; | ||
} | ||
await startTimer(); | ||
if (isButtonActive(gameStart)) { | ||
await animate(); | ||
} | ||
}); | ||
gameEnd.addEventListener('click', (event) => { | ||
const button = event.currentTarget; | ||
if (isButtonActive(button)) { | ||
return; | ||
} | ||
button.dataset.isActive = 'true'; | ||
gameStart.dataset.isActive = 'false'; | ||
}); | ||
|
||
async function animate() { | ||
const deltaRow = [-1, -1, -1, 0, 0, 1, 1, 1]; | ||
const deltaColumn = [-1, 0, 1, -1, 1, -1, 0, 1]; | ||
let isChanged = false; | ||
for (let i = 0; i < MATRIX_ROW_AMOUNT; i++) { | ||
for (let j = 0; j < MATRIX_COLUMN_AMOUNT; j++) { | ||
let liveNeighbours = 0; | ||
for (let k = 0; k < deltaColumn.length; k++) { | ||
let ni = i + deltaRow[k]; | ||
let nj = j + deltaColumn[k]; | ||
ni = ni < 0 ? MATRIX_ROW_AMOUNT - 1 : ni; | ||
ni = ni >= MATRIX_ROW_AMOUNT ? 0 : ni; | ||
nj = nj < 0 ? MATRIX_COLUMN_AMOUNT - 1 : nj; | ||
nj = nj >= MATRIX_COLUMN_AMOUNT ? 0 : nj; | ||
if (isCellAlive(gameBoardCellMatrix[ni][nj])) { | ||
liveNeighbours++; | ||
} | ||
} | ||
if (isCellAlive(gameBoardCellMatrix[i][j]) && (liveNeighbours < 2 || liveNeighbours > 3)) { | ||
isChanged = true; | ||
requestAnimationFrame(() => { markCellDeath(gameBoardCellMatrix[i][j]) }); | ||
continue; | ||
} | ||
if (!isCellAlive(gameBoardCellMatrix[i][j]) && liveNeighbours === 3) { | ||
isChanged = true; | ||
requestAnimationFrame(() => { markCellAlive(gameBoardCellMatrix[i][j]) }); | ||
} | ||
} | ||
} | ||
if (!isChanged) { | ||
setTimeout(() => { alert('Animation was finished with success!') }); | ||
gameStart.dataset.isActive = 'false'; | ||
return; | ||
} | ||
await startTimer(); | ||
if (isButtonActive(gameStart)) { | ||
setTimeout(() => {animate()}); | ||
} | ||
} | ||
|
||
async function startTimer() { | ||
const promise = new Promise((resolve) => { | ||
let currentInterval = +(epochaTime.dataset.time) || 0; | ||
const interval = setInterval(() => { | ||
if (isButtonActive(gameEnd)) { | ||
clearInterval(interval); | ||
resolve(); | ||
return; | ||
} | ||
if (currentInterval < ANIMATION_INTERVAL_SEC) { | ||
currentInterval++; | ||
epochaTime.dataset.time = currentInterval.toString(); | ||
requestAnimationFrame(() => { | ||
epochaTime.textContent = `${(currentInterval / 60).toFixed(0).padStart(2, '0')}:${(currentInterval % 60).toFixed(0).padStart(2, '0')}`; | ||
}); | ||
return; | ||
} | ||
requestAnimationFrame(() => { | ||
epochaTime.textContent = '00:00'; | ||
epochaTime.dataset.time = ''; | ||
}) | ||
clearInterval(interval); | ||
resolve(); | ||
}, SECOND_MS); | ||
}); | ||
return promise; | ||
} | ||
|
||
function getBoardCellMatrix() { | ||
const gameBoardCellList = document.querySelectorAll(GAME_CELL_CLASS); | ||
const gameBoardCellMatrix = []; | ||
for (let i = 0; i < MATRIX_ROW_AMOUNT; i++) { | ||
gameBoardCellMatrix[i] = []; | ||
for (let j = 0; j < MATRIX_COLUMN_AMOUNT; j++) { | ||
gameBoardCellMatrix[i][j] = gameBoardCellList[i*MATRIX_COLUMN_AMOUNT + j]; | ||
} | ||
} | ||
return gameBoardCellMatrix; | ||
} | ||
|
||
function isCellAlive(cell) { | ||
return cell.dataset.isAlive === 'true'; | ||
} | ||
|
||
function isButtonActive(button) { | ||
return button.dataset.isActive === 'true'; | ||
} | ||
|
||
function isTimerInProgress() { | ||
return !!epochaTime.dataset.time && epochaTime.dataset.time !== '0'; | ||
} | ||
|
||
function markCellAlive(cell) { | ||
cell.style.backgroundColor = LIFE_COLOR; | ||
cell.dataset.isAlive = 'true'; | ||
} | ||
|
||
function markCellDeath(cell) { | ||
cell.style.backgroundColor = ''; | ||
cell.dataset.isAlive = 'false'; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
* { | ||
margin: 0; | ||
padding: 0; | ||
outline: 0; | ||
color: black; | ||
} | ||
|
||
body { | ||
width: 100%; | ||
height: 100vh; | ||
font-size: 16px; | ||
} | ||
|
||
.main { | ||
position: relative; | ||
display: block; | ||
top: 50vh; | ||
transform: translateY(-50%); | ||
} | ||
|
||
.epocha-time-container { | ||
margin-left: 50%; | ||
display: inline-block; | ||
transform: translateX(-50%); | ||
font-size: 1.4rem; | ||
} | ||
|
||
.game-board { | ||
display: flex; | ||
margin: auto; | ||
margin-top: 2rem; | ||
position: relative; | ||
width: 60vh; | ||
border: 1px solid black; | ||
height: 60vh; | ||
flex-wrap: wrap; | ||
flex-direction: row; | ||
} | ||
|
||
.game-cell { | ||
border: 1px solid black; | ||
box-sizing: border-box; | ||
width: calc(100%/6); | ||
cursor: pointer; | ||
} | ||
|
||
.game-cell:hover { | ||
background-color:coral | ||
} | ||
|
||
.control-panel { | ||
margin-top: 4rem; | ||
display: flex; | ||
justify-content: center; | ||
gap: 6rem; | ||
} | ||
|
||
.game-start { | ||
background-color: transparent; | ||
border: 1px solid black; | ||
padding: 0.7rem 2.3rem; | ||
outline: 0; | ||
border-radius: 1rem; | ||
cursor: pointer; | ||
font-size: 1rem; | ||
} | ||
|
||
.game-end { | ||
background-color: transparent; | ||
border: 1px solid black; | ||
padding: 0.7rem 2.3rem; | ||
outline: 0; | ||
border-radius: 1rem; | ||
cursor: pointer; | ||
font-size: 1rem; | ||
} | ||
|
||
.game-start:hover, .game-end:hover { | ||
color: white; | ||
background-color: black; | ||
transition: all 0.3s ease-in-out; | ||
box-shadow: 1px 1px 4px 2px gray; | ||
} | ||
|
||
|
||
@media screen and (orientation: portrait) { | ||
.game-board { | ||
width: 60vw; | ||
height: 60vw; | ||
} | ||
} |