- function GameManager(size, InputManager, Actuator, StorageManager) {
- this.size = size; // Size of the grid
- this.inputManager = new InputManager;
- this.storageManager = new StorageManager;
- this.actuator = new Actuator;
- this.startTiles = 2;
- this.inputManager.on("move", this.move.bind(this));
- this.inputManager.on("restart", this.restart.bind(this));
- this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
- this.setup();
- }
- // Restart the game
- GameManager.prototype.restart = function () {
- this.storageManager.clearGameState();
- this.actuator.continue(); // Clear the game won/lost message
- this.setup();
- };
- // Keep playing after winning (allows going over 2048)
- GameManager.prototype.keepPlaying = function () {
- this.keepPlaying = true;
- this.actuator.continue(); // Clear the game won/lost message
- };
- // Return true if the game is lost, or has won and the user hasn't kept playing
- GameManager.prototype.isGameTerminated = function () {
- if (this.over || (this.won && !this.keepPlaying)) {
- return true;
- } else {
- return false;
- }
- };
- // Set up the game
- GameManager.prototype.setup = function () {
- var previousState = this.storageManager.getGameState();
- // Reload the game from a previous game if present
- if (previousState) {
- this.grid = new Grid(previousState.grid.size,
- previousState.grid.cells); // Reload grid
- this.score = previousState.score;
- this.over = previousState.over;
- this.won = previousState.won;
- this.keepPlaying = previousState.keepPlaying;
- } else {
- this.grid = new Grid(this.size);
- this.score = 0;
- this.over = false;
- this.won = false;
- this.keepPlaying = false;
- // Add the initial tiles
- 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 () {
- if (this.storageManager.getBestScore() < this.score) {
- this.storageManager.setBestScore(this.score);
- }
- // Clear the state when the game is over (game over only, not win)
- if (this.over) {
- this.storageManager.clearGameState();
- } else {
- this.storageManager.setGameState(this.serialize());
- }
- this.actuator.actuate(this.grid, {
- score: this.score,
- over: this.over,
- won: this.won,
- bestScore: this.storageManager.getBestScore(),
- terminated: this.isGameTerminated()
- });
- };
- // Represent the current game as an object
- GameManager.prototype.serialize = function () {
- return {
- grid: this.grid.serialize(),
- score: this.score,
- over: this.over,
- won: this.won,
- keepPlaying: this.keepPlaying
- };
- };
- // Save all tile positions and remove merger info
- GameManager.prototype.prepareTiles = function () {
- this.grid.eachCell(function (x, y, tile) {
- if (tile) {
- tile.mergedFrom = null;
- 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.updatePosition(cell);
- };
- // 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;
- if (this.isGameTerminated()) return; // Don't do anything if the game's over
- var cell, tile;
- var vector = this.getVector(direction);
- var traversals = this.buildTraversals(vector);
- var moved = false;
- // Save the current tile positions and remove merger information
- this.prepareTiles();
- // 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 positions = self.findFarthestPosition(cell, vector);
- var next = self.grid.cellContent(positions.next);
- // Only one merger per row traversal?
- if (next && next.value === tile.value && !next.mergedFrom) {
- var merged = new Tile(positions.next, tile.value * 2);
- merged.mergedFrom = [tile, next];
- self.grid.insertTile(merged);
- self.grid.removeTile(tile);
- // Converge the two tiles' positions
- tile.updatePosition(positions.next);
- // Update the score
- self.score += merged.value;
- // The mighty 2048 tile
- if (merged.value === 2048) self.won = true;
- } else {
- self.moveTile(tile, positions.farthest);
- }
- if (!self.positionsEqual(cell, tile)) {
- moved = true; // The tile moved from its original cell!
- }
- }
- });
- });
- if (moved) {
- this.addRandomTile();
- if (!this.movesAvailable()) {
- this.over = true; // Game over!
- }
- this.actuate();
- }
- /******************************************/
- /******************************************/
- /* THE AI CODE STARTS FROM HERE */
- /******************************************/
- /******************************************/
- /* 0:Up
- 1:Right
- 2:Down
- 3:Left
- */
- this.isValid = function(x,y){
- if(x < 0 || x >3 || y <0 || y > 3)
- return false;
- return true;
- }
- this.moveCells = function(matrix, move){
- var dx = [-1,0,1,0];
- var dy = [0,1,0,-1];
- var nx,ny;
- for(var k = 0;k<3;k++){
- for(var i = 0;i<4;i++){
- for(var j = 0; j<4; j++){
- nx = i+dx[move];
- ny = j+dy[move];
- if(self.isValid(nx,ny)){
- if(matrix[nx][ny] == 0){
- matrix[nx][ny] = matrix[i][j];
- matrix[i][j] = 0;
- }
- }
- }
- }
- }
- for(var i = 0;i<4;i++){
- for(var j = 0; j<4; j++){
- nx = i + dx[move];
- ny = j + dy[move];
- if(self.isValid(nx,ny)){
- if(matrix[i][j] == matrix[nx][ny]){
- matrix[nx][ny] *= -2;
- matrix[i][j] = 0;
- }
- }
- }
- }
- for(var k = 0;k<3;k++){
- for(var i = 0;i<4;i++){
- for(var j = 0; j<4; j++){
- if(matrix[i][j] <0)
- matrix[i][j] *= -1;
- nx = i+dx[move];
- ny = j+dy[move];
- if(self.isValid(nx,ny)){
- if(matrix[nx][ny] == 0){
- matrix[nx][ny] = matrix[i][j];
- matrix[i][j] = 0;
- }
- }
- }
- }
- }
- return matrix;
- }
- this.evaluateMatrix = function(matrix){
- /* Count Number of Free Spaces */
- var cc = 0;
- for(var i = 0;i<4;i++)
- for(var j = 0;j<4;j++){
- if(matrix[i][j] == 0)
- cc += 100;
- else
- cc += matrix[i][j]*matrix[i][j];
- }
- return cc;
- }
- this.printMatrix = function(matrix){
- for(var i = 0;i<4;i++){
- var str = ""
- for(var j = 0;j<4;j++)
- str += matrix[i][j] + " ";
- console.log(str)
- }
- console.log("******************************");
- }
- this.findFreeCell = function(matrix){
- var i,j,k=0;
- do{
- i = (Math.floor(Math.random()*100))%4;
- j = (Math.floor(Math.random()*100))%4;
- k++;
- }while(matrix[i][j] != 0 && k != 500);
- if(matrix[i][j] != 0)
- for(i = 0;i<4;i++)
- for(j = 0;j<4;j++)
- if(matrix[i][j] == 0)
- return ({x:i, y:j});
- return ({x:i, y:j});
- }
- this.isEqualMatrix = function(m1,m2){
- for(var i = 0;i<4;i++)
- for(var j = 0;j<4;j++)
- if(m1[i][j] != m2[i][j])
- return false;
- return true;
- }
- this.minMax = function(matrix, move, depth){
- if(depth == 6)
- return 0;
- var rmatrix = self.moveCells(self.createCopy(matrix),move);
- var areSame = self.isEqualMatrix(rmatrix, matrix);
- var score = self.evaluateMatrix(rmatrix);
- if(areSame == true)
- return score-1;
- var maxVal=-1000,val,ret;
- var freeCell = self.findFreeCell(rmatrix);
- if(freeCell.x == 4 || freeCell.y == 4)
- console.log("YES VALUE IS 4 || " + freeCell.x + " | " + freeCell.y);
- rmatrix[freeCell.x][freeCell.y] = 2;
- for(var x = 0;x<4;x++)
- {
- val = this.minMax(self.createCopy(rmatrix), x, depth+1);
- if(val > maxVal)
- maxVal = val;
- }
- return (score+maxVal);
- }
- this.getMove = function(matrix){
- var maxVal = 0,val,ret;
- for(var x = 0; x < 4;x++){
- val = this.minMax(self.createCopy(matrix),x,0);
- // console.log("Score for "+ x + ":" + val )
- if(val > maxVal){
- maxVal = val;
- ret = x;
- }
- }
- return ret;
- }
- this.getMatrix = function(){
- var matrix = [];
- for (var i = 0 ; i <4 ; i++) {
- var row = [];
- for (var j = 0; j < 4; j++) {
- tile = self.grid.cellContent({x:j, y:i});
- if(tile == null)
- row.push(0);
- else
- row.push(tile["value"]);
- };
- matrix.push(row);
- };
- return matrix;
- }
- this.createCopy = function(matrix){
- var ret =[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]];
- for(var i = 0; i < 4;i++)
- for(var j = 0; j < 4; j++)
- ret[i][j] = matrix[i][j].valueOf();
- return ret;
- }
- setTimeout(function() {
- matrix = self.getMatrix();
- var myMove = self.getMove(self.createCopy(matrix));
- var rmat = self.moveCells(self.createCopy(matrix), myMove);
- console.log(myMove);
- if( self.isEqualMatrix(rmat,matrix))
- myMove = (Math.floor(Math.random()*100))%4;
- self.move(myMove);
- }, 100);
- /******************************************/
- /******************************************/
- /* THE AI CODE ENDS HERE */
- /******************************************/
- /******************************************/
- };
- // 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 (this.grid.withinBounds(cell) &&
- this.grid.cellAvailable(cell));
- return {
- farthest: previous,
- next: cell // Used to check if a merge is required
- };
- };
- GameManager.prototype.movesAvailable = function () {
- return this.grid.cellsAvailable() || this.tileMatchesAvailable();
- };
- // Check for available matches between tiles (more expensive check)
- GameManager.prototype.tileMatchesAvailable = function () {
- var self = this;
- var tile;
- for (var x = 0; x < this.size; x++) {
- for (var y = 0; y < this.size; y++) {
- tile = this.grid.cellContent({ x: x, y: y });
- if (tile) {
- for (var direction = 0; direction < 4; direction++) {
- var vector = self.getVector(direction);
- var cell = { x: x + vector.x, y: y + vector.y };
- var other = self.grid.cellContent(cell);
- if (other && other.value === tile.value) {
- return true; // These two tiles can be merged
- }
- }
- }
- }
- }
- return false;
- };
- GameManager.prototype.positionsEqual = function (first, second) {
- return first.x === second.x && first.y === second.y;
- };
Googleiani: (Ingegneria, Matematica e Informatica) nasce come blog di informazione tecnologica. All'interno di questo blog è possibile trovare articoli che riguardano molti ambiti scientifici come: matematica, fisica, informatica. Inoltre non manca la parte comica, politica e giornalistica. Googleiani è un BLOG LIBERO. Buona lettura... THINK DIFFERENT