From dbea445f1d7c9f094600153bd582a0b81f43ec3f Mon Sep 17 00:00:00 2001 From: RomanenkoStud Date: Sun, 30 Jul 2023 14:06:04 +0300 Subject: [PATCH 1/5] add task solution --- src/scripts/Button.js | 28 +++++++ src/scripts/Cell.js | 28 +++++++ src/scripts/Controls.js | 39 +++++++++ src/scripts/Field.js | 155 +++++++++++++++++++++++++++++++++++ src/scripts/Game.js | 113 +++++++++++++++++++++++++ src/scripts/Message.js | 21 +++++ src/scripts/Score.js | 20 +++++ src/scripts/SwipeControls.js | 47 +++++++++++ src/scripts/main.js | 6 +- 9 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 src/scripts/Button.js create mode 100644 src/scripts/Cell.js create mode 100644 src/scripts/Controls.js create mode 100644 src/scripts/Field.js create mode 100644 src/scripts/Game.js create mode 100644 src/scripts/Message.js create mode 100644 src/scripts/Score.js create mode 100644 src/scripts/SwipeControls.js diff --git a/src/scripts/Button.js b/src/scripts/Button.js new file mode 100644 index 000000000..dcf7ffedc --- /dev/null +++ b/src/scripts/Button.js @@ -0,0 +1,28 @@ +'use strict'; + +class Button { + constructor(element, startFunc, restartFunc) { + const START_TEXT = 'Start'; + const START_CLASS = 'start'; + const RESTART_TEXT = 'Restart'; + const RESTART_CLASS = 'restart'; + + this.element = element; + + this.element.addEventListener('click', () => { + if (this.element.classList.contains(START_CLASS)) { + startFunc(); + this.element.classList.remove(START_CLASS); + this.element.classList.add(RESTART_CLASS); + this.element.textContent = RESTART_TEXT; + } else if (this.element.classList.contains(RESTART_CLASS)) { + restartFunc(); + this.element.classList.remove(RESTART_CLASS); + this.element.classList.add(START_CLASS); + this.element.textContent = START_TEXT; + } + }); + } +} + +module.exports = Button; diff --git a/src/scripts/Cell.js b/src/scripts/Cell.js new file mode 100644 index 000000000..15cd43855 --- /dev/null +++ b/src/scripts/Cell.js @@ -0,0 +1,28 @@ +'use strict'; + +class Cell { + constructor(element) { + this.isEmpty = true; + this.value = 0; + this.element = element; + } + + setValue(value) { + if (!this.isEmpty) { + this.element.classList.remove('field-cell--' + this.value); + } + this.isEmpty = false; + this.element.classList.add('field-cell--' + value); + this.value = value; + this.element.textContent = value; + } + + clear() { + this.isEmpty = true; + this.element.classList.remove('field-cell--' + this.value); + this.value = 0; + this.element.textContent = ''; + } +} + +module.exports = Cell; diff --git a/src/scripts/Controls.js b/src/scripts/Controls.js new file mode 100644 index 000000000..0692d67d1 --- /dev/null +++ b/src/scripts/Controls.js @@ -0,0 +1,39 @@ +'use strict'; + +class Controls { + constructor(onLeft, onRight, onUp, onDown, onAction) { + this.enabled = false; + this.onLeft = onLeft; + this.onRight = onRight; + this.onUp = onUp; + this.onDown = onDown; + this.onAction = onAction; + + document.addEventListener('keydown', (keyboardEvent) => { + if (!this.enabled) { + return; + } + + switch (keyboardEvent.key) { + case 'ArrowLeft': + this.onLeft(); + break; + case 'ArrowRight': + this.onRight(); + break; + case 'ArrowUp': + this.onUp(); + break; + case 'ArrowDown': + this.onDown(); + break; + default: + break; + } + + this.onAction(); + }); + } +} + +module.exports = Controls; diff --git a/src/scripts/Field.js b/src/scripts/Field.js new file mode 100644 index 000000000..1f20fd003 --- /dev/null +++ b/src/scripts/Field.js @@ -0,0 +1,155 @@ +'use strict'; + +const Cell = require('./Cell'); + +class Field { + constructor(element) { + this.cells = []; + + const rows = element.querySelectorAll('.field-row'); + + for (let i = 0; i < rows.length; i++) { + const row = rows[i].querySelectorAll('.field-cell'); + + this.cells.push([...row].map((cell) => new Cell(cell))); + } + } + + getMaxValue() { + let maxValue = 0; + + for (let row = 0; row < this.cells.length; row++) { + for (let column = 0; column < this.cells[row].length; column++) { + const cellValue = this.cells[row][column].value; + + if (cellValue > maxValue) { + maxValue = cellValue; + } + } + } + + return maxValue; + } + + hasAvailableMoves() { + for (let row = 0; row < this.cells.length; row++) { + for (let column = 0; column < this.cells[row].length; column++) { + const cell = this.cells[row][column]; + + if (cell.isEmpty) { + return true; + } + + if ( + (row > 0 && this.cells[row - 1][column].value === cell.value) + || (column > 0 && this.cells[row][column - 1].value === cell.value) + ) { + return true; + } + } + } + + return false; + } + + mergeCells(cells) { + let score = 0; + + for (let i = 0; i < cells.length; i++) { + for (let j = i + 1; j < cells.length; j++) { + if (!cells[i].isEmpty && cells[i].value === cells[j].value) { + score += cells[i].value * 2; + cells[i].setValue(cells[i].value * 2); + cells[j].clear(); + } else if (cells[i].isEmpty && !cells[j].isEmpty) { + cells[i].setValue(cells[j].value); + cells[j].clear(); + i++; + } + } + } + + return score; + } + + shiftLeft() { + let totalScore = 0; + + for (let row = 0; row < this.cells.length; row++) { + totalScore += this.mergeCells(this.cells[row]); + } + + return totalScore; + } + + shiftRight() { + let totalScore = 0; + + for (let row = 0; row < this.cells.length; row++) { + const reversedRow = this.cells[row].slice().reverse(); + + totalScore += this.mergeCells(reversedRow); + } + + return totalScore; + } + + shiftUp() { + let totalScore = 0; + + for (let column = 0; column < this.cells[0].length; column++) { + const columnCells = this.cells.map((row) => row[column]); + + totalScore += this.mergeCells(columnCells); + } + + return totalScore; + } + + shiftDown() { + let totalScore = 0; + + for (let column = 0; column < this.cells[0].length; column++) { + const columnCells = this.cells.map((row) => row[column]).reverse(); + + totalScore += this.mergeCells(columnCells); + } + + return totalScore; + } + + addTile(value) { + const emptyCells = []; + + for (let row = 0; row < this.cells.length; row++) { + for (let column = 0; column < this.cells[row].length; column++) { + if (this.cells[row][column].isEmpty) { + emptyCells.push({ + row, column, + }); + } + } + } + + if (emptyCells.length === 0) { + return false; + } + + const randomIndex = Math.floor(Math.random() * emptyCells.length); + const randomCell = emptyCells[randomIndex]; + + this.cells[randomCell.row][randomCell.column].setValue(value); + + return true; + } + + reset() { + for (let column = 0; column < this.cells.length; column++) { + for (let row = 0; row < this.cells.length; row++) { + this.cells[row][column].clear(); + } + } + } +} + +module.exports = Field; diff --git a/src/scripts/Game.js b/src/scripts/Game.js new file mode 100644 index 000000000..ab5109f4f --- /dev/null +++ b/src/scripts/Game.js @@ -0,0 +1,113 @@ +'use strict'; + +const Field = require('./Field'); +const Button = require('./Button'); +const Message = require('./Message'); +const Score = require('./Score'); +const SwipeControls = require('./SwipeControls'); + +class Game { + constructor() { + this.START_VALUE = 2; + this.END_VALUE = 2048; + this.DIVIDER = 2; + + this.MESSAGES = { + WIN: 'win', + LOSE: 'lose', + START: 'start', + }; + + this.score = new Score(document.querySelector('.game-score')); + this.message = new Message(document.querySelector('.message-container')); + this.field = new Field(document.querySelector('.game-field')); + + const onStart = () => { + this.field.addTile(this.START_VALUE); + this.field.addTile(this.START_VALUE); + this.message.setMessage(); + this.controls.enabled = true; + }; + + const onRestart = () => { + this.score.reset(); + this.message.setMessage(this.MESSAGES.START); + this.field.reset(); + this.controls.enabled = false; + }; + + const getRandomValue = (min, max) => { + if (min > max) { + return 2 ** min; + } + + const randomExponent = Math.floor( + Math.random() * (Math.log2(max) - Math.log2(min) + 1) + Math.log2(min) + ); + + return 2 ** randomExponent; + }; + + const onLeft = () => { + const points = this.field.shiftLeft(); + + this.score.addPoints(points); + }; + + const onRight = () => { + const points = this.field.shiftRight(); + + this.score.addPoints(points); + }; + + const onUp = () => { + const points = this.field.shiftUp(); + + this.score.addPoints(points); + }; + + const onDown = () => { + const points = this.field.shiftDown(); + + this.score.addPoints(points); + }; + + const onAction = () => { + const maxValue = this.field.getMaxValue(); + + if (maxValue === this.END_VALUE) { + this.message.setMessage(this.MESSAGES.WIN); + this.controls.enabled = false; + + return; + } + + if (!this.field.hasAvailableMoves()) { + this.message.setMessage(this.MESSAGES.LOSE); + this.controls.enabled = false; + + return; + } + + const newValue = getRandomValue( + this.START_VALUE, maxValue / this.DIVIDER + ); + + this.field.addTile(newValue); + }; + + this.button = new Button( + document.querySelector('.controls .button'), + onStart, onRestart + ); + + this.controls = new SwipeControls(onLeft, onRight, onUp, onDown, onAction); + this.message.setMessage(this.MESSAGES.START); + } + + load() { + return this; + } +} + +module.exports = Game; diff --git a/src/scripts/Message.js b/src/scripts/Message.js new file mode 100644 index 000000000..59869999d --- /dev/null +++ b/src/scripts/Message.js @@ -0,0 +1,21 @@ +'use strict'; + +class Message { + constructor(element) { + this.element = element; + } + + setMessage(messageType) { + const messages = this.element.querySelectorAll('.message'); + + messages.forEach((message) => { + if (message.classList.contains(`message-${messageType}`)) { + message.classList.remove('hidden'); + } else { + message.classList.add('hidden'); + } + }); + } +} + +module.exports = Message; diff --git a/src/scripts/Score.js b/src/scripts/Score.js new file mode 100644 index 000000000..1b30b8eab --- /dev/null +++ b/src/scripts/Score.js @@ -0,0 +1,20 @@ +'use strict'; + +class Score { + constructor(element) { + this.element = element; + this.value = 0; + } + + addPoints(value) { + this.value += value; + this.element.textContent = this.value; + } + + reset() { + this.value = 0; + this.element.textContent = this.value; + } +} + +module.exports = Score; diff --git a/src/scripts/SwipeControls.js b/src/scripts/SwipeControls.js new file mode 100644 index 000000000..f8bcf0d9f --- /dev/null +++ b/src/scripts/SwipeControls.js @@ -0,0 +1,47 @@ +'use strict'; + +const Controls = require('./Controls'); + +class SwipeControls extends Controls { + constructor(onLeft, onRight, onUp, onDown, onAction) { + super(onLeft, onRight, onUp, onDown, onAction); + + let touchStartX, touchStartY; + + document.addEventListener('touchstart', (e) => { + touchStartX = e.touches[0].clientX; + touchStartY = e.touches[0].clientY; + }); + + document.addEventListener('touchend', (e) => { + const touchEndX = e.changedTouches[0].clientX; + const touchEndY = e.changedTouches[0].clientY; + const deltaX = touchEndX - touchStartX; + const deltaY = touchEndY - touchStartY; + + if (Math.abs(deltaX) > Math.abs(deltaY)) { + // Minimum threshold for a valid horizontal swipe + if (Math.abs(deltaX) > 50) { + if (deltaX > 0) { + this.onRight(); + } else { + this.onLeft(); + } + } + } else { + // Minimum threshold for a valid vertical swipe + if (Math.abs(deltaY) > 50) { + if (deltaY > 0) { + this.onDown(); + } else { + this.onUp(); + } + } + } + + this.onAction(); + }); + } +} + +module.exports = SwipeControls; diff --git a/src/scripts/main.js b/src/scripts/main.js index c6e3f8784..f719f2173 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1,3 +1,7 @@ 'use strict'; -// write your code here +const Game = require('./Game'); + +const game = new Game(); + +game.load(); From 08c453e7cc0bf48da7f16a5c47af528c1121849a Mon Sep 17 00:00:00 2001 From: RomanenkoStud Date: Mon, 31 Jul 2023 11:48:12 +0300 Subject: [PATCH 2/5] fix controls --- src/scripts/Controls.js | 19 ++++++++++++++----- src/scripts/Field.js | 1 - src/scripts/Game.js | 3 +-- src/scripts/SwipeControls.js | 4 ++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/scripts/Controls.js b/src/scripts/Controls.js index 0692d67d1..6694d88e0 100644 --- a/src/scripts/Controls.js +++ b/src/scripts/Controls.js @@ -9,29 +9,38 @@ class Controls { this.onDown = onDown; this.onAction = onAction; + this.KEYS = { + LEFT: 'ArrowLeft', + RIGHT: 'ArrowRight', + UP: 'ArrowUp', + DOWN: 'ArrowDown', + }; + document.addEventListener('keydown', (keyboardEvent) => { if (!this.enabled) { return; } switch (keyboardEvent.key) { - case 'ArrowLeft': + case this.KEYS.LEFT: this.onLeft(); break; - case 'ArrowRight': + case this.KEYS.RIGHT: this.onRight(); break; - case 'ArrowUp': + case this.KEYS.UP: this.onUp(); break; - case 'ArrowDown': + case this.KEYS.DOWN: this.onDown(); break; default: break; } - this.onAction(); + if (Object.values(this.KEYS).includes(keyboardEvent.key)) { + this.onAction(); + } }); } } diff --git a/src/scripts/Field.js b/src/scripts/Field.js index 1f20fd003..507066517 100644 --- a/src/scripts/Field.js +++ b/src/scripts/Field.js @@ -64,7 +64,6 @@ class Field { } else if (cells[i].isEmpty && !cells[j].isEmpty) { cells[i].setValue(cells[j].value); cells[j].clear(); - i++; } } } diff --git a/src/scripts/Game.js b/src/scripts/Game.js index ab5109f4f..76afecf86 100644 --- a/src/scripts/Game.js +++ b/src/scripts/Game.js @@ -10,7 +10,6 @@ class Game { constructor() { this.START_VALUE = 2; this.END_VALUE = 2048; - this.DIVIDER = 2; this.MESSAGES = { WIN: 'win', @@ -90,7 +89,7 @@ class Game { } const newValue = getRandomValue( - this.START_VALUE, maxValue / this.DIVIDER + this.START_VALUE, maxValue ); this.field.addTile(newValue); diff --git a/src/scripts/SwipeControls.js b/src/scripts/SwipeControls.js index f8bcf0d9f..055b39820 100644 --- a/src/scripts/SwipeControls.js +++ b/src/scripts/SwipeControls.js @@ -27,6 +27,7 @@ class SwipeControls extends Controls { } else { this.onLeft(); } + this.onAction(); } } else { // Minimum threshold for a valid vertical swipe @@ -36,10 +37,9 @@ class SwipeControls extends Controls { } else { this.onUp(); } + this.onAction(); } } - - this.onAction(); }); } } From 79c71fe765b246d2516a321e58a97808ab38b10b Mon Sep 17 00:00:00 2001 From: RomanenkoStud Date: Mon, 31 Jul 2023 19:21:35 +0300 Subject: [PATCH 3/5] game optimization and bug fix --- src/scripts/Field.js | 158 +++++++++++++++++++++++++------------------ src/scripts/Game.js | 4 -- src/scripts/main.js | 6 +- 3 files changed, 98 insertions(+), 70 deletions(-) diff --git a/src/scripts/Field.js b/src/scripts/Field.js index 507066517..58aba4186 100644 --- a/src/scripts/Field.js +++ b/src/scripts/Field.js @@ -8,65 +8,82 @@ class Field { const rows = element.querySelectorAll('.field-row'); - for (let i = 0; i < rows.length; i++) { - const row = rows[i].querySelectorAll('.field-cell'); + rows.forEach((row) => { + const cellElements = row.querySelectorAll('.field-cell'); + const rowCells = [...cellElements].map((cell) => new Cell(cell)); - this.cells.push([...row].map((cell) => new Cell(cell))); - } + this.cells.push(rowCells); + }); } getMaxValue() { - let maxValue = 0; + return this.cells.reduce((maxValue, row) => { + const rowMaxValue = row.reduce((rowMax, cell) => { + return Math.max(rowMax, cell.value); + }, 0); - for (let row = 0; row < this.cells.length; row++) { - for (let column = 0; column < this.cells[row].length; column++) { - const cellValue = this.cells[row][column].value; + return Math.max(maxValue, rowMaxValue); + }, 0); + } - if (cellValue > maxValue) { - maxValue = cellValue; + hasAvailableMoves() { + let hasEmptyCell = false; + + this.cells.forEach((row, rowIndex) => { + row.forEach((cell, columnIndex) => { + const isEmpty = cell.isEmpty; + const isValueAboveSame = rowIndex > 0 + && this.cells[rowIndex - 1][columnIndex].value === cell.value; + const isValueToLeftSame = columnIndex > 0 + && this.cells[rowIndex][columnIndex - 1].value === cell.value; + + if (isEmpty || isValueAboveSame || isValueToLeftSame) { + hasEmptyCell = true; } - } - } + }); + }); - return maxValue; + return hasEmptyCell; } - hasAvailableMoves() { - for (let row = 0; row < this.cells.length; row++) { - for (let column = 0; column < this.cells[row].length; column++) { - const cell = this.cells[row][column]; + mergeCells(cells) { + let score = 0; + let currentIndex = 0; - if (cell.isEmpty) { - return true; - } + cells.forEach((cell, i) => { + if (!cell.isEmpty) { + cells[currentIndex].setValue(cell.value); - if ( - (row > 0 && this.cells[row - 1][column].value === cell.value) - || (column > 0 && this.cells[row][column - 1].value === cell.value) - ) { - return true; + if (currentIndex !== i) { + cell.clear(); } + currentIndex++; + } + }); + + for (let i = 0; i < cells.length - 1; i++) { + if (!cells[i].isEmpty && cells[i].value === cells[i + 1].value) { + const mergedValue = cells[i].value * 2; + + cells[i].setValue(mergedValue); + cells[i + 1].clear(); + score += mergedValue; + i++; } } - return false; - } + currentIndex = 0; - mergeCells(cells) { - let score = 0; + cells.forEach((cell, i) => { + if (!cell.isEmpty) { + cells[currentIndex].setValue(cell.value); - for (let i = 0; i < cells.length; i++) { - for (let j = i + 1; j < cells.length; j++) { - if (!cells[i].isEmpty && cells[i].value === cells[j].value) { - score += cells[i].value * 2; - cells[i].setValue(cells[i].value * 2); - cells[j].clear(); - } else if (cells[i].isEmpty && !cells[j].isEmpty) { - cells[i].setValue(cells[j].value); - cells[j].clear(); + if (currentIndex !== i) { + cell.clear(); } + currentIndex++; } - } + }); return score; } @@ -74,9 +91,9 @@ class Field { shiftLeft() { let totalScore = 0; - for (let row = 0; row < this.cells.length; row++) { - totalScore += this.mergeCells(this.cells[row]); - } + this.cells.forEach((row) => { + totalScore += this.mergeCells(row); + }); return totalScore; } @@ -84,11 +101,11 @@ class Field { shiftRight() { let totalScore = 0; - for (let row = 0; row < this.cells.length; row++) { - const reversedRow = this.cells[row].slice().reverse(); + this.cells.forEach((row) => { + const reversedRow = row.slice().reverse(); totalScore += this.mergeCells(reversedRow); - } + }); return totalScore; } @@ -96,11 +113,11 @@ class Field { shiftUp() { let totalScore = 0; - for (let column = 0; column < this.cells[0].length; column++) { - const columnCells = this.cells.map((row) => row[column]); + const transposedCells = this.transposeCells(); - totalScore += this.mergeCells(columnCells); - } + transposedCells.forEach((row) => { + totalScore += this.mergeCells(row); + }); return totalScore; } @@ -108,27 +125,40 @@ class Field { shiftDown() { let totalScore = 0; - for (let column = 0; column < this.cells[0].length; column++) { - const columnCells = this.cells.map((row) => row[column]).reverse(); + const transposedCells = this.transposeCells(); - totalScore += this.mergeCells(columnCells); - } + transposedCells.forEach((row) => { + const reversedRow = row.slice().reverse(); + + totalScore += this.mergeCells(reversedRow); + }); return totalScore; } + transposeCells() { + const transposedCells = []; + + for (let column = 0; column < this.cells[0].length; column++) { + transposedCells.push(this.cells.map((row) => row[column])); + } + + return transposedCells; + } + addTile(value) { const emptyCells = []; - for (let row = 0; row < this.cells.length; row++) { - for (let column = 0; column < this.cells[row].length; column++) { - if (this.cells[row][column].isEmpty) { + this.cells.forEach((row, rowIndex) => { + row.forEach((cell, columnIndex) => { + if (cell.isEmpty) { emptyCells.push({ - row, column, + row: rowIndex, + column: columnIndex, }); } - } - } + }); + }); if (emptyCells.length === 0) { return false; @@ -143,11 +173,11 @@ class Field { } reset() { - for (let column = 0; column < this.cells.length; column++) { - for (let row = 0; row < this.cells.length; row++) { - this.cells[row][column].clear(); - } - } + this.cells.forEach((row) => { + row.forEach((cell) => { + cell.clear(); + }); + }); } } diff --git a/src/scripts/Game.js b/src/scripts/Game.js index 76afecf86..5862a4bbd 100644 --- a/src/scripts/Game.js +++ b/src/scripts/Game.js @@ -103,10 +103,6 @@ class Game { this.controls = new SwipeControls(onLeft, onRight, onUp, onDown, onAction); this.message.setMessage(this.MESSAGES.START); } - - load() { - return this; - } } module.exports = Game; diff --git a/src/scripts/main.js b/src/scripts/main.js index f719f2173..03a270db2 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -2,6 +2,8 @@ const Game = require('./Game'); -const game = new Game(); +function initializeGame() { + return new Game(); +} -game.load(); +initializeGame(); From 7ab7a4b3360c2042a71c5f638a28edc55de81571 Mon Sep 17 00:00:00 2001 From: RomanenkoStud Date: Mon, 31 Jul 2023 21:06:55 +0300 Subject: [PATCH 4/5] game meta fix --- src/scripts/Game.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/scripts/Game.js b/src/scripts/Game.js index 5862a4bbd..d07c0e651 100644 --- a/src/scripts/Game.js +++ b/src/scripts/Game.js @@ -36,15 +36,7 @@ class Game { }; const getRandomValue = (min, max) => { - if (min > max) { - return 2 ** min; - } - - const randomExponent = Math.floor( - Math.random() * (Math.log2(max) - Math.log2(min) + 1) + Math.log2(min) - ); - - return 2 ** randomExponent; + return Math.floor(Math.random() * (max - min + 1)) + min; }; const onLeft = () => { @@ -88,9 +80,7 @@ class Game { return; } - const newValue = getRandomValue( - this.START_VALUE, maxValue - ); + const newValue = this.START_VALUE * getRandomValue(1, 2); this.field.addTile(newValue); }; From 891fd738e832b610b5916099b93b7a40cbde3a6c Mon Sep 17 00:00:00 2001 From: RomanenkoStud Date: Mon, 31 Jul 2023 21:12:34 +0300 Subject: [PATCH 5/5] game start value fix --- src/scripts/Game.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripts/Game.js b/src/scripts/Game.js index d07c0e651..42acdbb1e 100644 --- a/src/scripts/Game.js +++ b/src/scripts/Game.js @@ -17,13 +17,17 @@ class Game { START: 'start', }; + const getRandomValue = (min, max) => { + return Math.floor(Math.random() * (max - min + 1)) + min; + }; + this.score = new Score(document.querySelector('.game-score')); this.message = new Message(document.querySelector('.message-container')); this.field = new Field(document.querySelector('.game-field')); const onStart = () => { - this.field.addTile(this.START_VALUE); - this.field.addTile(this.START_VALUE); + this.field.addTile(this.START_VALUE * getRandomValue(1, 2)); + this.field.addTile(this.START_VALUE * getRandomValue(1, 2)); this.message.setMessage(); this.controls.enabled = true; }; @@ -35,10 +39,6 @@ class Game { this.controls.enabled = false; }; - const getRandomValue = (min, max) => { - return Math.floor(Math.random() * (max - min + 1)) + min; - }; - const onLeft = () => { const points = this.field.shiftLeft();