function GameManager(size, InputManager, Actuator) { this.size = size; // Size of the grid this.inputManager = new InputManager; this.actuator = new Actuator; this.startTiles = 2; this.grid = new Grid(this.size); this.inputManager.on("move", this.move.bind(this)); this.setup(); } // Set up the game GameManager.prototype.setup = function () { this.addStartTiles(); // Update the actuator this.actuate(); }; // Set up the initial tiles to start the game with GameManager.prototype.addStartTiles = function () { for (var i = 0; i < this.startTiles; i++) { this.addRandomTile(); } }; // Adds a tile in a random position GameManager.prototype.addRandomTile = function () { if (this.grid.cellsAvailable()) { var value = Math.random() < 0.9 ? 2 : 4; var tile = new Tile(this.grid.randomAvailableCell(), value); this.grid.insertTile(tile); } }; // Sends the updated grid to the actuator GameManager.prototype.actuate = function () { this.actuator.actuate(this.grid); }; // Saves all the current tile positions GameManager.prototype.saveTilePositions = function () { this.grid.eachCell(function (x, y, tile) { if (tile) { tile.savePosition(); } }); }; // Move a tile and its representation GameManager.prototype.moveTile = function (tile, cell) { this.grid.cells[tile.x][tile.y] = null; this.grid.cells[cell.x][cell.y] = tile; tile.x = cell.x; tile.y = cell.y; }; // Move tiles on the grid in the specified direction GameManager.prototype.move = function (direction) { // 0: up, 1: right, 2:down, 3: left var self = this; var cell, tile; var vector = this.getVector(direction); var traversals = this.buildTraversals(vector); // Save the current tile positions (for actuator awareness) this.saveTilePositions(); // Traverse the grid in the right direction and move tiles traversals.x.forEach(function (x) { traversals.y.forEach(function (y) { cell = { x: x, y: y }; tile = self.grid.cellContent(cell); if (tile) { var pos = self.findFarthestPosition(cell, vector); self.moveTile(tile, pos); } }); }); this.addRandomTile(); this.actuate(); }; // Get the vector representing the chosen direction GameManager.prototype.getVector = function (direction) { // Vectors representing tile movement var map = { 0: { x: 0, y: -1 }, // up 1: { x: 1, y: 0 }, // right 2: { x: 0, y: 1 }, // down 3: { x: -1, y: 0 } // left }; return map[direction]; }; // Build a list of positions to traverse in the right order GameManager.prototype.buildTraversals = function (vector) { var traversals = { x: [], y: [] }; for (var pos = 0; pos < this.size; pos++) { traversals.x.push(pos); traversals.y.push(pos); } // Always traverse from the farthest cell in the chosen direction if (vector.x === 1) traversals.x = traversals.x.reverse(); if (vector.y === 1) traversals.y = traversals.y.reverse(); return traversals; }; GameManager.prototype.findFarthestPosition = function (cell, vector) { var previous; // Progress towards the vector direction until an obstacle is found do { previous = cell; cell = { x: previous.x + vector.x, y: previous.y + vector.y }; } while (cell.x >= 0 && cell.x < this.size && cell.y >= 0 && cell.y < this.size && this.grid.cellAvailable(cell)); return previous; };