From ec75957b19d8b3da2e3bcdf883845b74d3de4d95 Mon Sep 17 00:00:00 2001 From: Maksym Bevskyi Date: Tue, 24 Oct 2023 14:04:47 +0200 Subject: [PATCH 1/6] add functionality with some issues --- src/index.html | 16 +-- src/scripts/main.js | 309 ++++++++++++++++++++++++++++++++++++++++++- src/styles/main.scss | 14 ++ 3 files changed, 329 insertions(+), 10 deletions(-) diff --git a/src/index.html b/src/index.html index cf82080f7..279ecd160 100644 --- a/src/index.html +++ b/src/index.html @@ -1,19 +1,17 @@ - - + + 2048 - +

2048

-

- Score: 0 -

+

Score: 0

@@ -34,7 +32,6 @@

2048

- @@ -42,7 +39,6 @@

2048

- @@ -55,7 +51,9 @@

2048

-

Press "Start" to begin game. Good luck!

+

+ Press "Start" to begin game. Good luck! +

diff --git a/src/scripts/main.js b/src/scripts/main.js index c6e3f8784..2f1edf7a9 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1,3 +1,310 @@ 'use strict'; -// write your code here +const messageStart = document.querySelector('.message-start'); +const messageLose = document.querySelector('.message-lose'); +const messageWin = document.querySelector('.message-win'); +const button = document.querySelector('.button'); +const score = document.querySelector('.game-score'); + +const board = [ + [1024, 256, 256, 0], + [0, 256, 256, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], +]; +const rows = 4; +const columns = 4; +let scoreCount = 0; +let won = false; +const initialBoard = board.map(row => [...row]); + +button.addEventListener('click', () => { + messageStart.classList.add('hidden'); + button.innerText = 'Restart'; + button.classList.replace('start', 'restart'); + + setGame(); +}); + +button.addEventListener('click', e => { + messageWin.classList.add('hidden'); + won = false; + setGame(); + clearBoard(); +}); + +const table = document.querySelector('.game-field'); + +const setGame = () => { + for (let r = 0; r < rows; r++) { + const row = table.querySelectorAll('.field-row')[r]; + const cells = row.querySelectorAll('.field-cell'); + + for (let c = 0; c < columns; c++) { + const cell = cells[c]; + + cell.setAttribute('id', `${r}-${c}`); + + const number = board[r][c]; + + updateCell(cell, number); + } + } + setCell(); + setCell(); +}; + +const hasEmptyCell = () => { + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns; c++) { + if (board[r][c] === 0) { + return true; + } + } + } + + return false; +}; + +const loseGame = () => { + if (hasEmptyCell()) { + return false; + } + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns; c++) { + if (board[r][c] === board[r][c + 1]) { + return false; + } + } + } + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns; c++) { + if (board[r][c] === board[r + 1][c]) { + return false; + } + } + } + + return true; +}; + +const clearBoard = () => { + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns; c++) { + const cell = document.getElementById(`${r}-${c}`); + + cell.innerText = ''; + cell.classList.value = ''; + cell.classList.add('field-cell'); + } + } + scoreCount = 0; + score.innerHTML = scoreCount; +}; + +const setCell = () => { + if (!hasEmptyCell()) { + return; + } + + let found = false; + const number = Math.random() < 0.8 ? 2 : 4; + + while (!found) { + const row = Math.floor(Math.random() * rows); + const column = Math.floor(Math.random() * columns); + + if (board[row][column] === 0) { + board[row][column] = 2; + + const cell = document.getElementById(`${row}-${column}`); + + cell.innerText = `${number}`; + cell.classList.add(`field-cell--${number}`); + found = true; + } + } + + if (loseGame()) { + messageLose.classList.remove('hidden'); + + button.addEventListener('click', () => { + messageLose.classList.add('hidden'); + + clearBoard(); + setGame(); + }); + } +}; + +const updateCell = (cell, number) => { + cell.innerText = ''; + cell.classList.value = ''; + cell.classList.add('field-cell'); + + if (number > 0) { + cell.innerText = number; + + if (number < 4096) { + cell.classList.add(`field-cell--${number}`); + } else { + cell.classList.add(`field-cell--8192`); + } + } + + if (number === 2048) { + messageWin.classList.remove('hidden'); + won = true; + } +}; + +document.addEventListener('keyup', arrow => { + arrow.preventDefault(); + + if (won) { + return; + } + + switch (arrow.key) { + case 'ArrowLeft': + slideLeft(); + break; + case 'ArrowRight': + slideRight(); + break; + case 'ArrowUp': + slideUp(); + break; + case 'ArrowDown': + slideDown(); + break; + default: + return; + } + + document.querySelector('.game-score').innerText = scoreCount; +}); + +const filterZero = row => row.filter(num => num !== 0); + +const slide = (row) => { + let initialRow = [...row]; + + initialRow = filterZero(initialRow); + + for (let i = 0; i < initialRow.length - 1; i++) { + if (initialRow[i] === initialRow[i + 1]) { + initialRow[i] *= 2; + initialRow[i + 1] = 0; + scoreCount += initialRow[i]; + } + } + + initialRow = filterZero(initialRow); + + while (initialRow.length < columns) { + initialRow.push(0); + } + + return initialRow; +}; + +const slideLeft = () => { + for (let r = 0; r < rows; r++) { + let row = board[r]; + + row = slide(row); + board[r] = row; + + for (let c = 0; c < columns; c++) { + const cell = document.getElementById(`${r}-${c}`); + const number = board[r][c]; + + updateCell(cell, number); + } + } + + if (hasChanges(initialBoard, board)) { + setCell(); + } +}; + +const slideRight = () => { + for (let r = 0; r < rows; r++) { + let row = board[r]; + + row.reverse(); + row = slide(row); + row.reverse(); + board[r] = row; + + for (let c = 0; c < columns; c++) { + const cell = document.getElementById(`${r}-${c}`); + const number = board[r][c]; + + updateCell(cell, number); + } + } + + if (hasChanges(initialBoard, board)) { + setCell(); + } +}; + +const slideUp = () => { + for (let c = 0; c < columns; c++) { + let row = [board[0][c], board[1][c], board[2][c], board[3][c]]; + + row = slide(row); + + for (let r = 0; r < rows; r++) { + board[r][c] = row[r]; + + const cell = document.getElementById(`${r}-${c}`); + const number = board[r][c]; + + updateCell(cell, number); + } + } + + if (hasChanges(initialBoard, board)) { + setCell(); + } +}; + +const slideDown = () => { + for (let c = 0; c < columns; c++) { + let row = [board[0][c], board[1][c], board[2][c], board[3][c]]; + + row.reverse(); + row = slide(row); + row.reverse(); + + for (let r = 0; r < rows; r++) { + board[r][c] = row[r]; + + const cell = document.getElementById(`${r}-${c}`); + const number = board[r][c]; + + updateCell(cell, number); + } + } + + if (hasChanges(initialBoard, board)) { + setCell(); + } +}; + +const hasChanges = (arrayA, arrayB) => { + for (let i = 0; i < arrayA.length; i++) { + for (let j = 0; j < arrayA[i].length; j++) { + if (arrayA[i][j] !== arrayB[i][j]) { + return true; + } + } + } + + return false; +}; diff --git a/src/styles/main.scss b/src/styles/main.scss index c43f37dcf..ff3efcf78 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -73,6 +73,16 @@ body { background: #edc22e; color: #f9f6f2; } + + &--4096 { + background: #fe3d3d; + color: #f9f6f2; + } + + &--8192 { + background: #ff2020; + color: #f9f6f2; + } } .game-field { @@ -144,6 +154,10 @@ h1 { &:hover { background: #179921; } + + &:focus { + outline: none; + } } .restart { From 6dedce2f44cc6ad43999c11ce0a4fe4ed9dad98b Mon Sep 17 00:00:00 2001 From: Maksym Bevskyi Date: Tue, 24 Oct 2023 16:30:54 +0200 Subject: [PATCH 2/6] fix issues --- src/scripts/main.js | 50 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/scripts/main.js b/src/scripts/main.js index 2f1edf7a9..5042af0fe 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -7,8 +7,8 @@ const button = document.querySelector('.button'); const score = document.querySelector('.game-score'); const board = [ - [1024, 256, 256, 0], - [0, 256, 256, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], ]; @@ -17,20 +17,22 @@ const columns = 4; let scoreCount = 0; let won = false; const initialBoard = board.map(row => [...row]); +let isInitialSetup = true; button.addEventListener('click', () => { - messageStart.classList.add('hidden'); - button.innerText = 'Restart'; - button.classList.replace('start', 'restart'); - - setGame(); -}); - -button.addEventListener('click', e => { - messageWin.classList.add('hidden'); - won = false; - setGame(); - clearBoard(); + if (isInitialSetup) { + messageStart.classList.add('hidden'); + button.innerText = 'Restart'; + button.classList.replace('start', 'restart'); + + setGame(); + isInitialSetup = false; + } else { + messageWin.classList.add('hidden'); + won = false; + setGame(); + clearBoard(); + } }); const table = document.querySelector('.game-field'); @@ -43,7 +45,7 @@ const setGame = () => { for (let c = 0; c < columns; c++) { const cell = cells[c]; - cell.setAttribute('id', `${r}-${c}`); + cell.setAttribute('id', `row_${r}-column_${c}`); const number = board[r][c]; @@ -72,15 +74,15 @@ const loseGame = () => { } for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { + for (let c = 0; c < rows; c++) { if (board[r][c] === board[r][c + 1]) { return false; } } } - for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { + for (let r = 0; r < rows - 1; r++) { + for (let c = 0; c < rows; c++) { if (board[r][c] === board[r + 1][c]) { return false; } @@ -93,7 +95,7 @@ const loseGame = () => { const clearBoard = () => { for (let r = 0; r < rows; r++) { for (let c = 0; c < columns; c++) { - const cell = document.getElementById(`${r}-${c}`); + const cell = document.getElementById(`row_${r}-column_${c}`); cell.innerText = ''; cell.classList.value = ''; @@ -119,7 +121,7 @@ const setCell = () => { if (board[row][column] === 0) { board[row][column] = 2; - const cell = document.getElementById(`${row}-${column}`); + const cell = document.getElementById(`row_${row}-column_${column}`); cell.innerText = `${number}`; cell.classList.add(`field-cell--${number}`); @@ -219,7 +221,7 @@ const slideLeft = () => { board[r] = row; for (let c = 0; c < columns; c++) { - const cell = document.getElementById(`${r}-${c}`); + const cell = document.getElementById(`row_${r}-column_${c}`); const number = board[r][c]; updateCell(cell, number); @@ -241,7 +243,7 @@ const slideRight = () => { board[r] = row; for (let c = 0; c < columns; c++) { - const cell = document.getElementById(`${r}-${c}`); + const cell = document.getElementById(`row_${r}-column_${c}`); const number = board[r][c]; updateCell(cell, number); @@ -262,7 +264,7 @@ const slideUp = () => { for (let r = 0; r < rows; r++) { board[r][c] = row[r]; - const cell = document.getElementById(`${r}-${c}`); + const cell = document.getElementById(`row_${r}-column_${c}`); const number = board[r][c]; updateCell(cell, number); @@ -285,7 +287,7 @@ const slideDown = () => { for (let r = 0; r < rows; r++) { board[r][c] = row[r]; - const cell = document.getElementById(`${r}-${c}`); + const cell = document.getElementById(`row_${r}-column_${c}`); const number = board[r][c]; updateCell(cell, number); From df2f72983f003820df7a7c50b694474226e8411d Mon Sep 17 00:00:00 2001 From: Maksym Bevskyi Date: Tue, 24 Oct 2023 18:28:56 +0200 Subject: [PATCH 3/6] fix reset button --- src/scripts/main.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/scripts/main.js b/src/scripts/main.js index 5042af0fe..da8e2e6b7 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -30,8 +30,8 @@ button.addEventListener('click', () => { } else { messageWin.classList.add('hidden'); won = false; + resetFields(); setGame(); - clearBoard(); } }); @@ -92,6 +92,14 @@ const loseGame = () => { return true; }; +const resetFields = () => { + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns; c++) { + board[r][c] = 0; + } + } +}; + const clearBoard = () => { for (let r = 0; r < rows; r++) { for (let c = 0; c < columns; c++) { From f099532157bab3ff0570990e66292a41a7d7d501 Mon Sep 17 00:00:00 2001 From: Maksym Bevskyi Date: Tue, 24 Oct 2023 20:47:20 +0200 Subject: [PATCH 4/6] Add task solution --- src/scripts/main.js | 111 +++++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/src/scripts/main.js b/src/scripts/main.js index da8e2e6b7..72edbd0a4 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1,5 +1,7 @@ 'use strict'; +const MAGIC_NUMBER = 2048; + const messageStart = document.querySelector('.message-start'); const messageLose = document.querySelector('.message-lose'); const messageWin = document.querySelector('.message-win'); @@ -19,21 +21,7 @@ let won = false; const initialBoard = board.map(row => [...row]); let isInitialSetup = true; -button.addEventListener('click', () => { - if (isInitialSetup) { - messageStart.classList.add('hidden'); - button.innerText = 'Restart'; - button.classList.replace('start', 'restart'); - - setGame(); - isInitialSetup = false; - } else { - messageWin.classList.add('hidden'); - won = false; - resetFields(); - setGame(); - } -}); +button.addEventListener('click', restartGame); const table = document.querySelector('.game-field'); @@ -57,15 +45,7 @@ const setGame = () => { }; const hasEmptyCell = () => { - for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { - if (board[r][c] === 0) { - return true; - } - } - } - - return false; + return board.some(row => row.some(cell => cell === 0)); }; const loseGame = () => { @@ -92,19 +72,13 @@ const loseGame = () => { return true; }; -const resetFields = () => { - for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { - board[r][c] = 0; - } - } -}; - const clearBoard = () => { for (let r = 0; r < rows; r++) { for (let c = 0; c < columns; c++) { const cell = document.getElementById(`row_${r}-column_${c}`); + board[r][c] = 0; + cell.innerText = ''; cell.classList.value = ''; cell.classList.add('field-cell'); @@ -127,7 +101,7 @@ const setCell = () => { const column = Math.floor(Math.random() * columns); if (board[row][column] === 0) { - board[row][column] = 2; + board[row][column] = number; const cell = document.getElementById(`row_${row}-column_${column}`); @@ -144,7 +118,7 @@ const setCell = () => { messageLose.classList.add('hidden'); clearBoard(); - setGame(); + restartGame(); }); } }; @@ -164,7 +138,7 @@ const updateCell = (cell, number) => { } } - if (number === 2048) { + if (number === MAGIC_NUMBER) { messageWin.classList.remove('hidden'); won = true; } @@ -221,12 +195,42 @@ const slide = (row) => { return initialRow; }; +const slideHorizontal = (row, direction) => { + let newRow = [...row]; + + if (direction === 'right') { + newRow.reverse(); + } + + newRow = filterZero(newRow); + + for (let i = 0; i < newRow.length - 1; i++) { + if (newRow[i] === newRow[i + 1]) { + newRow[i] *= 2; + newRow[i + 1] = 0; + scoreCount += newRow[i]; + } + } + + newRow = filterZero(newRow); + + while (newRow.length < columns) { + newRow.push(0); + } + + if (direction === 'right') { + newRow.reverse(); + } + + return newRow; +}; + const slideLeft = () => { for (let r = 0; r < rows; r++) { - let row = board[r]; + const row = board[r]; + const newRow = slideHorizontal(row, 'left'); - row = slide(row); - board[r] = row; + board[r] = newRow; for (let c = 0; c < columns; c++) { const cell = document.getElementById(`row_${r}-column_${c}`); @@ -243,12 +247,10 @@ const slideLeft = () => { const slideRight = () => { for (let r = 0; r < rows; r++) { - let row = board[r]; + const row = board[r]; + const newRow = slideHorizontal(row, 'right'); - row.reverse(); - row = slide(row); - row.reverse(); - board[r] = row; + board[r] = newRow; for (let c = 0; c < columns; c++) { const cell = document.getElementById(`row_${r}-column_${c}`); @@ -318,3 +320,26 @@ const hasChanges = (arrayA, arrayB) => { return false; }; + +button.removeEventListener('click', restartGame); + +function restartGame() { + messageWin.classList.add('hidden'); + won = false; + clearBoard(); + setGame(); +} + +if (isInitialSetup) { + messageStart.classList.add('hidden'); + button.innerText = 'Restart'; + button.classList.replace('start', 'restart'); + + setGame(); + isInitialSetup = false; +} else { + messageWin.classList.add('hidden'); + won = false; + clearBoard(); + setGame(); +} From 443b0cbc213099e00163e7ebf6ebee2747ce8f48 Mon Sep 17 00:00:00 2001 From: Maksym Bevskyi Date: Wed, 25 Oct 2023 13:35:41 +0200 Subject: [PATCH 5/6] created a better variables --- src/scripts/main.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/scripts/main.js b/src/scripts/main.js index 72edbd0a4..7cd313f0e 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1,6 +1,12 @@ 'use strict'; -const MAGIC_NUMBER = 2048; +const WINNER_SCORE = 2048; +const ARROW = { + LEFT: 'ArrowLeft', + RIGHT: 'ArrowRight', + UP: 'ArrowUp', + DOWN: 'ArrowDown', +}; const messageStart = document.querySelector('.message-start'); const messageLose = document.querySelector('.message-lose'); @@ -138,7 +144,7 @@ const updateCell = (cell, number) => { } } - if (number === MAGIC_NUMBER) { + if (number === WINNER_SCORE) { messageWin.classList.remove('hidden'); won = true; } @@ -152,16 +158,16 @@ document.addEventListener('keyup', arrow => { } switch (arrow.key) { - case 'ArrowLeft': + case ARROW.LEFT: slideLeft(); break; - case 'ArrowRight': + case ARROW.RIGHT: slideRight(); break; - case 'ArrowUp': + case ARROW.UP: slideUp(); break; - case 'ArrowDown': + case ARROW.DOWN: slideDown(); break; default: From fb6bc8639baf8afbf3f1f77997a29c559e717580 Mon Sep 17 00:00:00 2001 From: Maksym Bevskyi Date: Wed, 25 Oct 2023 14:07:39 +0200 Subject: [PATCH 6/6] fix mistake when page get start --- src/scripts/main.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/scripts/main.js b/src/scripts/main.js index 7cd313f0e..ba74089e2 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -336,16 +336,19 @@ function restartGame() { setGame(); } -if (isInitialSetup) { - messageStart.classList.add('hidden'); - button.innerText = 'Restart'; - button.classList.replace('start', 'restart'); - - setGame(); - isInitialSetup = false; -} else { - messageWin.classList.add('hidden'); - won = false; - clearBoard(); - setGame(); +button.addEventListener('click', () => { + if (isInitialSetup) { + messageStart.classList.add('hidden'); + button.innerText = 'Restart'; + button.classList.replace('start', 'restart'); + + setGame(); + isInitialSetup = false; + } else { + messageWin.classList.add('hidden'); + won = false; + clearBoard(); + setGame(); + } } +);