diff --git a/.github/workflows/test.yml-template b/.github/workflows/test.yml-template new file mode 100644 index 000000000..44ac4e963 --- /dev/null +++ b/.github/workflows/test.yml-template @@ -0,0 +1,29 @@ +name: Test + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm start & sleep 5 && npm test + - name: Upload tests report(cypress mochaawesome merged HTML report) + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: report + path: reports diff --git a/README.md b/README.md index 5aab92544..0d692a183 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ You can change the HTML/CSS layout if you need it. ## Deploy and Pull Request 1. Replace `` with your Github username in the link - - [DEMO LINK](https://.github.io/js_2048_game/) + - [DEMO LINK](https://IrynaMariiko00.github.io/js_2048_game/) 2. Follow [this instructions](https://mate-academy.github.io/layout_task-guideline/) - Run `npm run test` command to test your code; - Run `npm run test:only -- -n` to run fast test ignoring linter; diff --git a/dist/Untitled.be14dc54.png b/dist/Untitled.be14dc54.png new file mode 100644 index 000000000..b696a183f Binary files /dev/null and b/dist/Untitled.be14dc54.png differ diff --git a/dist/index.0d5498be.js b/dist/index.0d5498be.js new file mode 100644 index 000000000..244b0fcfb --- /dev/null +++ b/dist/index.0d5498be.js @@ -0,0 +1,2 @@ +!function(){var t="idle",e="playing",r="lose",o=new(function(){var o;function a(e,r,o){!function(t,e){if(!(t instanceof e))throw TypeError("Cannot call a class as a function")}(this,a),this.board=e||[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],this.score=0,this.status=t,this.isStarted=!1,this.winCallback=r,this.loseCallback=o}return o=[{key:"moveTile",value:function(t,e){var r=t.getBoundingClientRect(),o=e.getBoundingClientRect(),a=o.left-r.left,n=o.top-r.top;t.style.setProperty("--x-offset","".concat(a,"px")),t.style.setProperty("--y-offset","".concat(n,"px")),t.classList.add("moving")}},{key:"updateBoard",value:function(){for(var t=document.querySelectorAll(".field-cell"),e=0,r=0;r0){var o=t[Math.floor(Math.random()*t.length)],a=o.row,n=o.col;0===this.score&&(this.board[a][n]=2),this.updateBoard()}}},{key:"addRandomCellAfterMoving",value:function(){for(var t=[],e=0;e<4;e++)for(var r=0;r<4;r++)0===this.board[e][r]&&t.push({row:e,col:r});if(t.length>0){var o=t[Math.floor(Math.random()*t.length)],a=o.row,n=o.col;this.board[a][n]=.9>Math.random()?2:4,this.updateBoard()}}},{key:"createColumn",value:function(t){for(var e=[],r=0;r0;a--)r[a]===r[a-1]&&o[a]&&o[a-1]&&(r[a]*=2,r.splice(a-1,1),t=!0,o[a]=!1,this.getScore(t,r[a]));for(;r.length0){var r,o,a;this.score+=e,r=this.score,s.textContent=r,o=this.score,(a=localStorage.getItem("highScore"))&&!(o>a)||(localStorage.setItem("highScore",o),f())}},a.addEventListener("click",function(){a.textContent="Restart",a.classList.remove("start"),a.classList.add("restart"),s.textContent="0",n.forEach(function(t){t.classList.remove("hidden")}),("win"===o.status||o.status===r)&&(c(),u()),o.start(),l.classList.add("hidden"),u(),c(),f()}),document.addEventListener("keydown",function(t){switch(t.key){case"ArrowLeft":o.moveLeft();break;case"ArrowRight":o.moveRight();break;case"ArrowUp":o.moveUp();break;case"ArrowDown":o.moveDown()}})}(); +//# sourceMappingURL=index.0d5498be.js.map diff --git a/dist/index.0d5498be.js.map b/dist/index.0d5498be.js.map new file mode 100644 index 000000000..7a6e02ea3 --- /dev/null +++ b/dist/index.0d5498be.js.map @@ -0,0 +1 @@ +{"mappings":"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","sources":["","src/scripts/main.js","src/modules/Game.class.js","node_modules/@swc/helpers/esm/_class_call_check.js","node_modules/@swc/helpers/esm/_create_class.js"],"sourcesContent":["(function () {\nfunction $8713978b2328d32b$export$71511d61b312f219(instance, Constructor) {\n if (!(instance instanceof Constructor)) throw new TypeError(\"Cannot call a class as a function\");\n}\n\n\nfunction $4fc75ccb937ab1df$var$_defineProperties(target, props) {\n for(var i = 0; i < props.length; i++){\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\nfunction $4fc75ccb937ab1df$export$71511d61b312f219(Constructor, protoProps, staticProps) {\n if (protoProps) $4fc75ccb937ab1df$var$_defineProperties(Constructor.prototype, protoProps);\n if (staticProps) $4fc75ccb937ab1df$var$_defineProperties(Constructor, staticProps);\n return Constructor;\n}\n\n\n\"use strict\";\nvar $3d28d7f1aac198f5$var$IDLE = \"idle\";\nvar $3d28d7f1aac198f5$var$PLAYING = \"playing\";\nvar $3d28d7f1aac198f5$export$eb2b832b8b9fda85 = \"win\";\nvar $3d28d7f1aac198f5$export$43a03cf66b318012 = \"lose\";\nvar $3d28d7f1aac198f5$export$985739bfa5723e08 = /*#__PURE__*/ function() {\n function Game(initialState, winCallback, loseCallback) {\n (0, $8713978b2328d32b$export$71511d61b312f219)(this, Game);\n this.board = initialState || [\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ]\n ];\n this.score = 0;\n this.status = $3d28d7f1aac198f5$var$IDLE;\n this.isStarted = false;\n this.winCallback = winCallback;\n this.loseCallback = loseCallback;\n }\n (0, $4fc75ccb937ab1df$export$71511d61b312f219)(Game, [\n {\n key: \"moveTile\",\n value: function moveTile(fromCell, toCell) {\n var fromCellRect = fromCell.getBoundingClientRect();\n var toCellRect = toCell.getBoundingClientRect();\n var xOffset = toCellRect.left - fromCellRect.left;\n var yOffset = toCellRect.top - fromCellRect.top;\n fromCell.style.setProperty(\"--x-offset\", \"\".concat(xOffset, \"px\"));\n fromCell.style.setProperty(\"--y-offset\", \"\".concat(yOffset, \"px\"));\n fromCell.classList.add(\"moving\");\n }\n },\n {\n key: \"updateBoard\",\n value: function updateBoard() {\n var cells = document.querySelectorAll(\".field-cell\");\n var cellIndex = 0;\n for(var row = 0; row < this.board.length; row++)for(var col = 0; col < this.board[row].length; col++){\n var cell = cells[cellIndex++];\n var value = this.board[row][col];\n var previousValue = cell.textContent;\n cell.classList.remove(\"field-cell--\".concat(previousValue));\n if (value === 0) cell.textContent = \"\";\n else {\n cell.classList.add(\"field-cell--\".concat(value));\n cell.textContent = value;\n }\n }\n }\n },\n {\n key: \"addRandomTile\",\n value: function addRandomTile() {\n var emptyCells = [];\n for(var row = 0; row < 4; row++){\n for(var col = 0; col < 4; col++)if (this.board[row][col] === 0) emptyCells.push({\n row: row,\n col: col\n });\n }\n if (emptyCells.length > 0) {\n var _emptyCells_Math_floor = emptyCells[Math.floor(Math.random() * emptyCells.length)], row1 = _emptyCells_Math_floor.row, col1 = _emptyCells_Math_floor.col;\n if (this.score === 0) this.board[row1][col1] = 2;\n this.updateBoard();\n }\n }\n },\n {\n key: \"addRandomCellAfterMoving\",\n value: function addRandomCellAfterMoving() {\n var emptyCells = [];\n for(var row = 0; row < 4; row++){\n for(var col = 0; col < 4; col++)if (this.board[row][col] === 0) emptyCells.push({\n row: row,\n col: col\n });\n }\n if (emptyCells.length > 0) {\n var _emptyCells_Math_floor = emptyCells[Math.floor(Math.random() * emptyCells.length)], row1 = _emptyCells_Math_floor.row, col1 = _emptyCells_Math_floor.col;\n this.board[row1][col1] = Math.random() < 0.9 ? 2 : 4;\n this.updateBoard();\n }\n }\n },\n {\n key: \"createColumn\",\n value: function createColumn(col) {\n var newColumn = [];\n for(var row = 0; row < this.board.length; row++)if (this.board[row][col] !== 0) newColumn.push(this.board[row][col]);\n return newColumn;\n }\n },\n {\n key: \"updateColumn\",\n value: function updateColumn(col, newColumn) {\n var moved = false;\n for(var row = 0; row < this.board.length; row++)if (this.board[row][col] !== newColumn[row]) {\n this.board[row][col] = newColumn[row];\n moved = true;\n }\n return moved;\n }\n },\n {\n key: \"resetGameStart\",\n value: function resetGameStart() {\n this.score = 0;\n this.status = $3d28d7f1aac198f5$var$PLAYING;\n this.board = [\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ]\n ];\n this.addRandomTile();\n this.addRandomTile();\n }\n },\n {\n key: \"mergeTitles\",\n value: function mergeTitles(newRow, canMerge) {\n var mergedThisMove = [];\n for(var i = 0; i < newRow.length - 1; i++)if (newRow[i] === newRow[i + 1]) {\n newRow[i] *= 2;\n newRow.splice(i + 1, 1);\n canMerge[i] = false;\n mergedThisMove.push(i);\n }\n return mergedThisMove;\n }\n },\n {\n key: \"moveLeft\",\n value: function moveLeft() {\n var _this = this, _loop = function(row) {\n var currentRow = _this.board[row].filter(function(val) {\n return val !== 0;\n });\n var mergedRow = [];\n var skip = false;\n for(var i = 0; i < currentRow.length; i++){\n if (skip) {\n skip = false;\n continue;\n }\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n _this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else mergedRow.push(currentRow[i]);\n }\n while(mergedRow.length < _this.board[row].length)mergedRow.push(0);\n if (!moved) {\n for(var i1 = 0; i1 < _this.board[row].length; i1++)if (_this.board[row][i1] !== mergedRow[i1]) {\n moved = true;\n break;\n }\n }\n _this.board[row] = mergedRow;\n };\n var moved = false;\n for(var row = 0; row < this.board.length; row++)_loop(row);\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n },\n {\n key: \"moveRight\",\n value: function moveRight() {\n var _this = this, _loop = function(row) {\n var currentRow = _this.board[row].filter(function(val) {\n return val !== 0;\n });\n var mergedRow = [];\n var skip = false;\n for(var i = 0; i < currentRow.length; i++){\n if (skip) {\n skip = false;\n continue;\n }\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n _this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else mergedRow.push(currentRow[i]);\n }\n while(mergedRow.length < _this.board[row].length)mergedRow.unshift(0);\n for(var i1 = 0; i1 < _this.board[row].length; i1++)if (_this.board[row][i1] !== mergedRow[i1]) {\n moved = true;\n break;\n }\n _this.board[row] = mergedRow;\n };\n var moved = false;\n for(var row = 0; row < this.board.length; row++)_loop(row);\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n },\n {\n key: \"moveUp\",\n value: function moveUp() {\n var moved = false;\n for(var col = 0; col < this.board.length; col++){\n var newColumn = this.createColumn(col);\n var canMerge = new Array(newColumn.length).fill(true);\n for(var i = 0; i < newColumn.length - 1; i++)if (newColumn[i] === newColumn[i + 1] && canMerge[i] && canMerge[i + 1]) {\n newColumn[i] *= 2;\n newColumn.splice(i + 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n while(newColumn.length < this.board.length)newColumn.push(0);\n moved = this.updateColumn(col, newColumn) || moved;\n }\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n },\n {\n key: \"moveDown\",\n value: function moveDown() {\n var moved = false;\n for(var col = 0; col < this.board.length; col++){\n var newColumn = this.createColumn(col);\n var canMerge = new Array(newColumn.length).fill(true);\n for(var i = newColumn.length - 1; i > 0; i--)if (newColumn[i] === newColumn[i - 1] && canMerge[i] && canMerge[i - 1]) {\n newColumn[i] *= 2;\n newColumn.splice(i - 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n while(newColumn.length < this.board.length)newColumn.unshift(0);\n moved = this.updateColumn(col, newColumn) || moved;\n }\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n },\n {\n /**\n * @returns {number[][]}\n */ key: \"getState\",\n value: function getState() {\n return this.board;\n }\n },\n {\n key: \"getStatus\",\n value: function getStatus() {\n if (this.score === 0) this.status = $3d28d7f1aac198f5$var$IDLE;\n else {\n var hasEmptyCell = false;\n var has2048Cell = false;\n var canMove = false;\n for(var row = 0; row < this.board.length; row++)for(var col = 0; col < this.board[row].length; col++){\n if (this.board[row][col] === 0) hasEmptyCell = true;\n if (this.board[row][col] === 2048) has2048Cell = true;\n if (row < this.board.length - 1 && this.board[row][col] === this.board[row + 1][col]) canMove = true;\n if (col < this.board[row].length - 1 && this.board[row][col] === this.board[row][col + 1]) canMove = true;\n }\n if (has2048Cell) {\n this.status = $3d28d7f1aac198f5$export$eb2b832b8b9fda85;\n this.winCallback();\n } else if (hasEmptyCell || canMove) this.status = $3d28d7f1aac198f5$var$PLAYING;\n else {\n this.status = $3d28d7f1aac198f5$export$43a03cf66b318012;\n this.loseCallback();\n }\n }\n return this.status;\n }\n },\n {\n key: \"start\",\n value: function start() {\n this.resetGameStart();\n }\n },\n {\n key: \"restart\",\n value: function restart() {\n this.resetGameStart();\n }\n }\n ]);\n return Game;\n}();\n\n\n\"use strict\";\nvar $197cd56b15c33885$var$game = new (0, $3d28d7f1aac198f5$export$985739bfa5723e08)(null, $197cd56b15c33885$var$showWinMessage, $197cd56b15c33885$var$showLoseMessage);\nvar $197cd56b15c33885$var$startButton = document.querySelector(\".start\");\nvar $197cd56b15c33885$var$cells = document.querySelectorAll(\".field-cell\");\nvar $197cd56b15c33885$var$score = document.querySelector(\".game-score\");\nvar $197cd56b15c33885$var$recordElement = document.querySelector(\".best__score\");\nvar $197cd56b15c33885$var$messageStart = document.querySelector(\".message-start\");\nvar $197cd56b15c33885$var$messageWin = document.querySelector(\".message-win\");\nvar $197cd56b15c33885$var$messageLose = document.querySelector(\".message-lose\");\nfunction $197cd56b15c33885$var$showWinMessage() {\n $197cd56b15c33885$var$messageWin.classList.remove(\"hidden\");\n}\nfunction $197cd56b15c33885$var$showLoseMessage() {\n $197cd56b15c33885$var$messageLose.classList.remove(\"hidden\");\n}\nfunction $197cd56b15c33885$var$hideMessageStart() {\n $197cd56b15c33885$var$messageStart.classList.add(\"hidden\");\n}\nfunction $197cd56b15c33885$var$hideMessageLose() {\n $197cd56b15c33885$var$messageLose.classList.add(\"hidden\");\n}\nfunction $197cd56b15c33885$var$hideMessageWin() {\n $197cd56b15c33885$var$messageWin.classList.add(\"hidden\");\n}\nfunction $197cd56b15c33885$var$updateScore(value) {\n $197cd56b15c33885$var$score.textContent = value;\n}\nfunction $197cd56b15c33885$var$saveScore(sscore) {\n var currentRecord = localStorage.getItem(\"highScore\");\n if (!currentRecord || sscore > currentRecord) {\n localStorage.setItem(\"highScore\", sscore);\n $197cd56b15c33885$var$displayRecord();\n }\n}\nfunction $197cd56b15c33885$var$displayRecord() {\n var highScore = localStorage.getItem(\"highScore\") || 0;\n $197cd56b15c33885$var$recordElement.textContent = highScore;\n}\n$197cd56b15c33885$var$displayRecord();\n$197cd56b15c33885$var$game.getScore = function(moved, value) {\n if (moved && value > 0) {\n this.score += value;\n $197cd56b15c33885$var$updateScore(this.score);\n $197cd56b15c33885$var$saveScore(this.score);\n }\n};\n$197cd56b15c33885$var$startButton.addEventListener(\"click\", function() {\n $197cd56b15c33885$var$startButton.textContent = \"Restart\";\n $197cd56b15c33885$var$startButton.classList.remove(\"start\");\n $197cd56b15c33885$var$startButton.classList.add(\"restart\");\n $197cd56b15c33885$var$score.textContent = \"0\";\n $197cd56b15c33885$var$cells.forEach(function(cell) {\n cell.classList.remove(\"hidden\");\n });\n if ($197cd56b15c33885$var$game.status === (0, $3d28d7f1aac198f5$export$eb2b832b8b9fda85) || $197cd56b15c33885$var$game.status === (0, $3d28d7f1aac198f5$export$43a03cf66b318012)) {\n $197cd56b15c33885$var$hideMessageWin();\n $197cd56b15c33885$var$hideMessageLose();\n }\n $197cd56b15c33885$var$game.start();\n $197cd56b15c33885$var$hideMessageStart();\n $197cd56b15c33885$var$hideMessageLose();\n $197cd56b15c33885$var$hideMessageWin();\n $197cd56b15c33885$var$displayRecord();\n});\ndocument.addEventListener(\"keydown\", function(e) {\n switch(e.key){\n case \"ArrowLeft\":\n $197cd56b15c33885$var$game.moveLeft();\n break;\n case \"ArrowRight\":\n $197cd56b15c33885$var$game.moveRight();\n break;\n case \"ArrowUp\":\n $197cd56b15c33885$var$game.moveUp();\n break;\n case \"ArrowDown\":\n $197cd56b15c33885$var$game.moveDown();\n break;\n }\n});\n\n})();\n//# sourceMappingURL=index.0d5498be.js.map\n","'use strict';\n\nimport { WIN, LOSE, Game } from '../modules/Game.class';\n\nconst game = new Game(null, showWinMessage, showLoseMessage);\n\nconst startButton = document.querySelector('.start');\nconst cells = document.querySelectorAll('.field-cell');\nconst score = document.querySelector('.game-score');\nconst recordElement = document.querySelector('.best__score');\nconst messageStart = document.querySelector('.message-start');\nconst messageWin = document.querySelector('.message-win');\nconst messageLose = document.querySelector('.message-lose');\n\nfunction showWinMessage() {\n messageWin.classList.remove('hidden');\n}\n\nfunction showLoseMessage() {\n messageLose.classList.remove('hidden');\n}\n\nfunction hideMessageStart() {\n messageStart.classList.add('hidden');\n}\n\nfunction hideMessageLose() {\n messageLose.classList.add('hidden');\n}\n\nfunction hideMessageWin() {\n messageWin.classList.add('hidden');\n}\n\nfunction updateScore(value) {\n score.textContent = value;\n}\n\nfunction saveScore(sscore) {\n const currentRecord = localStorage.getItem('highScore');\n\n if (!currentRecord || sscore > currentRecord) {\n localStorage.setItem('highScore', sscore);\n displayRecord();\n }\n}\n\nfunction displayRecord() {\n const highScore = localStorage.getItem('highScore') || 0;\n\n recordElement.textContent = highScore;\n}\n\ndisplayRecord();\n\ngame.getScore = function (moved, value) {\n if (moved && value > 0) {\n this.score += value;\n updateScore(this.score);\n saveScore(this.score);\n }\n};\n\nstartButton.addEventListener('click', () => {\n startButton.textContent = 'Restart';\n startButton.classList.remove('start');\n startButton.classList.add('restart');\n score.textContent = '0';\n\n cells.forEach((cell) => {\n cell.classList.remove('hidden');\n });\n\n if (game.status === WIN || game.status === LOSE) {\n hideMessageWin();\n hideMessageLose();\n }\n\n game.start();\n hideMessageStart();\n hideMessageLose();\n hideMessageWin();\n displayRecord();\n});\n\ndocument.addEventListener('keydown', (e) => {\n switch (e.key) {\n case 'ArrowLeft':\n game.moveLeft();\n break;\n case 'ArrowRight':\n game.moveRight();\n break;\n case 'ArrowUp':\n game.moveUp();\n break;\n case 'ArrowDown':\n game.moveDown();\n break;\n }\n});\n","'use strict';\n\nconst IDLE = 'idle';\nconst PLAYING = 'playing';\n\nexport const WIN = 'win';\nexport const LOSE = 'lose';\n\nexport class Game {\n constructor(initialState, winCallback, loseCallback) {\n this.board = initialState || [\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n ];\n\n this.score = 0;\n\n this.status = IDLE;\n this.isStarted = false;\n this.winCallback = winCallback;\n this.loseCallback = loseCallback;\n }\n\n moveTile(fromCell, toCell) {\n const fromCellRect = fromCell.getBoundingClientRect();\n const toCellRect = toCell.getBoundingClientRect();\n\n const xOffset = toCellRect.left - fromCellRect.left;\n const yOffset = toCellRect.top - fromCellRect.top;\n\n fromCell.style.setProperty('--x-offset', `${xOffset}px`);\n fromCell.style.setProperty('--y-offset', `${yOffset}px`);\n\n fromCell.classList.add('moving');\n }\n\n updateBoard() {\n const cells = document.querySelectorAll('.field-cell');\n\n let cellIndex = 0;\n\n for (let row = 0; row < this.board.length; row++) {\n for (let col = 0; col < this.board[row].length; col++) {\n const cell = cells[cellIndex++];\n const value = this.board[row][col];\n const previousValue = cell.textContent;\n\n cell.classList.remove(`field-cell--${previousValue}`);\n\n if (value === 0) {\n cell.textContent = '';\n } else {\n cell.classList.add(`field-cell--${value}`);\n cell.textContent = value;\n }\n }\n }\n }\n\n addRandomTile() {\n const emptyCells = [];\n\n for (let row = 0; row < 4; row++) {\n for (let col = 0; col < 4; col++) {\n if (this.board[row][col] === 0) {\n emptyCells.push({ row, col });\n }\n }\n }\n\n if (emptyCells.length > 0) {\n const { row, col } =\n emptyCells[Math.floor(Math.random() * emptyCells.length)];\n\n if (this.score === 0) {\n this.board[row][col] = 2;\n }\n this.updateBoard();\n }\n }\n\n addRandomCellAfterMoving() {\n const emptyCells = [];\n\n for (let row = 0; row < 4; row++) {\n for (let col = 0; col < 4; col++) {\n if (this.board[row][col] === 0) {\n emptyCells.push({ row, col });\n }\n }\n }\n\n if (emptyCells.length > 0) {\n const { row, col } =\n emptyCells[Math.floor(Math.random() * emptyCells.length)];\n\n this.board[row][col] = Math.random() < 0.9 ? 2 : 4;\n this.updateBoard();\n }\n }\n\n createColumn(col) {\n const newColumn = [];\n\n for (let row = 0; row < this.board.length; row++) {\n if (this.board[row][col] !== 0) {\n newColumn.push(this.board[row][col]);\n }\n }\n\n return newColumn;\n }\n\n updateColumn(col, newColumn) {\n let moved = false;\n\n for (let row = 0; row < this.board.length; row++) {\n if (this.board[row][col] !== newColumn[row]) {\n this.board[row][col] = newColumn[row];\n moved = true;\n }\n }\n\n return moved;\n }\n\n resetGameStart() {\n this.score = 0;\n this.status = PLAYING;\n\n this.board = [\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n ];\n\n this.addRandomTile();\n this.addRandomTile();\n }\n\n mergeTitles(newRow, canMerge) {\n const mergedThisMove = [];\n\n for (let i = 0; i < newRow.length - 1; i++) {\n if (newRow[i] === newRow[i + 1]) {\n newRow[i] *= 2;\n newRow.splice(i + 1, 1);\n canMerge[i] = false;\n mergedThisMove.push(i);\n }\n }\n\n return mergedThisMove;\n }\n\n moveLeft() {\n let moved = false;\n\n for (let row = 0; row < this.board.length; row++) {\n const currentRow = this.board[row].filter((val) => val !== 0);\n const mergedRow = [];\n\n let skip = false;\n\n for (let i = 0; i < currentRow.length; i++) {\n if (skip) {\n skip = false;\n continue;\n }\n\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else {\n mergedRow.push(currentRow[i]);\n }\n }\n\n while (mergedRow.length < this.board[row].length) {\n mergedRow.push(0);\n }\n\n if (!moved) {\n for (let i = 0; i < this.board[row].length; i++) {\n if (this.board[row][i] !== mergedRow[i]) {\n moved = true;\n break;\n }\n }\n }\n\n this.board[row] = mergedRow;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n moveRight() {\n let moved = false;\n\n for (let row = 0; row < this.board.length; row++) {\n const currentRow = this.board[row].filter((val) => val !== 0);\n\n const mergedRow = [];\n let skip = false;\n\n for (let i = 0; i < currentRow.length; i++) {\n if (skip) {\n skip = false;\n continue;\n }\n\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else {\n mergedRow.push(currentRow[i]);\n }\n }\n\n while (mergedRow.length < this.board[row].length) {\n mergedRow.unshift(0);\n }\n\n for (let i = 0; i < this.board[row].length; i++) {\n if (this.board[row][i] !== mergedRow[i]) {\n moved = true;\n break;\n }\n }\n\n this.board[row] = mergedRow;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n moveUp() {\n let moved = false;\n\n for (let col = 0; col < this.board.length; col++) {\n const newColumn = this.createColumn(col);\n const canMerge = new Array(newColumn.length).fill(true);\n\n for (let i = 0; i < newColumn.length - 1; i++) {\n if (\n newColumn[i] === newColumn[i + 1] &&\n canMerge[i] &&\n canMerge[i + 1]\n ) {\n newColumn[i] *= 2;\n newColumn.splice(i + 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n }\n\n while (newColumn.length < this.board.length) {\n newColumn.push(0);\n }\n\n moved = this.updateColumn(col, newColumn) || moved;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n moveDown() {\n let moved = false;\n\n for (let col = 0; col < this.board.length; col++) {\n const newColumn = this.createColumn(col);\n const canMerge = new Array(newColumn.length).fill(true);\n\n for (let i = newColumn.length - 1; i > 0; i--) {\n if (\n newColumn[i] === newColumn[i - 1] &&\n canMerge[i] &&\n canMerge[i - 1]\n ) {\n newColumn[i] *= 2;\n newColumn.splice(i - 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n }\n\n while (newColumn.length < this.board.length) {\n newColumn.unshift(0);\n }\n\n moved = this.updateColumn(col, newColumn) || moved;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n /**\n * @returns {number[][]}\n */\n getState() {\n return this.board;\n }\n\n getStatus() {\n if (this.score === 0) {\n this.status = IDLE;\n } else {\n let hasEmptyCell = false;\n let has2048Cell = false;\n let canMove = false;\n\n for (let row = 0; row < this.board.length; row++) {\n for (let col = 0; col < this.board[row].length; col++) {\n if (this.board[row][col] === 0) {\n hasEmptyCell = true;\n }\n\n if (this.board[row][col] === 2048) {\n has2048Cell = true;\n }\n\n if (\n row < this.board.length - 1 &&\n this.board[row][col] === this.board[row + 1][col]\n ) {\n canMove = true;\n }\n\n if (\n col < this.board[row].length - 1 &&\n this.board[row][col] === this.board[row][col + 1]\n ) {\n canMove = true;\n }\n }\n }\n\n if (has2048Cell) {\n this.status = WIN;\n this.winCallback();\n } else if (hasEmptyCell || canMove) {\n this.status = PLAYING;\n } else {\n this.status = LOSE;\n this.loseCallback();\n }\n }\n\n return this.status;\n }\n\n start() {\n this.resetGameStart();\n }\n\n restart() {\n this.resetGameStart();\n }\n}\n","function _class_call_check(instance, Constructor) {\n if (!(instance instanceof Constructor)) throw new TypeError(\"Cannot call a class as a function\");\n}\nexport { _class_call_check as _ };\n","function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n\n if (\"value\" in descriptor) descriptor.writable = true;\n\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\nfunction _create_class(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n\n return Constructor;\n}\nexport { _create_class as _ };\n"],"names":["$3d28d7f1aac198f5$var$IDLE","$3d28d7f1aac198f5$var$PLAYING","$3d28d7f1aac198f5$export$43a03cf66b318012","$197cd56b15c33885$var$game","protoProps","Game","initialState","winCallback","loseCallback","instance","Constructor","TypeError","board","score","status","isStarted","key","value","fromCell","toCell","fromCellRect","getBoundingClientRect","toCellRect","xOffset","left","yOffset","top","style","setProperty","concat","classList","add","cells","document","querySelectorAll","cellIndex","row","length","col","cell","previousValue","textContent","remove","emptyCells","push","_emptyCells_Math_floor","Math","floor","random","row1","col1","updateBoard","newColumn","moved","addRandomTile","newRow","canMerge","mergedThisMove","i","splice","_this","_loop","currentRow","filter","val","mergedRow","skip","getScore","i1","addRandomCellAfterMoving","getStatus","unshift","createColumn","Array","fill","updateColumn","hasEmptyCell","has2048Cell","canMove","resetGameStart","$4fc75ccb937ab1df$var$_defineProperties","target","props","descriptor","enumerable","configurable","writable","Object","defineProperty","prototype","$197cd56b15c33885$var$messageWin","$197cd56b15c33885$var$messageLose","$197cd56b15c33885$var$startButton","querySelector","$197cd56b15c33885$var$cells","$197cd56b15c33885$var$score","$197cd56b15c33885$var$recordElement","$197cd56b15c33885$var$messageStart","$197cd56b15c33885$var$hideMessageLose","$197cd56b15c33885$var$hideMessageWin","$197cd56b15c33885$var$displayRecord","highScore","localStorage","getItem","sscore","currentRecord","setItem","addEventListener","forEach","start","e","moveLeft","moveRight","moveUp","moveDown"],"version":3,"file":"index.0d5498be.js.map"} \ No newline at end of file diff --git a/dist/index.b8123ea8.css b/dist/index.b8123ea8.css new file mode 100644 index 000000000..30dcca84d --- /dev/null +++ b/dist/index.b8123ea8.css @@ -0,0 +1,2 @@ +body{background:#fbf8ef;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;min-height:100vh;margin:0;font-family:sans-serif;font-size:24px;font-weight:900;display:-ms-flexbox;display:flex}.field-cell{color:#776e65;box-sizing:border-box;text-align:center;vertical-align:middle;-webkit-user-select:none;-ms-user-select:none;user-select:none;background:#d6cdc4;border-radius:5px;width:75px;height:75px;transition:transform .2s,background-color .2s;position:relative}.field-cell:empty{background:#d6cdc4}.field-cell--2{background:#eee4da}.field-cell--4{background:#e1d5c7}.field-cell--8{color:#f9f6f2;background:#5cb3bb}.field-cell--16{color:#f9f6f2;background:#469299}.field-cell--32{color:#f9f6f2;background:#349569}.field-cell--64{color:#f9f6f2;background:#30ac64}.field-cell--128{color:#f9f6f2;background:#26b84d}.field-cell--256{color:#fbfbfb;background:#0b7476}.field-cell--512{color:#f9f6f2;background:#5b8fd9}.field-cell--1024{color:#f9f6f2;background:#3b75c6}.field-cell--2048{color:#f9f6f2;background:#3b49c6}.game-field{border-spacing:10px;background:#bbada0;border-radius:5px}.game-header{box-sizing:border-box;-ms-flex-pack:justify;justify-content:space-between;width:100%;margin-bottom:24px;padding:10px;display:-ms-flexbox;display:flex}h1{color:#f9f6f2;box-sizing:border-box;background:#3a6ed6;border-radius:5px;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;width:75px;height:75px;margin:0;font-size:24px;display:-ms-flexbox;display:flex}.best,.info{color:#776e65;box-sizing:border-box;background:#d6cdc4;border-radius:5px;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;width:75px;height:75px;margin:0 8px 0 0;font-size:16px;display:-ms-flexbox;display:flex}.controls{display:-ms-flexbox;display:flex}.button{cursor:pointer;color:#f9f6f2;border:none;border-radius:5px;width:75px;height:75px;font-family:sans-serif;font-size:16px;font-weight:700;transition:background .25s}.start{background:#0aca6d;font-size:20px}.start:hover{background:#10b96a}.restart{background:#eb5b7d}.restart:hover{background:#d45271}.message{box-sizing:border-box;color:#776e65;text-align:center;background:#d6cdc4;border-radius:5px;width:100%;padding:10px;font-size:20px}.hidden{display:none}.container{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;width:350px;display:-ms-flexbox;display:flex}.message-win{color:#f9f6f2;background:#2669b5}.message-lose{color:#f9f6f2;background:#bf687c}.message-container{width:100%;height:150px}.moving{animation:.5s forwards move-tile}@keyframes move-tile{0%{transform:translate(var(--x-offset),var(--y-offset))}to{transform:translate(0)}}@keyframes merge-tile{0%{opacity:1;transform:scale(1);box-shadow:0 0 transparent}50%{opacity:.7;transform:scale(1.2);box-shadow:0 0 10px rgba(0,0,0,.3)}to{opacity:1;transform:scale(1);box-shadow:0 0 transparent}}.field-cell--merged{transition:transform .2s,opacity .4s;animation:.2s merge-tile} +/*# sourceMappingURL=index.b8123ea8.css.map */ diff --git a/dist/index.b8123ea8.css.map b/dist/index.b8123ea8.css.map new file mode 100644 index 000000000..1d32f4f70 --- /dev/null +++ b/dist/index.b8123ea8.css.map @@ -0,0 +1 @@ +{"mappings":"ACAA,8NAYA,mRAcA,qCAIA,kCAIA,kCAIA,gDAKA,iDAKA,iDAKA,iDAKA,kDAKA,kDAKA,kDAKA,mDAKA,mDAKA,qEAMA,mKASA,iPAcA,kTAgBA,2CAIA,2KAaA,yCAIE,gCAKF,4BAGE,kCAKF,2IAWA,qBAIA,iJAOA,8CAKA,+CAKA,2CAKA,yCAIA,wGAKA,oNAkBA","sources":["index.b8123ea8.css","src/styles/main.scss"],"sourcesContent":["body {\n background: #fbf8ef;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n font-family: sans-serif;\n font-size: 24px;\n font-weight: 900;\n display: -ms-flexbox;\n display: flex;\n}\n\n.field-cell {\n color: #776e65;\n box-sizing: border-box;\n text-align: center;\n vertical-align: middle;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n background: #d6cdc4;\n border-radius: 5px;\n width: 75px;\n height: 75px;\n transition: transform .2s, background-color .2s;\n position: relative;\n}\n\n.field-cell:empty {\n background: #d6cdc4;\n}\n\n.field-cell--2 {\n background: #eee4da;\n}\n\n.field-cell--4 {\n background: #e1d5c7;\n}\n\n.field-cell--8 {\n color: #f9f6f2;\n background: #5cb3bb;\n}\n\n.field-cell--16 {\n color: #f9f6f2;\n background: #469299;\n}\n\n.field-cell--32 {\n color: #f9f6f2;\n background: #349569;\n}\n\n.field-cell--64 {\n color: #f9f6f2;\n background: #30ac64;\n}\n\n.field-cell--128 {\n color: #f9f6f2;\n background: #26b84d;\n}\n\n.field-cell--256 {\n color: #fbfbfb;\n background: #0b7476;\n}\n\n.field-cell--512 {\n color: #f9f6f2;\n background: #5b8fd9;\n}\n\n.field-cell--1024 {\n color: #f9f6f2;\n background: #3b75c6;\n}\n\n.field-cell--2048 {\n color: #f9f6f2;\n background: #3b49c6;\n}\n\n.game-field {\n border-spacing: 10px;\n background: #bbada0;\n border-radius: 5px;\n}\n\n.game-header {\n box-sizing: border-box;\n justify-content: space-between;\n width: 100%;\n margin-bottom: 24px;\n padding: 10px;\n display: -ms-flexbox;\n display: flex;\n}\n\nh1 {\n color: #f9f6f2;\n box-sizing: border-box;\n background: #3a6ed6;\n border-radius: 5px;\n justify-content: center;\n align-items: center;\n width: 75px;\n height: 75px;\n margin: 0;\n font-size: 24px;\n display: -ms-flexbox;\n display: flex;\n}\n\n.best, .info {\n color: #776e65;\n box-sizing: border-box;\n background: #d6cdc4;\n border-radius: 5px;\n -ms-flex-direction: column;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n width: 75px;\n height: 75px;\n margin: 0 8px 0 0;\n font-size: 16px;\n display: -ms-flexbox;\n display: flex;\n}\n\n.controls {\n display: -ms-flexbox;\n display: flex;\n}\n\n.button {\n cursor: pointer;\n color: #f9f6f2;\n border: none;\n border-radius: 5px;\n width: 75px;\n height: 75px;\n font-family: sans-serif;\n font-size: 16px;\n font-weight: 700;\n transition: background .25s;\n}\n\n.start {\n background: #0aca6d;\n font-size: 20px;\n}\n\n.start:hover {\n background: #10b96a;\n}\n\n.restart {\n background: #eb5b7d;\n}\n\n.restart:hover {\n background: #d45271;\n}\n\n.message {\n box-sizing: border-box;\n color: #776e65;\n text-align: center;\n background: #d6cdc4;\n border-radius: 5px;\n width: 100%;\n padding: 10px;\n font-size: 20px;\n}\n\n.hidden {\n display: none;\n}\n\n.container {\n -ms-flex-direction: column;\n flex-direction: column;\n align-items: center;\n width: 350px;\n display: -ms-flexbox;\n display: flex;\n}\n\n.message-win {\n color: #f9f6f2;\n background: #2669b5;\n}\n\n.message-lose {\n color: #f9f6f2;\n background: #bf687c;\n}\n\n.message-container {\n width: 100%;\n height: 150px;\n}\n\n.moving {\n animation: .5s forwards move-tile;\n}\n\n@keyframes move-tile {\n from {\n transform: translate(var(--x-offset), var(--y-offset));\n }\n\n to {\n transform: translate(0);\n }\n}\n\n@keyframes merge-tile {\n 0% {\n opacity: 1;\n transform: scale(1);\n box-shadow: 0 0 #0000;\n }\n\n 50% {\n opacity: .7;\n transform: scale(1.2);\n box-shadow: 0 0 10px #0000004d;\n }\n\n 100% {\n opacity: 1;\n transform: scale(1);\n box-shadow: 0 0 #0000;\n }\n}\n\n.field-cell--merged {\n transition: transform .2s, opacity .4s;\n animation: .2s merge-tile;\n}\n/*# sourceMappingURL=index.b8123ea8.css.map */\n","body {\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n background: #fbf8ef;\n font-family: sans-serif;\n font-size: 24px;\n font-weight: 900;\n}\n\n.field-cell {\n background: #d6cdc4;\n width: 75px;\n height: 75px;\n border-radius: 5px;\n color: #776e65;\n box-sizing: border-box;\n text-align: center;\n vertical-align: middle;\n user-select: none;\n position: relative;\n transition: transform 0.2s ease, background-color 0.2s ease;\n}\n\n.field-cell:empty {\n background: #d6cdc4;\n}\n\n.field-cell--2 {\n background: #eee4da;\n}\n\n.field-cell--4 {\n background: #e1d5c7;\n}\n\n.field-cell--8 {\n background: #5cb3bb;\n color: #f9f6f2;\n}\n\n.field-cell--16 {\n background: #469299;\n color: #f9f6f2;\n}\n\n.field-cell--32 {\n background: #349569;\n color: #f9f6f2;\n}\n\n.field-cell--64 {\n background: #30ac64;\n color: #f9f6f2;\n}\n\n.field-cell--128 {\n background: #26b84d;\n color: #f9f6f2;\n}\n\n.field-cell--256 {\n background: #0b7476;\n color: #fbfbfb;\n}\n\n.field-cell--512 {\n background: #5b8fd9;\n color: #f9f6f2;\n}\n\n.field-cell--1024 {\n background: #3b75c6;\n color: #f9f6f2;\n}\n\n.field-cell--2048 {\n background: #3b49c6;\n color: #f9f6f2;\n}\n\n.game-field {\n background: #bbada0;\n border-spacing: 10px;\n border-radius: 5px;\n}\n\n.game-header {\n display: flex;\n width: 100%;\n justify-content: space-between;\n margin-bottom: 24px;\n padding: 10px;\n box-sizing: border-box;\n}\n\nh1 {\n background: #3a6ed6;\n color: #f9f6f2;\n width: 75px;\n height: 75px;\n font-size: 24px;\n border-radius: 5px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n margin: 0;\n}\n\n.best,\n.info {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: #d6cdc4;\n width: 75px;\n height: 75px;\n border-radius: 5px;\n color: #776e65;\n box-sizing: border-box;\n font-size: 16px;\n margin: 0 8px 0 0;\n}\n\n.controls {\n display: flex;\n}\n\n.button {\n border: none;\n border-radius: 5px;\n cursor: pointer;\n color: #f9f6f2;\n font-family: sans-serif;\n font-weight: 700;\n font-size: 16px;\n width: 75px;\n height: 75px;\n transition: 0.25s ease background;\n}\n\n.start {\n background: #0aca6d;\n font-size: 20px;\n\n &:hover {\n background: #10b96a;\n }\n}\n\n.restart {\n background: #eb5b7d;\n\n &:hover {\n background: #d45271;\n }\n}\n\n.message {\n box-sizing: border-box;\n width: 100%;\n background: #d6cdc4;\n color: #776e65;\n padding: 10px;\n text-align: center;\n border-radius: 5px;\n font-size: 20px;\n}\n\n.hidden {\n display: none;\n}\n\n.container {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 350px;\n}\n\n.message-win {\n background: #2669b5;\n color: #f9f6f2;\n}\n\n.message-lose {\n background: #bf687c;\n color: #f9f6f2;\n}\n\n.message-container {\n width: 100%;\n height: 150px;\n}\n\n.moving {\n animation: move-tile 0.5s forwards;\n}\n\n@keyframes move-tile {\n from { transform: translate(var(--x-offset), var(--y-offset)); }\n to { transform: translate(0, 0); }\n}\n\n@keyframes merge-tile {\n 0% {\n transform: scale(1);\n opacity: 1;\n box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n }\n 50% {\n transform: scale(1.2);\n opacity: 0.7;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n }\n}\n\n.field-cell--merged {\n animation: merge-tile 0.2s ease;\n transition: transform 0.2s ease, opacity 0.4s ease;\n}\n"],"names":[],"version":3,"file":"index.b8123ea8.css.map"} \ No newline at end of file diff --git a/dist/index.ef8de8d9.js b/dist/index.ef8de8d9.js new file mode 100644 index 000000000..62b7d33d9 --- /dev/null +++ b/dist/index.ef8de8d9.js @@ -0,0 +1,2 @@ +const t="idle",e="playing",s="lose",o=new class{constructor(e,s,o){this.board=e||[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],this.score=0,this.status=t,this.isStarted=!1,this.winCallback=s,this.loseCallback=o}moveTile(t,e){let s=t.getBoundingClientRect(),o=e.getBoundingClientRect(),r=o.left-s.left,l=o.top-s.top;t.style.setProperty("--x-offset",`${r}px`),t.style.setProperty("--y-offset",`${l}px`),t.classList.add("moving")}updateBoard(){let t=document.querySelectorAll(".field-cell"),e=0;for(let s=0;s0){let{row:e,col:s}=t[Math.floor(Math.random()*t.length)];0===this.score&&(this.board[e][s]=2),this.updateBoard()}}addRandomCellAfterMoving(){let t=[];for(let e=0;e<4;e++)for(let s=0;s<4;s++)0===this.board[e][s]&&t.push({row:e,col:s});if(t.length>0){let{row:e,col:s}=t[Math.floor(Math.random()*t.length)];this.board[e][s]=.9>Math.random()?2:4,this.updateBoard()}}createColumn(t){let e=[];for(let s=0;s0!==t),o=[],r=!1;for(let e=0;e0!==t),o=[],r=!1;for(let e=0;e0;e--)s[e]===s[e-1]&&o[e]&&o[e-1]&&(s[e]*=2,s.splice(e-1,1),t=!0,o[e]=!1,this.getScore(t,s[e]));for(;s.length0){var s;this.score+=e,s=this.score,a.textContent=s,function(t){let e=localStorage.getItem("highScore");(!e||t>e)&&(localStorage.setItem("highScore",t),g())}(this.score)}},r.addEventListener("click",()=>{r.textContent="Restart",r.classList.remove("start"),r.classList.add("restart"),a.textContent="0",l.forEach(t=>{t.classList.remove("hidden")}),("win"===o.status||o.status===s)&&(u(),c()),o.start(),h.classList.add("hidden"),c(),u(),g()}),document.addEventListener("keydown",t=>{switch(t.key){case"ArrowLeft":o.moveLeft();break;case"ArrowRight":o.moveRight();break;case"ArrowUp":o.moveUp();break;case"ArrowDown":o.moveDown()}}); +//# sourceMappingURL=index.ef8de8d9.js.map diff --git a/dist/index.ef8de8d9.js.map b/dist/index.ef8de8d9.js.map new file mode 100644 index 000000000..4a006bc17 --- /dev/null +++ b/dist/index.ef8de8d9.js.map @@ -0,0 +1 @@ +{"mappings":"AEEA,MAAM,EAAO,OACP,EAAU,UAGH,EAAO,ODFd,EAAO,ICIN,MACL,YAAY,CAAY,CAAE,CAAW,CAAE,CAAY,CAAE,CACnD,IAAI,CAAC,KAAK,CAAG,GAAgB,CAC3B,CAAC,EAAG,EAAG,EAAG,EAAE,CACZ,CAAC,EAAG,EAAG,EAAG,EAAE,CACZ,CAAC,EAAG,EAAG,EAAG,EAAE,CACZ,CAAC,EAAG,EAAG,EAAG,EAAE,CACb,CAED,IAAI,CAAC,KAAK,CAAG,EAEb,IAAI,CAAC,MAAM,CAAG,EACd,IAAI,CAAC,SAAS,CAAG,CAAA,EACjB,IAAI,CAAC,WAAW,CAAG,EACnB,IAAI,CAAC,YAAY,CAAG,CACtB,CAEA,SAAS,CAAQ,CAAE,CAAM,CAAE,CACzB,IAAM,EAAe,EAAS,qBAAqB,GAC7C,EAAa,EAAO,qBAAqB,GAEzC,EAAU,EAAW,IAAI,CAAG,EAAa,IAAI,CAC7C,EAAU,EAAW,GAAG,CAAG,EAAa,GAAG,CAEjD,EAAS,KAAK,CAAC,WAAW,CAAC,aAAc,CAAC,EAAE,EAAQ,EAAE,CAAC,EACvD,EAAS,KAAK,CAAC,WAAW,CAAC,aAAc,CAAC,EAAE,EAAQ,EAAE,CAAC,EAEvD,EAAS,SAAS,CAAC,GAAG,CAAC,SACzB,CAEA,aAAc,CACZ,IAAM,EAAQ,SAAS,gBAAgB,CAAC,eAEpC,EAAY,EAEhB,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IACzC,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAE,IAAO,CACrD,IAAM,EAAO,CAAK,CAAC,IAAY,CACzB,EAAQ,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,CAC5B,EAAgB,EAAK,WAAW,CAEtC,EAAK,SAAS,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,EAAc,CAAC,EAEhD,AAAU,IAAV,EACF,EAAK,WAAW,CAAG,IAEnB,EAAK,SAAS,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAM,CAAC,EACzC,EAAK,WAAW,CAAG,EAEvB,CAEJ,CAEA,eAAgB,CACd,IAAM,EAAa,EAAE,CAErB,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,IACzB,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,IACI,IAAzB,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,EACtB,EAAW,IAAI,CAAC,CAAE,IAAA,EAAK,IAAA,CAAI,GAKjC,GAAI,EAAW,MAAM,CAAG,EAAG,CACzB,GAAM,CAAA,IAAE,CAAG,CAAA,IAAE,CAAG,CAAE,CAChB,CAAU,CAAC,KAAK,KAAK,CAAC,KAAK,MAAM,GAAK,EAAW,MAAM,EAAE,AAExC,CAAA,IAAf,IAAI,CAAC,KAAK,EACZ,CAAA,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,CAAG,CAAA,EAEzB,IAAI,CAAC,WAAW,EAClB,CACF,CAEA,0BAA2B,CACzB,IAAM,EAAa,EAAE,CAErB,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,IACzB,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,IACI,IAAzB,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,EACtB,EAAW,IAAI,CAAC,CAAE,IAAA,EAAK,IAAA,CAAI,GAKjC,GAAI,EAAW,MAAM,CAAG,EAAG,CACzB,GAAM,CAAA,IAAE,CAAG,CAAA,IAAE,CAAG,CAAE,CAChB,CAAU,CAAC,KAAK,KAAK,CAAC,KAAK,MAAM,GAAK,EAAW,MAAM,EAAE,AAE3D,CAAA,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,CAAG,AAAgB,GAAhB,KAAK,MAAM,GAAW,EAAI,EACjD,IAAI,CAAC,WAAW,EAClB,CACF,CAEA,aAAa,CAAG,CAAE,CAChB,IAAM,EAAY,EAAE,CAEpB,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IACZ,IAAzB,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,EACtB,EAAU,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,EAIvC,OAAO,CACT,CAEA,aAAa,CAAG,CAAE,CAAS,CAAE,CAC3B,IAAI,EAAQ,CAAA,EAEZ,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IACrC,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,GAAK,CAAS,CAAC,EAAI,GACzC,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,CAAG,CAAS,CAAC,EAAI,CACrC,EAAQ,CAAA,GAIZ,OAAO,CACT,CAEA,gBAAiB,CACf,IAAI,CAAC,KAAK,CAAG,EACb,IAAI,CAAC,MAAM,CAAG,EAEd,IAAI,CAAC,KAAK,CAAG,CACX,CAAC,EAAG,EAAG,EAAG,EAAE,CACZ,CAAC,EAAG,EAAG,EAAG,EAAE,CACZ,CAAC,EAAG,EAAG,EAAG,EAAE,CACZ,CAAC,EAAG,EAAG,EAAG,EAAE,CACb,CAED,IAAI,CAAC,aAAa,GAClB,IAAI,CAAC,aAAa,EACpB,CAEA,YAAY,CAAM,CAAE,CAAQ,CAAE,CAC5B,IAAM,EAAiB,EAAE,CAEzB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,MAAM,CAAG,EAAG,IACjC,CAAM,CAAC,EAAE,GAAK,CAAM,CAAC,EAAI,EAAE,GAC7B,CAAM,CAAC,EAAE,EAAI,EACb,EAAO,MAAM,CAAC,EAAI,EAAG,GACrB,CAAQ,CAAC,EAAE,CAAG,CAAA,EACd,EAAe,IAAI,CAAC,IAIxB,OAAO,CACT,CAEA,UAAW,CACT,IAAI,EAAQ,CAAA,EAEZ,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IAAO,CAChD,IAAM,EAAa,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAC,AAAC,GAAQ,AAAQ,IAAR,GAC7C,EAAY,EAAE,CAEhB,EAAO,CAAA,EAEX,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,MAAM,CAAE,IAAK,CAC1C,GAAI,EAAM,CACR,EAAO,CAAA,EACP,QACF,CAEI,CAAU,CAAC,EAAE,GAAK,CAAU,CAAC,EAAI,EAAE,EACrC,EAAU,IAAI,CAAC,AAAgB,EAAhB,CAAU,CAAC,EAAE,EAC5B,IAAI,CAAC,QAAQ,CAAC,CAAA,EAAM,AAAgB,EAAhB,CAAU,CAAC,EAAE,EACjC,EAAO,CAAA,EACP,EAAQ,CAAA,GAER,EAAU,IAAI,CAAC,CAAU,CAAC,EAAE,CAEhC,CAEA,KAAO,EAAU,MAAM,CAAG,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,EAC9C,EAAU,IAAI,CAAC,GAGjB,GAAI,CAAC,EACH,CAAA,IAAK,IAAI,EAAI,EAAG,EAAI,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAE,IAC1C,GAAI,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAE,GAAK,CAAS,CAAC,EAAE,CAAE,CACvC,EAAQ,CAAA,EACR,KACF,CAAA,CAIJ,IAAI,CAAC,KAAK,CAAC,EAAI,CAAG,CACpB,CAQA,OANI,IACF,IAAI,CAAC,wBAAwB,GAC7B,IAAI,CAAC,WAAW,GAChB,IAAI,CAAC,SAAS,IAGT,CACT,CAEA,WAAY,CACV,IAAI,EAAQ,CAAA,EAEZ,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IAAO,CAChD,IAAM,EAAa,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAC,AAAC,GAAQ,AAAQ,IAAR,GAE7C,EAAY,EAAE,CAChB,EAAO,CAAA,EAEX,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,MAAM,CAAE,IAAK,CAC1C,GAAI,EAAM,CACR,EAAO,CAAA,EACP,QACF,CAEI,CAAU,CAAC,EAAE,GAAK,CAAU,CAAC,EAAI,EAAE,EACrC,EAAU,IAAI,CAAC,AAAgB,EAAhB,CAAU,CAAC,EAAE,EAC5B,IAAI,CAAC,QAAQ,CAAC,CAAA,EAAM,AAAgB,EAAhB,CAAU,CAAC,EAAE,EACjC,EAAO,CAAA,EACP,EAAQ,CAAA,GAER,EAAU,IAAI,CAAC,CAAU,CAAC,EAAE,CAEhC,CAEA,KAAO,EAAU,MAAM,CAAG,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,EAC9C,EAAU,OAAO,CAAC,GAGpB,IAAK,IAAI,EAAI,EAAG,EAAI,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAE,IAC1C,GAAI,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAE,GAAK,CAAS,CAAC,EAAE,CAAE,CACvC,EAAQ,CAAA,EACR,KACF,CAGF,IAAI,CAAC,KAAK,CAAC,EAAI,CAAG,CACpB,CAQA,OANI,IACF,IAAI,CAAC,wBAAwB,GAC7B,IAAI,CAAC,WAAW,GAChB,IAAI,CAAC,SAAS,IAGT,CACT,CAEA,QAAS,CACP,IAAI,EAAQ,CAAA,EAEZ,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IAAO,CAChD,IAAM,EAAY,IAAI,CAAC,YAAY,CAAC,GAC9B,EAAW,AAAI,MAAM,EAAU,MAAM,EAAE,IAAI,CAAC,CAAA,GAElD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,MAAM,CAAG,EAAG,IAEtC,CAAS,CAAC,EAAE,GAAK,CAAS,CAAC,EAAI,EAAE,EACjC,CAAQ,CAAC,EAAE,EACX,CAAQ,CAAC,EAAI,EAAE,GAEf,CAAS,CAAC,EAAE,EAAI,EAChB,EAAU,MAAM,CAAC,EAAI,EAAG,GACxB,EAAQ,CAAA,EACR,CAAQ,CAAC,EAAE,CAAG,CAAA,EACd,IAAI,CAAC,QAAQ,CAAC,EAAO,CAAS,CAAC,EAAE,GAIrC,KAAO,EAAU,MAAM,CAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EACzC,EAAU,IAAI,CAAC,GAGjB,EAAQ,IAAI,CAAC,YAAY,CAAC,EAAK,IAAc,CAC/C,CAQA,OANI,IACF,IAAI,CAAC,wBAAwB,GAC7B,IAAI,CAAC,WAAW,GAChB,IAAI,CAAC,SAAS,IAGT,CACT,CAEA,UAAW,CACT,IAAI,EAAQ,CAAA,EAEZ,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IAAO,CAChD,IAAM,EAAY,IAAI,CAAC,YAAY,CAAC,GAC9B,EAAW,AAAI,MAAM,EAAU,MAAM,EAAE,IAAI,CAAC,CAAA,GAElD,IAAK,IAAI,EAAI,EAAU,MAAM,CAAG,EAAG,EAAI,EAAG,IAEtC,CAAS,CAAC,EAAE,GAAK,CAAS,CAAC,EAAI,EAAE,EACjC,CAAQ,CAAC,EAAE,EACX,CAAQ,CAAC,EAAI,EAAE,GAEf,CAAS,CAAC,EAAE,EAAI,EAChB,EAAU,MAAM,CAAC,EAAI,EAAG,GACxB,EAAQ,CAAA,EACR,CAAQ,CAAC,EAAE,CAAG,CAAA,EACd,IAAI,CAAC,QAAQ,CAAC,EAAO,CAAS,CAAC,EAAE,GAIrC,KAAO,EAAU,MAAM,CAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EACzC,EAAU,OAAO,CAAC,GAGpB,EAAQ,IAAI,CAAC,YAAY,CAAC,EAAK,IAAc,CAC/C,CAQA,OANI,IACF,IAAI,CAAC,wBAAwB,GAC7B,IAAI,CAAC,WAAW,GAChB,IAAI,CAAC,SAAS,IAGT,CACT,CAKA,UAAW,CACT,OAAO,IAAI,CAAC,KAAK,AACnB,CAEA,WAAY,CACV,GAAI,AAAe,IAAf,IAAI,CAAC,KAAK,CACZ,IAAI,CAAC,MAAM,CAAG,MACT,CACL,IAAI,EAAe,CAAA,EACf,EAAc,CAAA,EACd,EAAU,CAAA,EAEd,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,IACzC,IAAK,IAAI,EAAM,EAAG,EAAM,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAE,IACjB,IAAzB,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,EACtB,CAAA,EAAe,CAAA,CADjB,EAI6B,OAAzB,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,EACtB,CAAA,EAAc,CAAA,CADhB,EAKE,EAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAG,GAC1B,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,GAAK,IAAI,CAAC,KAAK,CAAC,EAAM,EAAE,CAAC,EAAI,EAEjD,CAAA,EAAU,CAAA,CAJZ,EAQE,EAAM,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,MAAM,CAAG,GAC/B,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAI,GAAK,IAAI,CAAC,KAAK,CAAC,EAAI,CAAC,EAAM,EAAE,EAEjD,CAAA,EAAU,CAAA,CAJZ,EASA,GACF,IAAI,CAAC,MAAM,CA/WA,MAgXX,IAAI,CAAC,WAAW,IACP,GAAgB,EACzB,IAAI,CAAC,MAAM,CAAG,GAEd,IAAI,CAAC,MAAM,CAAG,EACd,IAAI,CAAC,YAAY,GAErB,CAEA,OAAO,IAAI,CAAC,MAAM,AACpB,CAEA,OAAQ,CACN,IAAI,CAAC,cAAc,EACrB,CAEA,SAAU,CACR,IAAI,CAAC,cAAc,EACrB,CACF,EDpYsB,KAUtB,WACE,EAAW,SAAS,CAAC,MAAM,CAAC,SAC9B,EAEA,WACE,EAAY,SAAS,CAAC,MAAM,CAAC,SAC/B,GAdM,EAAc,SAAS,aAAa,CAAC,UACrC,EAAQ,SAAS,gBAAgB,CAAC,eAClC,EAAQ,SAAS,aAAa,CAAC,eAC/B,EAAgB,SAAS,aAAa,CAAC,gBACvC,EAAe,SAAS,aAAa,CAAC,kBACtC,EAAa,SAAS,aAAa,CAAC,gBACpC,EAAc,SAAS,aAAa,CAAC,iBAc3C,SAAS,IACP,EAAY,SAAS,CAAC,GAAG,CAAC,SAC5B,CAEA,SAAS,IACP,EAAW,SAAS,CAAC,GAAG,CAAC,SAC3B,CAeA,SAAS,IACP,IAAM,EAAY,aAAa,OAAO,CAAC,cAAgB,CAEvD,CAAA,EAAc,WAAW,CAAG,CAC9B,CAEA,IAEA,EAAK,QAAQ,CAAG,SAAU,CAAK,CAAE,CAAK,EACpC,GAAI,GAAS,EAAQ,EAAG,KAtBL,CAuBjB,CAAA,IAAI,CAAC,KAAK,EAAI,EAvBG,EAwBL,IAAI,CAAC,KAAK,CAvBxB,EAAM,WAAW,CAAG,EAwBlB,AArBJ,SAAmB,CAAM,EACvB,IAAM,EAAgB,aAAa,OAAO,CAAC,aAEvC,CAAA,CAAC,GAAiB,EAAS,CAAA,IAC7B,aAAa,OAAO,CAAC,YAAa,GAClC,IAEJ,EAcc,IAAI,CAAC,KAAK,CACtB,CACF,EAEA,EAAY,gBAAgB,CAAC,QAAS,KACpC,EAAY,WAAW,CAAG,UAC1B,EAAY,SAAS,CAAC,MAAM,CAAC,SAC7B,EAAY,SAAS,CAAC,GAAG,CAAC,WAC1B,EAAM,WAAW,CAAG,IAEpB,EAAM,OAAO,CAAC,AAAC,IACb,EAAK,SAAS,CAAC,MAAM,CAAC,SACxB,GAEI,CAAA,ACpEa,QDoEb,EAAK,MAAM,EAAY,EAAK,MAAM,GAAK,CAAG,IAC5C,IACA,KAGF,EAAK,KAAK,GAvDV,EAAa,SAAS,CAAC,GAAG,CAAC,UAyD3B,IACA,IACA,GACF,GAEA,SAAS,gBAAgB,CAAC,UAAW,AAAC,IACpC,OAAQ,EAAE,GAAG,EACX,IAAK,YACH,EAAK,QAAQ,GACb,KACF,KAAK,aACH,EAAK,SAAS,GACd,KACF,KAAK,UACH,EAAK,MAAM,GACX,KACF,KAAK,YACH,EAAK,QAAQ,EAEjB,CACF","sources":["","src/scripts/main.js","src/modules/Game.class.js"],"sourcesContent":["\"use strict\";\nconst $a5fd07fa01589658$var$IDLE = \"idle\";\nconst $a5fd07fa01589658$var$PLAYING = \"playing\";\nconst $a5fd07fa01589658$export$eb2b832b8b9fda85 = \"win\";\nconst $a5fd07fa01589658$export$43a03cf66b318012 = \"lose\";\nclass $a5fd07fa01589658$export$985739bfa5723e08 {\n constructor(initialState, winCallback, loseCallback){\n this.board = initialState || [\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ]\n ];\n this.score = 0;\n this.status = $a5fd07fa01589658$var$IDLE;\n this.isStarted = false;\n this.winCallback = winCallback;\n this.loseCallback = loseCallback;\n }\n moveTile(fromCell, toCell) {\n const fromCellRect = fromCell.getBoundingClientRect();\n const toCellRect = toCell.getBoundingClientRect();\n const xOffset = toCellRect.left - fromCellRect.left;\n const yOffset = toCellRect.top - fromCellRect.top;\n fromCell.style.setProperty(\"--x-offset\", `${xOffset}px`);\n fromCell.style.setProperty(\"--y-offset\", `${yOffset}px`);\n fromCell.classList.add(\"moving\");\n }\n updateBoard() {\n const cells = document.querySelectorAll(\".field-cell\");\n let cellIndex = 0;\n for(let row = 0; row < this.board.length; row++)for(let col = 0; col < this.board[row].length; col++){\n const cell = cells[cellIndex++];\n const value = this.board[row][col];\n const previousValue = cell.textContent;\n cell.classList.remove(`field-cell--${previousValue}`);\n if (value === 0) cell.textContent = \"\";\n else {\n cell.classList.add(`field-cell--${value}`);\n cell.textContent = value;\n }\n }\n }\n addRandomTile() {\n const emptyCells = [];\n for(let row = 0; row < 4; row++){\n for(let col = 0; col < 4; col++)if (this.board[row][col] === 0) emptyCells.push({\n row: row,\n col: col\n });\n }\n if (emptyCells.length > 0) {\n const { row: row, col: col } = emptyCells[Math.floor(Math.random() * emptyCells.length)];\n if (this.score === 0) this.board[row][col] = 2;\n this.updateBoard();\n }\n }\n addRandomCellAfterMoving() {\n const emptyCells = [];\n for(let row = 0; row < 4; row++){\n for(let col = 0; col < 4; col++)if (this.board[row][col] === 0) emptyCells.push({\n row: row,\n col: col\n });\n }\n if (emptyCells.length > 0) {\n const { row: row, col: col } = emptyCells[Math.floor(Math.random() * emptyCells.length)];\n this.board[row][col] = Math.random() < 0.9 ? 2 : 4;\n this.updateBoard();\n }\n }\n createColumn(col) {\n const newColumn = [];\n for(let row = 0; row < this.board.length; row++)if (this.board[row][col] !== 0) newColumn.push(this.board[row][col]);\n return newColumn;\n }\n updateColumn(col, newColumn) {\n let moved = false;\n for(let row = 0; row < this.board.length; row++)if (this.board[row][col] !== newColumn[row]) {\n this.board[row][col] = newColumn[row];\n moved = true;\n }\n return moved;\n }\n resetGameStart() {\n this.score = 0;\n this.status = $a5fd07fa01589658$var$PLAYING;\n this.board = [\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0\n ]\n ];\n this.addRandomTile();\n this.addRandomTile();\n }\n mergeTitles(newRow, canMerge) {\n const mergedThisMove = [];\n for(let i = 0; i < newRow.length - 1; i++)if (newRow[i] === newRow[i + 1]) {\n newRow[i] *= 2;\n newRow.splice(i + 1, 1);\n canMerge[i] = false;\n mergedThisMove.push(i);\n }\n return mergedThisMove;\n }\n moveLeft() {\n let moved = false;\n for(let row = 0; row < this.board.length; row++){\n const currentRow = this.board[row].filter((val)=>val !== 0);\n const mergedRow = [];\n let skip = false;\n for(let i = 0; i < currentRow.length; i++){\n if (skip) {\n skip = false;\n continue;\n }\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else mergedRow.push(currentRow[i]);\n }\n while(mergedRow.length < this.board[row].length)mergedRow.push(0);\n if (!moved) {\n for(let i = 0; i < this.board[row].length; i++)if (this.board[row][i] !== mergedRow[i]) {\n moved = true;\n break;\n }\n }\n this.board[row] = mergedRow;\n }\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n moveRight() {\n let moved = false;\n for(let row = 0; row < this.board.length; row++){\n const currentRow = this.board[row].filter((val)=>val !== 0);\n const mergedRow = [];\n let skip = false;\n for(let i = 0; i < currentRow.length; i++){\n if (skip) {\n skip = false;\n continue;\n }\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else mergedRow.push(currentRow[i]);\n }\n while(mergedRow.length < this.board[row].length)mergedRow.unshift(0);\n for(let i = 0; i < this.board[row].length; i++)if (this.board[row][i] !== mergedRow[i]) {\n moved = true;\n break;\n }\n this.board[row] = mergedRow;\n }\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n moveUp() {\n let moved = false;\n for(let col = 0; col < this.board.length; col++){\n const newColumn = this.createColumn(col);\n const canMerge = new Array(newColumn.length).fill(true);\n for(let i = 0; i < newColumn.length - 1; i++)if (newColumn[i] === newColumn[i + 1] && canMerge[i] && canMerge[i + 1]) {\n newColumn[i] *= 2;\n newColumn.splice(i + 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n while(newColumn.length < this.board.length)newColumn.push(0);\n moved = this.updateColumn(col, newColumn) || moved;\n }\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n moveDown() {\n let moved = false;\n for(let col = 0; col < this.board.length; col++){\n const newColumn = this.createColumn(col);\n const canMerge = new Array(newColumn.length).fill(true);\n for(let i = newColumn.length - 1; i > 0; i--)if (newColumn[i] === newColumn[i - 1] && canMerge[i] && canMerge[i - 1]) {\n newColumn[i] *= 2;\n newColumn.splice(i - 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n while(newColumn.length < this.board.length)newColumn.unshift(0);\n moved = this.updateColumn(col, newColumn) || moved;\n }\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n return moved;\n }\n /**\n * @returns {number[][]}\n */ getState() {\n return this.board;\n }\n getStatus() {\n if (this.score === 0) this.status = $a5fd07fa01589658$var$IDLE;\n else {\n let hasEmptyCell = false;\n let has2048Cell = false;\n let canMove = false;\n for(let row = 0; row < this.board.length; row++)for(let col = 0; col < this.board[row].length; col++){\n if (this.board[row][col] === 0) hasEmptyCell = true;\n if (this.board[row][col] === 2048) has2048Cell = true;\n if (row < this.board.length - 1 && this.board[row][col] === this.board[row + 1][col]) canMove = true;\n if (col < this.board[row].length - 1 && this.board[row][col] === this.board[row][col + 1]) canMove = true;\n }\n if (has2048Cell) {\n this.status = $a5fd07fa01589658$export$eb2b832b8b9fda85;\n this.winCallback();\n } else if (hasEmptyCell || canMove) this.status = $a5fd07fa01589658$var$PLAYING;\n else {\n this.status = $a5fd07fa01589658$export$43a03cf66b318012;\n this.loseCallback();\n }\n }\n return this.status;\n }\n start() {\n this.resetGameStart();\n }\n restart() {\n this.resetGameStart();\n }\n}\n\n\n\"use strict\";\nconst $09e991522ca7e64e$var$game = new (0, $a5fd07fa01589658$export$985739bfa5723e08)(null, $09e991522ca7e64e$var$showWinMessage, $09e991522ca7e64e$var$showLoseMessage);\nconst $09e991522ca7e64e$var$startButton = document.querySelector(\".start\");\nconst $09e991522ca7e64e$var$cells = document.querySelectorAll(\".field-cell\");\nconst $09e991522ca7e64e$var$score = document.querySelector(\".game-score\");\nconst $09e991522ca7e64e$var$recordElement = document.querySelector(\".best__score\");\nconst $09e991522ca7e64e$var$messageStart = document.querySelector(\".message-start\");\nconst $09e991522ca7e64e$var$messageWin = document.querySelector(\".message-win\");\nconst $09e991522ca7e64e$var$messageLose = document.querySelector(\".message-lose\");\nfunction $09e991522ca7e64e$var$showWinMessage() {\n $09e991522ca7e64e$var$messageWin.classList.remove(\"hidden\");\n}\nfunction $09e991522ca7e64e$var$showLoseMessage() {\n $09e991522ca7e64e$var$messageLose.classList.remove(\"hidden\");\n}\nfunction $09e991522ca7e64e$var$hideMessageStart() {\n $09e991522ca7e64e$var$messageStart.classList.add(\"hidden\");\n}\nfunction $09e991522ca7e64e$var$hideMessageLose() {\n $09e991522ca7e64e$var$messageLose.classList.add(\"hidden\");\n}\nfunction $09e991522ca7e64e$var$hideMessageWin() {\n $09e991522ca7e64e$var$messageWin.classList.add(\"hidden\");\n}\nfunction $09e991522ca7e64e$var$updateScore(value) {\n $09e991522ca7e64e$var$score.textContent = value;\n}\nfunction $09e991522ca7e64e$var$saveScore(sscore) {\n const currentRecord = localStorage.getItem(\"highScore\");\n if (!currentRecord || sscore > currentRecord) {\n localStorage.setItem(\"highScore\", sscore);\n $09e991522ca7e64e$var$displayRecord();\n }\n}\nfunction $09e991522ca7e64e$var$displayRecord() {\n const highScore = localStorage.getItem(\"highScore\") || 0;\n $09e991522ca7e64e$var$recordElement.textContent = highScore;\n}\n$09e991522ca7e64e$var$displayRecord();\n$09e991522ca7e64e$var$game.getScore = function(moved, value) {\n if (moved && value > 0) {\n this.score += value;\n $09e991522ca7e64e$var$updateScore(this.score);\n $09e991522ca7e64e$var$saveScore(this.score);\n }\n};\n$09e991522ca7e64e$var$startButton.addEventListener(\"click\", ()=>{\n $09e991522ca7e64e$var$startButton.textContent = \"Restart\";\n $09e991522ca7e64e$var$startButton.classList.remove(\"start\");\n $09e991522ca7e64e$var$startButton.classList.add(\"restart\");\n $09e991522ca7e64e$var$score.textContent = \"0\";\n $09e991522ca7e64e$var$cells.forEach((cell)=>{\n cell.classList.remove(\"hidden\");\n });\n if ($09e991522ca7e64e$var$game.status === (0, $a5fd07fa01589658$export$eb2b832b8b9fda85) || $09e991522ca7e64e$var$game.status === (0, $a5fd07fa01589658$export$43a03cf66b318012)) {\n $09e991522ca7e64e$var$hideMessageWin();\n $09e991522ca7e64e$var$hideMessageLose();\n }\n $09e991522ca7e64e$var$game.start();\n $09e991522ca7e64e$var$hideMessageStart();\n $09e991522ca7e64e$var$hideMessageLose();\n $09e991522ca7e64e$var$hideMessageWin();\n $09e991522ca7e64e$var$displayRecord();\n});\ndocument.addEventListener(\"keydown\", (e)=>{\n switch(e.key){\n case \"ArrowLeft\":\n $09e991522ca7e64e$var$game.moveLeft();\n break;\n case \"ArrowRight\":\n $09e991522ca7e64e$var$game.moveRight();\n break;\n case \"ArrowUp\":\n $09e991522ca7e64e$var$game.moveUp();\n break;\n case \"ArrowDown\":\n $09e991522ca7e64e$var$game.moveDown();\n break;\n }\n});\n\n\n//# sourceMappingURL=index.ef8de8d9.js.map\n","'use strict';\n\nimport { WIN, LOSE, Game } from '../modules/Game.class';\n\nconst game = new Game(null, showWinMessage, showLoseMessage);\n\nconst startButton = document.querySelector('.start');\nconst cells = document.querySelectorAll('.field-cell');\nconst score = document.querySelector('.game-score');\nconst recordElement = document.querySelector('.best__score');\nconst messageStart = document.querySelector('.message-start');\nconst messageWin = document.querySelector('.message-win');\nconst messageLose = document.querySelector('.message-lose');\n\nfunction showWinMessage() {\n messageWin.classList.remove('hidden');\n}\n\nfunction showLoseMessage() {\n messageLose.classList.remove('hidden');\n}\n\nfunction hideMessageStart() {\n messageStart.classList.add('hidden');\n}\n\nfunction hideMessageLose() {\n messageLose.classList.add('hidden');\n}\n\nfunction hideMessageWin() {\n messageWin.classList.add('hidden');\n}\n\nfunction updateScore(value) {\n score.textContent = value;\n}\n\nfunction saveScore(sscore) {\n const currentRecord = localStorage.getItem('highScore');\n\n if (!currentRecord || sscore > currentRecord) {\n localStorage.setItem('highScore', sscore);\n displayRecord();\n }\n}\n\nfunction displayRecord() {\n const highScore = localStorage.getItem('highScore') || 0;\n\n recordElement.textContent = highScore;\n}\n\ndisplayRecord();\n\ngame.getScore = function (moved, value) {\n if (moved && value > 0) {\n this.score += value;\n updateScore(this.score);\n saveScore(this.score);\n }\n};\n\nstartButton.addEventListener('click', () => {\n startButton.textContent = 'Restart';\n startButton.classList.remove('start');\n startButton.classList.add('restart');\n score.textContent = '0';\n\n cells.forEach((cell) => {\n cell.classList.remove('hidden');\n });\n\n if (game.status === WIN || game.status === LOSE) {\n hideMessageWin();\n hideMessageLose();\n }\n\n game.start();\n hideMessageStart();\n hideMessageLose();\n hideMessageWin();\n displayRecord();\n});\n\ndocument.addEventListener('keydown', (e) => {\n switch (e.key) {\n case 'ArrowLeft':\n game.moveLeft();\n break;\n case 'ArrowRight':\n game.moveRight();\n break;\n case 'ArrowUp':\n game.moveUp();\n break;\n case 'ArrowDown':\n game.moveDown();\n break;\n }\n});\n","'use strict';\n\nconst IDLE = 'idle';\nconst PLAYING = 'playing';\n\nexport const WIN = 'win';\nexport const LOSE = 'lose';\n\nexport class Game {\n constructor(initialState, winCallback, loseCallback) {\n this.board = initialState || [\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n ];\n\n this.score = 0;\n\n this.status = IDLE;\n this.isStarted = false;\n this.winCallback = winCallback;\n this.loseCallback = loseCallback;\n }\n\n moveTile(fromCell, toCell) {\n const fromCellRect = fromCell.getBoundingClientRect();\n const toCellRect = toCell.getBoundingClientRect();\n\n const xOffset = toCellRect.left - fromCellRect.left;\n const yOffset = toCellRect.top - fromCellRect.top;\n\n fromCell.style.setProperty('--x-offset', `${xOffset}px`);\n fromCell.style.setProperty('--y-offset', `${yOffset}px`);\n\n fromCell.classList.add('moving');\n }\n\n updateBoard() {\n const cells = document.querySelectorAll('.field-cell');\n\n let cellIndex = 0;\n\n for (let row = 0; row < this.board.length; row++) {\n for (let col = 0; col < this.board[row].length; col++) {\n const cell = cells[cellIndex++];\n const value = this.board[row][col];\n const previousValue = cell.textContent;\n\n cell.classList.remove(`field-cell--${previousValue}`);\n\n if (value === 0) {\n cell.textContent = '';\n } else {\n cell.classList.add(`field-cell--${value}`);\n cell.textContent = value;\n }\n }\n }\n }\n\n addRandomTile() {\n const emptyCells = [];\n\n for (let row = 0; row < 4; row++) {\n for (let col = 0; col < 4; col++) {\n if (this.board[row][col] === 0) {\n emptyCells.push({ row, col });\n }\n }\n }\n\n if (emptyCells.length > 0) {\n const { row, col } =\n emptyCells[Math.floor(Math.random() * emptyCells.length)];\n\n if (this.score === 0) {\n this.board[row][col] = 2;\n }\n this.updateBoard();\n }\n }\n\n addRandomCellAfterMoving() {\n const emptyCells = [];\n\n for (let row = 0; row < 4; row++) {\n for (let col = 0; col < 4; col++) {\n if (this.board[row][col] === 0) {\n emptyCells.push({ row, col });\n }\n }\n }\n\n if (emptyCells.length > 0) {\n const { row, col } =\n emptyCells[Math.floor(Math.random() * emptyCells.length)];\n\n this.board[row][col] = Math.random() < 0.9 ? 2 : 4;\n this.updateBoard();\n }\n }\n\n createColumn(col) {\n const newColumn = [];\n\n for (let row = 0; row < this.board.length; row++) {\n if (this.board[row][col] !== 0) {\n newColumn.push(this.board[row][col]);\n }\n }\n\n return newColumn;\n }\n\n updateColumn(col, newColumn) {\n let moved = false;\n\n for (let row = 0; row < this.board.length; row++) {\n if (this.board[row][col] !== newColumn[row]) {\n this.board[row][col] = newColumn[row];\n moved = true;\n }\n }\n\n return moved;\n }\n\n resetGameStart() {\n this.score = 0;\n this.status = PLAYING;\n\n this.board = [\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n ];\n\n this.addRandomTile();\n this.addRandomTile();\n }\n\n mergeTitles(newRow, canMerge) {\n const mergedThisMove = [];\n\n for (let i = 0; i < newRow.length - 1; i++) {\n if (newRow[i] === newRow[i + 1]) {\n newRow[i] *= 2;\n newRow.splice(i + 1, 1);\n canMerge[i] = false;\n mergedThisMove.push(i);\n }\n }\n\n return mergedThisMove;\n }\n\n moveLeft() {\n let moved = false;\n\n for (let row = 0; row < this.board.length; row++) {\n const currentRow = this.board[row].filter((val) => val !== 0);\n const mergedRow = [];\n\n let skip = false;\n\n for (let i = 0; i < currentRow.length; i++) {\n if (skip) {\n skip = false;\n continue;\n }\n\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else {\n mergedRow.push(currentRow[i]);\n }\n }\n\n while (mergedRow.length < this.board[row].length) {\n mergedRow.push(0);\n }\n\n if (!moved) {\n for (let i = 0; i < this.board[row].length; i++) {\n if (this.board[row][i] !== mergedRow[i]) {\n moved = true;\n break;\n }\n }\n }\n\n this.board[row] = mergedRow;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n moveRight() {\n let moved = false;\n\n for (let row = 0; row < this.board.length; row++) {\n const currentRow = this.board[row].filter((val) => val !== 0);\n\n const mergedRow = [];\n let skip = false;\n\n for (let i = 0; i < currentRow.length; i++) {\n if (skip) {\n skip = false;\n continue;\n }\n\n if (currentRow[i] === currentRow[i + 1]) {\n mergedRow.push(currentRow[i] * 2);\n this.getScore(true, currentRow[i] * 2);\n skip = true;\n moved = true;\n } else {\n mergedRow.push(currentRow[i]);\n }\n }\n\n while (mergedRow.length < this.board[row].length) {\n mergedRow.unshift(0);\n }\n\n for (let i = 0; i < this.board[row].length; i++) {\n if (this.board[row][i] !== mergedRow[i]) {\n moved = true;\n break;\n }\n }\n\n this.board[row] = mergedRow;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n moveUp() {\n let moved = false;\n\n for (let col = 0; col < this.board.length; col++) {\n const newColumn = this.createColumn(col);\n const canMerge = new Array(newColumn.length).fill(true);\n\n for (let i = 0; i < newColumn.length - 1; i++) {\n if (\n newColumn[i] === newColumn[i + 1] &&\n canMerge[i] &&\n canMerge[i + 1]\n ) {\n newColumn[i] *= 2;\n newColumn.splice(i + 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n }\n\n while (newColumn.length < this.board.length) {\n newColumn.push(0);\n }\n\n moved = this.updateColumn(col, newColumn) || moved;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n moveDown() {\n let moved = false;\n\n for (let col = 0; col < this.board.length; col++) {\n const newColumn = this.createColumn(col);\n const canMerge = new Array(newColumn.length).fill(true);\n\n for (let i = newColumn.length - 1; i > 0; i--) {\n if (\n newColumn[i] === newColumn[i - 1] &&\n canMerge[i] &&\n canMerge[i - 1]\n ) {\n newColumn[i] *= 2;\n newColumn.splice(i - 1, 1);\n moved = true;\n canMerge[i] = false;\n this.getScore(moved, newColumn[i]);\n }\n }\n\n while (newColumn.length < this.board.length) {\n newColumn.unshift(0);\n }\n\n moved = this.updateColumn(col, newColumn) || moved;\n }\n\n if (moved) {\n this.addRandomCellAfterMoving();\n this.updateBoard();\n this.getStatus();\n }\n\n return moved;\n }\n\n /**\n * @returns {number[][]}\n */\n getState() {\n return this.board;\n }\n\n getStatus() {\n if (this.score === 0) {\n this.status = IDLE;\n } else {\n let hasEmptyCell = false;\n let has2048Cell = false;\n let canMove = false;\n\n for (let row = 0; row < this.board.length; row++) {\n for (let col = 0; col < this.board[row].length; col++) {\n if (this.board[row][col] === 0) {\n hasEmptyCell = true;\n }\n\n if (this.board[row][col] === 2048) {\n has2048Cell = true;\n }\n\n if (\n row < this.board.length - 1 &&\n this.board[row][col] === this.board[row + 1][col]\n ) {\n canMove = true;\n }\n\n if (\n col < this.board[row].length - 1 &&\n this.board[row][col] === this.board[row][col + 1]\n ) {\n canMove = true;\n }\n }\n }\n\n if (has2048Cell) {\n this.status = WIN;\n this.winCallback();\n } else if (hasEmptyCell || canMove) {\n this.status = PLAYING;\n } else {\n this.status = LOSE;\n this.loseCallback();\n }\n }\n\n return this.status;\n }\n\n start() {\n this.resetGameStart();\n }\n\n restart() {\n this.resetGameStart();\n }\n}\n"],"names":["$a5fd07fa01589658$var$IDLE","$a5fd07fa01589658$var$PLAYING","$a5fd07fa01589658$export$43a03cf66b318012","$09e991522ca7e64e$var$game","constructor","initialState","winCallback","loseCallback","board","score","status","isStarted","moveTile","fromCell","toCell","fromCellRect","getBoundingClientRect","toCellRect","xOffset","left","yOffset","top","style","setProperty","classList","add","updateBoard","cells","document","querySelectorAll","cellIndex","row","length","col","cell","value","previousValue","textContent","remove","addRandomTile","emptyCells","push","Math","floor","random","addRandomCellAfterMoving","createColumn","newColumn","updateColumn","moved","resetGameStart","mergeTitles","newRow","canMerge","mergedThisMove","i","splice","moveLeft","currentRow","filter","val","mergedRow","skip","getScore","getStatus","moveRight","unshift","moveUp","Array","fill","moveDown","getState","hasEmptyCell","has2048Cell","canMove","start","restart","$09e991522ca7e64e$var$messageWin","$09e991522ca7e64e$var$messageLose","$09e991522ca7e64e$var$startButton","querySelector","$09e991522ca7e64e$var$cells","$09e991522ca7e64e$var$score","$09e991522ca7e64e$var$recordElement","$09e991522ca7e64e$var$messageStart","$09e991522ca7e64e$var$hideMessageLose","$09e991522ca7e64e$var$hideMessageWin","$09e991522ca7e64e$var$displayRecord","highScore","localStorage","getItem","$09e991522ca7e64e$var$saveScore","sscore","currentRecord","setItem","addEventListener","forEach","e","key"],"version":3,"file":"index.ef8de8d9.js.map"} \ No newline at end of file diff --git a/dist/index.html b/dist/index.html new file mode 100644 index 000000000..f538a138d --- /dev/null +++ b/dist/index.html @@ -0,0 +1 @@ +2048

2048

Best: 0

Score: 0

Press "Start" to begin game. Good luck!

\ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f209cb6e0..ff37dc85b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@mate-academy/eslint-config": "latest", "@mate-academy/jest-mochawesome-reporter": "^1.0.0", "@mate-academy/linthtml-config": "latest", - "@mate-academy/scripts": "^1.8.5", + "@mate-academy/scripts": "^1.9.12", "@mate-academy/stylelint-config": "latest", "@parcel/transformer-sass": "^2.12.0", "cypress": "^13.13.0", @@ -1467,10 +1467,11 @@ "dev": true }, "node_modules/@mate-academy/scripts": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.8.5.tgz", - "integrity": "sha512-mHRY2FkuoYCf5U0ahIukkaRo5LSZsxrTSgMJheFoyf3VXsTvfM9OfWcZIDIDB521kdPrScHHnRp+JRNjCfUO5A==", + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.9.12.tgz", + "integrity": "sha512-/OcmxMa34lYLFlGx7Ig926W1U1qjrnXbjFJ2TzUcDaLmED+A5se652NcWwGOidXRuMAOYLPU2jNYBEkKyXrFJA==", "dev": true, + "license": "MIT", "dependencies": { "@octokit/rest": "^17.11.2", "@types/get-port": "^4.2.0", diff --git a/package.json b/package.json index 0335978ca..05abe81e0 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@mate-academy/eslint-config": "latest", "@mate-academy/jest-mochawesome-reporter": "^1.0.0", "@mate-academy/linthtml-config": "latest", - "@mate-academy/scripts": "^1.8.5", + "@mate-academy/scripts": "^1.9.12", "@mate-academy/stylelint-config": "latest", "@parcel/transformer-sass": "^2.12.0", "cypress": "^13.13.0", diff --git a/src/images/Untitled.png b/src/images/Untitled.png new file mode 100644 index 000000000..448d52e27 Binary files /dev/null and b/src/images/Untitled.png differ diff --git a/src/index.html b/src/index.html index aff3d1a98..8469f09c6 100644 --- a/src/index.html +++ b/src/index.html @@ -7,6 +7,8 @@ content="width=device-width, initial-scale=1.0" /> 2048 +

2048

+

+ Best: + 0 +

Score: 0 @@ -65,6 +71,6 @@

2048

- + diff --git a/src/modules/Game.class.js b/src/modules/Game.class.js index 65cd219c9..3f7a0ca5d 100644 --- a/src/modules/Game.class.js +++ b/src/modules/Game.class.js @@ -1,68 +1,294 @@ 'use strict'; -/** - * This class represents the game. - * Now it has a basic structure, that is needed for testing. - * Feel free to add more props and methods if needed. - */ -class Game { - /** - * Creates a new game instance. - * - * @param {number[][]} initialState - * The initial state of the board. - * @default - * [[0, 0, 0, 0], - * [0, 0, 0, 0], - * [0, 0, 0, 0], - * [0, 0, 0, 0]] - * - * If passed, the board will be initialized with the provided - * initial state. - */ - constructor(initialState) { - // eslint-disable-next-line no-console - console.log(initialState); +const IDLE = 'idle'; +const PLAYING = 'playing'; + +export const WIN = 'win'; +export const LOSE = 'lose'; + +export class Game { + constructor(initialState, winCallback, loseCallback) { + this.board = initialState || [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ]; + + this.score = 0; + + this.status = IDLE; + this.winCallback = winCallback; + this.loseCallback = loseCallback; } - moveLeft() {} - moveRight() {} - moveUp() {} - moveDown() {} + updateBoard() { + const cells = document.querySelectorAll('.field-cell'); - /** - * @returns {number} - */ - getScore() {} + let cellIndex = 0; + + for (let row = 0; row < this.board.length; row++) { + for (let col = 0; col < this.board[row].length; col++) { + const cell = cells[cellIndex++]; + const value = this.board[row][col]; + const previousValue = cell.textContent; + + cell.classList.remove(`field-cell--${previousValue}`); + + if (value === 0) { + cell.textContent = ''; + } else { + cell.classList.add(`field-cell--${value}`); + cell.textContent = value; + } + } + } + } + + findEmptyCell() { + const emptyCells = []; + + for (let row = 0; row < this.board.length; row++) { + for (let col = 0; col < this.board.length; col++) { + if (this.board[row][col] === 0) { + emptyCells.push({ row, col }); + } + } + } + + return emptyCells[Math.floor(Math.random() * emptyCells.length)]; + } + + addRandomTile() { + const emptyCell = this.findEmptyCell(); + + if (!emptyCell) { + return; + } + + if (this.score === 0) { + this.board[emptyCell.row][emptyCell.col] = 2; + } + this.updateBoard(); + } + + addRandomCellAfterMoving() { + const emptyCell = this.findEmptyCell(); + + if (!emptyCell) { + return; + } + + this.board[emptyCell.row][emptyCell.col] = Math.random() < 0.9 ? 2 : 4; + this.updateBoard(); + } + + createColumn(col) { + const newColumn = []; + + for (let row = 0; row < this.board.length; row++) { + if (this.board[row][col] !== 0) { + newColumn.push(this.board[row][col]); + } + } + + return newColumn; + } + + updateColumn(col, newColumn) { + let moved = false; + + for (let row = 0; row < this.board.length; row++) { + if (this.board[row][col] !== newColumn[row]) { + this.board[row][col] = newColumn[row]; + moved = true; + } + } + + return moved; + } + + resetGameStart() { + this.score = 0; + this.status = PLAYING; + + this.board = [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ]; + + this.addRandomTile(); + this.addRandomTile(); + } + + updateBoardAfterMoving() { + this.addRandomCellAfterMoving(); + this.updateBoard(); + this.getStatus(); + } + + moveHorizontal(fillWithZeros) { + for (let row = 0; row < this.board.length; row++) { + const currentRow = this.board[row].filter((val) => val !== 0); + + const mergedRow = []; + + for (let i = 0; i < currentRow.length; i++) { + const currentValue = currentRow[i]; + + if (currentValue === currentRow[i + 1]) { + const doubled = currentValue * 2; + + mergedRow.push(doubled); + this.getScore(true, doubled); + i++; + } else { + mergedRow.push(currentValue); + } + } + + while (mergedRow.length < this.board[row].length) { + fillWithZeros(mergedRow); + } + + this.board[row] = mergedRow; + } + } + + moveLeft() { + this.moveHorizontal((array) => array.push(0)); + this.updateBoardAfterMoving(); + } + + moveRight() { + this.moveHorizontal((array) => array.unshift(0)); + this.updateBoardAfterMoving(); + } + + moveUp() { + for (let col = 0; col < this.board.length; col++) { + const newColumn = this.createColumn(col); + const canMerge = new Array(newColumn.length).fill(true); + + for (let i = 0; i < newColumn.length - 1; i++) { + if ( + newColumn[i] === newColumn[i + 1] && + canMerge[i] && + canMerge[i + 1] + ) { + newColumn[i] *= 2; + newColumn.splice(i + 1, 1); + canMerge[i] = false; + this.getScore(true, newColumn[i]); + } + } + + while (newColumn.length < this.board.length) { + newColumn.push(0); + } + + this.updateColumn(col, newColumn); + } + + this.updateBoardAfterMoving(); + } + + moveDown() { + for (let col = 0; col < this.board.length; col++) { + const newColumn = this.createColumn(col); + const canMerge = new Array(newColumn.length).fill(true); + + for (let i = newColumn.length - 1; i > 0; i--) { + if ( + newColumn[i] === newColumn[i - 1] && + canMerge[i] && + canMerge[i - 1] + ) { + newColumn[i] *= 2; + newColumn.splice(i - 1, 1); + canMerge[i] = false; + this.getScore(true, newColumn[i]); + } + } + + while (newColumn.length < this.board.length) { + newColumn.unshift(0); + } + + this.updateColumn(col, newColumn); + } + + this.updateBoardAfterMoving(); + } /** * @returns {number[][]} */ - getState() {} + getState() { + return this.board; + } - /** - * Returns the current game status. - * - * @returns {string} One of: 'idle', 'playing', 'win', 'lose' - * - * `idle` - the game has not started yet (the initial state); - * `playing` - the game is in progress; - * `win` - the game is won; - * `lose` - the game is lost - */ - getStatus() {} + getStatus() { + if (this.score === 0) { + this.status = IDLE; - /** - * Starts the game. - */ - start() {} + return this.status; + } - /** - * Resets the game. - */ - restart() {} + let has2048Cell = false; + let canMove = false; - // Add your own methods here -} + for (let row = 0; row < this.board.length; row++) { + for (let col = 0; col < this.board[row].length; col++) { + const currentCell = this.board[row][col]; + + if (currentCell === 2048) { + has2048Cell = true; + } + + if (canMove) { + continue; + } + + if (currentCell === 0) { + canMove = true; + continue; + } -module.exports = Game; + const canMoveVertically = + row < this.board.length - 1 && + currentCell === this.board[row + 1][col]; + + const canMoveHorrizontally = + col < this.board[row].length - 1 && + currentCell === this.board[row][col + 1]; + + if (canMoveVertically || canMoveHorrizontally) { + canMove = true; + } + } + } + + if (has2048Cell) { + this.status = WIN; + this.winCallback(); + } else if (canMove) { + this.status = PLAYING; + } else { + this.status = LOSE; + this.loseCallback(); + } + + return this.status; + } + + start() { + this.resetGameStart(); + } + + restart() { + this.resetGameStart(); + } +} diff --git a/src/scripts/main.js b/src/scripts/main.js index dc7f045a3..6ba853b36 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1,7 +1,101 @@ 'use strict'; -// Uncomment the next lines to use your game instance in the browser -// const Game = require('../modules/Game.class'); -// const game = new Game(); +import { WIN, LOSE, Game } from '../modules/Game.class'; -// Write your code here +const game = new Game(null, showWinMessage, showLoseMessage); + +const startButton = document.querySelector('.start'); +const cells = document.querySelectorAll('.field-cell'); +const score = document.querySelector('.game-score'); +const recordElement = document.querySelector('.best__score'); +const messageStart = document.querySelector('.message-start'); +const messageWin = document.querySelector('.message-win'); +const messageLose = document.querySelector('.message-lose'); + +function showWinMessage() { + messageWin.classList.remove('hidden'); +} + +function showLoseMessage() { + messageLose.classList.remove('hidden'); +} + +function hideMessageStart() { + messageStart.classList.add('hidden'); +} + +function hideMessageLose() { + messageLose.classList.add('hidden'); +} + +function hideMessageWin() { + messageWin.classList.add('hidden'); +} + +function updateScore(value) { + score.textContent = value; +} + +function saveScore(sscore) { + const currentRecord = localStorage.getItem('highScore'); + + if (!currentRecord || sscore > currentRecord) { + localStorage.setItem('highScore', sscore); + displayRecord(); + } +} + +function displayRecord() { + const highScore = localStorage.getItem('highScore') || 0; + + recordElement.textContent = highScore; +} + +displayRecord(); + +game.getScore = function (moved, value) { + if (moved && value > 0) { + this.score += value; + updateScore(this.score); + saveScore(this.score); + } +}; + +startButton.addEventListener('click', () => { + startButton.textContent = 'Restart'; + startButton.classList.remove('start'); + startButton.classList.add('restart'); + score.textContent = '0'; + + cells.forEach((cell) => { + cell.classList.remove('hidden'); + }); + + if (game.status === WIN || game.status === LOSE) { + hideMessageWin(); + hideMessageLose(); + } + + game.start(); + hideMessageStart(); + hideMessageLose(); + hideMessageWin(); + displayRecord(); +}); + +document.addEventListener('keydown', (e) => { + switch (e.key) { + case 'ArrowLeft': + game.moveLeft(); + break; + case 'ArrowRight': + game.moveRight(); + break; + case 'ArrowUp': + game.moveUp(); + break; + case 'ArrowDown': + game.moveDown(); + break; + } +}); diff --git a/src/styles/main.scss b/src/styles/main.scss index c43f37dcf..14cc90dc3 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -18,61 +18,67 @@ body { color: #776e65; box-sizing: border-box; text-align: center; - vertical-align: center; + vertical-align: middle; user-select: none; + position: relative; + transition: transform 0.2s ease, background-color 0.2s ease; +} - &--2 { - background: #eee4da; - } +.field-cell:empty { + background: #d6cdc4; +} - &--4 { - background: #ede0c8; - } +.field-cell--2 { + background: #eee4da; +} - &--8 { - background: #f2b179; - color: #f9f6f2; - } +.field-cell--4 { + background: #e1d5c7; +} - &--16 { - background: #f59563; - color: #f9f6f2; - } +.field-cell--8 { + background: #5cb3bb; + color: #f9f6f2; +} - &--32 { - background: #f67c5f; - color: #f9f6f2; - } +.field-cell--16 { + background: #469299; + color: #f9f6f2; +} - &--64 { - background: #f65e3b; - color: #f9f6f2; - } +.field-cell--32 { + background: #349569; + color: #f9f6f2; +} - &--128 { - background: #edcf72; - color: #f9f6f2; - } +.field-cell--64 { + background: #30ac64; + color: #f9f6f2; +} - &--256 { - background: #edcc61; - color: #f9f6f2; - } +.field-cell--128 { + background: #26b84d; + color: #f9f6f2; +} - &--512 { - background: #edc850; - color: #f9f6f2; - } +.field-cell--256 { + background: #0b7476; + color: #fbfbfb; +} - &--1024 { - background: #edc53f; - color: #f9f6f2; - } +.field-cell--512 { + background: #5b8fd9; + color: #f9f6f2; +} - &--2048 { - background: #edc22e; - color: #f9f6f2; - } +.field-cell--1024 { + background: #3b75c6; + color: #f9f6f2; +} + +.field-cell--2048 { + background: #3b49c6; + color: #f9f6f2; } .game-field { @@ -91,7 +97,7 @@ body { } h1 { - background: #edc22e; + background: #3a6ed6; color: #f9f6f2; width: 75px; height: 75px; @@ -104,6 +110,7 @@ h1 { margin: 0; } +.best, .info { display: flex; flex-direction: column; @@ -133,24 +140,23 @@ h1 { font-size: 16px; width: 75px; height: 75px; - transition: 0.25s ease background; } .start { - background: #1dae28; + background: #0aca6d; font-size: 20px; &:hover { - background: #179921; + background: #10b96a; } } .restart { - background: #f1b2b2; + background: #eb5b7d; &:hover { - background: #f87474; + background: #d45271; } } @@ -177,7 +183,12 @@ h1 { } .message-win { - background: #edc22e; + background: #2669b5; + color: #f9f6f2; +} + +.message-lose { + background: #bf687c; color: #f9f6f2; } @@ -185,3 +196,35 @@ h1 { width: 100%; height: 150px; } + +.moving { + animation: move-tile 0.5s forwards; +} + +@keyframes move-tile { + from { transform: translate(var(--x-offset), var(--y-offset)); } + to { transform: translate(0, 0); } +} + +@keyframes merge-tile { + 0% { + transform: scale(1); + opacity: 1; + box-shadow: 0 0 0 rgba(0, 0, 0, 0); + } + 50% { + transform: scale(1.2); + opacity: 0.7; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + } + 100% { + transform: scale(1); + opacity: 1; + box-shadow: 0 0 0 rgba(0, 0, 0, 0); + } +} + +.field-cell--merged { + animation: merge-tile 0.2s ease; + transition: transform 0.2s ease, opacity 0.4s ease; +}