{"mappings":"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","sources":["src/js/game_manager.js"],"sourcesContent":["// _fibonacci = {1: 2, 2: 3, 3: 5, 5: 8, 8: 13, 13: 21, 21: 34, 34: 55, 55: 89, 89: 144, 144: 233, 233: 377, 377: 610, 610: 987, 987: 1597, 1597: 2584, 2584: 4181, 4181: 6765}\n_fibonacci = {1: 2, 2: 3}\n\nfunction isMergeable(x, y) {\n if (x > y) [x, y] = [y, x]\n // if (_fibonacci[x] === y && !_fibonacci[y]) _fibonacci[y] = x + y\n // return _fibonacci[x] === y || (x === 1 && y == 1)\n return Math.round(x * (1 + Math.sqrt(5)) / 2) === y || (x === 1 && y == 1)\n}\n\nfunction GameManager(size, InputManager, Actuator, StorageManager) {\n this.size = size; // Size of the grid\n this.inputManager = new InputManager;\n this.storageManager = new StorageManager;\n this.actuator = new Actuator;\n\n this.startTiles = 2;\n\n this.inputManager.on(\"move\", this.move.bind(this));\n this.inputManager.on(\"restart\", this.restart.bind(this));\n this.inputManager.on(\"keepPlaying\", this.keepPlaying.bind(this));\n\n this.setup();\n}\n\n// Restart the game\nGameManager.prototype.restart = function () {\n this.storageManager.clearGameState();\n this.actuator.continueGame(); // Clear the game won/lost message\n this.setup();\n};\n\n// Keep playing after winning (allows going over 987)\nGameManager.prototype.keepPlaying = function () {\n this.keepPlaying = true;\n this.actuator.continueGame(); // Clear the game won/lost message\n};\n\n// Return true if the game is lost, or has won and the user hasn't kept playing\nGameManager.prototype.isGameTerminated = function () {\n return this.over || (this.won && !this.keepPlaying);\n};\n\n// Set up the game\nGameManager.prototype.setup = function () {\n var previousState = this.storageManager.getGameState();\n\n // Reload the game from a previous game if present\n if (previousState) {\n this.grid = new Grid(previousState.grid.size,\n previousState.grid.cells); // Reload grid\n this.score = previousState.score;\n this.over = previousState.over;\n this.won = previousState.won;\n this.keepPlaying = previousState.keepPlaying;\n } else {\n this.grid = new Grid(this.size);\n this.score = 0;\n this.over = false;\n this.won = false;\n this.keepPlaying = false;\n\n // Add the initial tiles\n this.addStartTiles();\n }\n\n // Update the actuator\n this.actuate();\n};\n\n// Set up the initial tiles to start the game with\nGameManager.prototype.addStartTiles = function () {\n for (var i = 0; i < this.startTiles; i++) {\n this.addRandomTile();\n }\n};\n\n// Adds a tile in a random position\nGameManager.prototype.addRandomTile = function () {\n if (this.grid.cellsAvailable()) {\n var value = Math.random() < 0.75 ? 1 : 2;\n var tile = new Tile(this.grid.randomAvailableCell(), value);\n\n this.grid.insertTile(tile);\n }\n};\n\n// Sends the updated grid to the actuator\nGameManager.prototype.actuate = function () {\n if (this.storageManager.getBestScore() < this.score) {\n this.storageManager.setBestScore(this.score);\n }\n\n // Clear the state when the game is over (game over only, not win)\n if (this.over) {\n this.storageManager.clearGameState();\n } else {\n this.storageManager.setGameState(this.serialize());\n }\n\n this.actuator.actuate(this.grid, {\n score: this.score,\n over: this.over,\n won: this.won,\n bestScore: this.storageManager.getBestScore(),\n terminated: this.isGameTerminated()\n });\n\n};\n\n// Represent the current game as an object\nGameManager.prototype.serialize = function () {\n return {\n grid: this.grid.serialize(),\n score: this.score,\n over: this.over,\n won: this.won,\n keepPlaying: this.keepPlaying\n };\n};\n\n// Save all tile positions and remove merger info\nGameManager.prototype.prepareTiles = function () {\n this.grid.eachCell(function (x, y, tile) {\n if (tile) {\n tile.mergedFrom = null;\n tile.savePosition();\n }\n });\n};\n\n// Move a tile and its representation\nGameManager.prototype.moveTile = function (tile, cell) {\n this.grid.cells[tile.x][tile.y] = null;\n this.grid.cells[cell.x][cell.y] = tile;\n tile.updatePosition(cell);\n};\n\n// Move tiles on the grid in the specified direction\nGameManager.prototype.move = function (direction) {\n // 0: up, 1: right, 2: down, 3: left\n var self = this;\n\n if (this.isGameTerminated()) return; // Don't do anything if the game's over\n\n var cell, tile;\n\n var vector = this.getVector(direction);\n var traversals = this.buildTraversals(vector);\n var moved = false;\n\n // Save the current tile positions and remove merger information\n this.prepareTiles();\n\n // Traverse the grid in the right direction and move tiles\n traversals.x.forEach(function (x) {\n traversals.y.forEach(function (y) {\n cell = { x: x, y: y };\n tile = self.grid.cellContent(cell);\n\n if (tile) {\n var positions = self.findFarthestPosition(cell, vector);\n var next = self.grid.cellContent(positions.next);\n\n // Only one merger per row traversal?\n if (next && isMergeable(next.value, tile.value) && !next.mergedFrom) {\n var merged = new Tile(positions.next, next.value + tile.value);\n merged.mergedFrom = [tile, next];\n\n self.grid.insertTile(merged);\n self.grid.removeTile(tile);\n\n // Converge the two tiles' positions\n tile.updatePosition(positions.next);\n\n // Update the score\n self.score += merged.value;\n\n // The mighty 987 tile\n if (merged.value === 987) self.won = true;\n } else {\n self.moveTile(tile, positions.farthest);\n }\n\n if (!self.positionsEqual(cell, tile)) {\n moved = true; // The tile moved from its original cell!\n }\n }\n });\n });\n\n if (moved) {\n this.addRandomTile();\n\n if (!this.movesAvailable()) {\n this.over = true; // Game over!\n }\n\n this.actuate();\n }\n};\n\n// Get the vector representing the chosen direction\nGameManager.prototype.getVector = function (direction) {\n // Vectors representing tile movement\n var map = {\n 0: { x: 0, y: -1 }, // Up\n 1: { x: 1, y: 0 }, // Right\n 2: { x: 0, y: 1 }, // Down\n 3: { x: -1, y: 0 } // Left\n };\n\n return map[direction];\n};\n\n// Build a list of positions to traverse in the right order\nGameManager.prototype.buildTraversals = function (vector) {\n var traversals = { x: [], y: [] };\n\n for (var pos = 0; pos < this.size; pos++) {\n traversals.x.push(pos);\n traversals.y.push(pos);\n }\n\n // Always traverse from the farthest cell in the chosen direction\n if (vector.x === 1) traversals.x = traversals.x.reverse();\n if (vector.y === 1) traversals.y = traversals.y.reverse();\n\n return traversals;\n};\n\nGameManager.prototype.findFarthestPosition = function (cell, vector) {\n var previous;\n\n // Progress towards the vector direction until an obstacle is found\n do {\n previous = cell;\n cell = { x: previous.x + vector.x, y: previous.y + vector.y };\n } while (this.grid.withinBounds(cell) &&\n this.grid.cellAvailable(cell));\n\n return {\n farthest: previous,\n next: cell // Used to check if a merge is required\n };\n};\n\nGameManager.prototype.movesAvailable = function () {\n return this.grid.cellsAvailable() || this.tileMatchesAvailable();\n};\n\n// Check for available matches between tiles (more expensive check)\nGameManager.prototype.tileMatchesAvailable = function () {\n var self = this;\n\n var tile;\n\n for (var x = 0; x < this.size; x++) {\n for (var y = 0; y < this.size; y++) {\n tile = this.grid.cellContent({ x: x, y: y });\n\n if (tile) {\n for (var direction = 0; direction < 4; direction++) {\n var vector = self.getVector(direction);\n var cell = { x: x + vector.x, y: y + vector.y };\n\n var other = self.grid.cellContent(cell);\n\n if (other && isMergeable(other.value, tile.value)) {\n return true; // These two tiles can be merged\n }\n }\n }\n }\n }\n\n return false;\n};\n\nGameManager.prototype.positionsEqual = function (first, second) {\n return first.x === second.x && first.y === second.y;\n};\n"],"names":["isMergeable","x","y","Math","round","sqrt","GameManager","size","InputManager","Actuator","StorageManager","this","inputManager","storageManager","actuator","startTiles","on","move","bind","restart","keepPlaying","setup","_fibonacci","prototype","clearGameState","continueGame","isGameTerminated","over","won","previousState","getGameState","grid","Grid","cells","score","addStartTiles","actuate","i","addRandomTile","cellsAvailable","value","random","tile","Tile","randomAvailableCell","insertTile","getBestScore","setBestScore","setGameState","serialize","bestScore","terminated","prepareTiles","eachCell","mergedFrom","savePosition","moveTile","cell","updatePosition","direction","self","vector","getVector","traversals","buildTraversals","moved","forEach","cellContent","positions","findFarthestPosition","next","merged","removeTile","farthest","positionsEqual","movesAvailable","pos","push","reverse","previous","withinBounds","cellAvailable","tileMatchesAvailable","other","first","second"],"version":3,"file":"index.1df39ad2.js.map"}