Skip to content
Open

Ai #106

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions src/checkers/checkers_game.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ function CheckersGame(board) {
this.moveEvaluationType = TableTop.Constants.moveEvalationTypeGameEvaluator;
this.possibleNumPlayers = [2];
this.showNextPlayerScreen = false;
this.AIDifficulty = TableTop.Constants.AIDifficultyHard;
this.hasMadeGame = false;
this.firstMove = true;
};

inherits(CheckersGame, TableTop.Game);

CheckersGame.prototype.createPlayer = function(name) {
Expand Down Expand Up @@ -166,15 +168,14 @@ CheckersGame.prototype.isValidMove = function(token, oldTile, newTile) {
it's not a valid move!
*/

var p = this.getPlayerForToken(token);

var p = this.getPlayerForToken(token);
if (this.getPlayerForToken(token) != player ||
newTile.color != TableTop.Constants.redColor ||
newTile.tokens[0]) {

return false;
}

return this.validNormalMove(token, oldPos, newPos, 1) ||
this.validJumpMove(token, oldPos, newPos);
};
Expand Down Expand Up @@ -209,4 +210,43 @@ CheckersGame.prototype.playerDidWin = function(player) {
};


// returns all possible valid moves
CheckersGame.prototype.getValidMoves = function() {

var validMoves = [];

this.board.tokens.forEach(function(token) {

var tile = this.board.findTileForToken(token);

// for each possible destination tile...
this.board.tiles.forEach(function(destinationRow) {
destinationRow.forEach(function(destination) {

if (this.isValidMove(token, tile, destination)) {
validMoves.push({
token: token,
tile: tile,
destination: destination
});
}

}, this);
}, this);
}, this);


return validMoves;
};


// takes in a player
// returns the score for the board based on the player passed in (ie. if the player
// has won it should return 10, if he loses should return -10)
CheckersGame.prototype.scoreBoard = function() {
var otherPlayer = this.players[this.getNextPlayer()];
return 12 - otherPlayer.tokens.length;
};


module.exports = CheckersGame;
48 changes: 24 additions & 24 deletions src/checkers/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,34 @@ form {
}

select {
background: #FFE064;
width: 5%;
padding: 20px;
font-size: 4vw;
line-height: 1;
border: 0;
border-radius: 0;
height: 15%;
text-align: center;
background: #FFE064;
width: 5%;
padding: 20px;
font-size: 4vw;
line-height: 1;
border: 0;
border-radius: 0;
height: 15%;
text-align: center;
}

input {
background: #FFE064;
width: 15%;
padding: 10px;
font-size: 3vw;
line-height: 1;
border: 0;
border-radius: 0;
height: 15%;
text-align: center;
border-radius: 20px;
background: #FFE064;
width: 15%;
padding: 10px;
font-size: 3vw;
line-height: 1;
border: 0;
border-radius: 0;
height: 15%;
text-align: center;
border-radius: 20px;
}

canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}*/
70 changes: 70 additions & 0 deletions tabletop/core/aiplayer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
var inherits = require('util').inherits;
var Player = require("./Player.js");
var Gridboard = require("./grid_board.js");
var c = require("./ttConstants");

/**
* AI Player
* @constructor
* @extends {Player}
* @param {string} difficulty - difficulty of AI. Should be one of the values of TableTop.Constants.validAIDifficulties.
*/

function AIPlayer(name, color, id, difficulty) {
Player.call(this, name, color, id);

// safety check
if (c.validAIDifficulties.indexOf(difficulty) == -1)
difficulty = c.AIDifficultyEasy;

this.difficulty = difficulty;
}

inherits(AIPlayer, Player);


AIPlayer.prototype.isAI = function() {
return true;
};


AIPlayer.prototype.generateMove = function(game) {

var moves = game.getValidMoves();
var results = [];

moves.forEach(function(move) {

var gameCopy = game.copyGameStatus(game);
gameCopy.proposedMove = game.copyMoveForGame(move, gameCopy);
gameCopy.executeMove();
results.push({
move: move,
score: gameCopy.scoreBoard()
});
});

var result = this.pickMove(results);
return result.move;
};

AIPlayer.prototype.pickMove = function(results) {

// sort descending based on score
var resultsSorted = results.sort(function(a, b) {
return b.score - a.score;
});

var range;
if (this.difficulty == c.AIDifficultyHard) {
range = 1;
} else if (this.difficulty == c.AIDifficultyMedium) {
range = Math.min(results.length, 3);
} else if (this.difficulty == c.AIDifficultyEasy) {
range = Math.min(results.length, 5);
}

return resultsSorted[Math.floor(Math.random()*range)];
};

module.exports = AIPlayer;
12 changes: 6 additions & 6 deletions tabletop/core/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ Component.prototype.subscribe = function(callback) {
* @return {void}
*/
Component.prototype.propagate = function(child) {
var context = this;
child.subscribe(function(messageObj) {
context.sendMessage(messageObj.text, messageObj.type, messageObj.sender, messageObj.clientID);
});
}
var context = this;
child.subscribe(function(messageObj) {
context.sendMessage(messageObj.text, messageObj.type, messageObj.sender, messageObj.clientID);
});
};

module.exports = Component;
module.exports = Component;
113 changes: 112 additions & 1 deletion tabletop/core/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ var ManualTurn = require("./manual_turn.js");
var Component = require("./component.js");
var inherits = require('util').inherits;
var _ = require('lodash');
var Tile = require('./tile.js');
var Token = require('./token.js');
var Player = require('./player.js');
var Gridboard = require('./grid_board.js');

/**
* The Game class
Expand All @@ -23,6 +27,7 @@ function Game(board) {
this.showNextPlayerScreen = true;
this.playerColors = [0xFF0000, 0x000000, 0x00FF00, 0x0000FF, 0xFF00FF];
this.currentPlayer = 0;
this.AIDifficulty = c.AIDifficultyEasy;
this.gameID = null;
this.clientPlayerID = -1; // id of the player of THIS client
};
Expand Down Expand Up @@ -268,6 +273,15 @@ Game.prototype.nextPlayer = function() {
this.currentPlayer = (this.currentPlayer + 1) % this.players.length;
};

/**
* Returns the next player, but does not switch like nextPlayer does
* Override to provide more logic on determining the next player
* @returns {int} The index of the next player.
*/
Game.prototype.getNextPlayer = function() {
return (this.currentPlayer + 1) % this.players.length;
};

/**
* Set the destination for a proposed move
* @param {Tile} tile - the tile to move to
Expand Down Expand Up @@ -403,4 +417,101 @@ Game.prototype.destroyToken = function(token) {
this.board.destroyToken(token);
};

module.exports = Game;

// Create copy of game and manually copy over
// tiles/tokens to remove references
Game.prototype.copyGameStatus = function(game) {

//var newGame = $.extend(true, {}, game);
var newGame = Object.create(this);
newGame.board = Object.create(this.board);
newGame.board.tokens = [];
newGame.board.tiles = [];
newGame.players = [];
var i, j = 0;

// copy players, clear token arrays
for (i = 0; i < game.players.length; i++) {
newGame.players.push(new Player());
Object.assign(newGame.players[i], game.players[i]);
newGame.players[i].tokens = [];
}

// copy tiles, clear token arrays
if (game.board instanceof Gridboard) {
for (i = 0; i < game.board.tiles.length; i++) {
newGame.board.tiles.push([]);
for (j = 0; j < game.board.tiles[i].length; j++) {
newGame.board.tiles[i].push(new Tile({}));
Object.assign(newGame.board.tiles[i][j], game.board.tiles[i][j]);
newGame.board.tiles[i][j].clearTokens();
}
}
} else {
for (i = 0; i < game.board.tiles.length; i++) {
newGame.board.tiles.push(new Tile({}));
Object.assign(newGame.board.tiles[i], game.board.tiles[i]);
newGame.board.tiles[i].clearTokens();
}
}

// copy tokens, and assign to proper tile and player
for (i = 0; i < game.board.tokens.length; i++) {
var token = game.board.tokens[i];
newGame.board.tokens.push(new Token());
var newToken = newGame.board.tokens[i];
Object.assign(newToken, token);

// assign tile to proper player if it's owned, or do nothing
for (j = 0; j < game.players.length; j++) {
if (game.players[j].tokens.indexOf(token) >= 0) {
newGame.players[j].tokens.push(newToken);
}
}

// if a token is on a tile, add it to the tile's list of tokens
var tile = game.board.findTileForToken(token);
var tilePos = game.board.getTilePosition(tile);
if (!tile || !tilePos) continue;

if (game.board instanceof Gridboard)
newGame.board.tiles[tilePos.x][tilePos.y].addToken(newGame.board.tokens[i]);
else
newGame.board.tiles[tilePos].addToken(newGame.board.tokens[i]);

}

return newGame;
};

Game.prototype.copyMoveForGame = function(move, gameCopy) {

var newMove = {};
Object.keys(move).forEach(function(key) {

var obj = move[key];
if (obj instanceof Token) {
var tokenIdx = this.board.tokens.indexOf(obj);
var tokenCp = gameCopy.board.tokens[tokenIdx];
newMove[key] = tokenCp;
} else if (obj instanceof Tile) {
var tilePos = this.board.getTilePosition(obj);
var tileCp;
if (this.board instanceof Gridboard)
tileCp = gameCopy.board.tiles[tilePos.x][tilePos.y];
else
tileCp = gameCopy.board.tiles[tilePos];

newMove[key] = tileCp;
}
}, this);

return newMove;
};

Game.prototype.getValidMoves = function() {
return [];
};


module.exports = Game;
3 changes: 2 additions & 1 deletion tabletop/core/grid_board.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function GridBoard(width, height) {
Board.call(this);
for (var i = 0; i < width; i++) {
this.tiles[i] = Array(this.height);
}
}

this.width = width;
this.height = height;
Expand Down Expand Up @@ -69,6 +69,7 @@ GridBoard.prototype.moveTokenToTile = function(token, tile) {
GridBoard.prototype.destroyToken = function(token) {
var tile = this.findTileForToken(token);
tile.removeToken(token);
token.isDead = true;
};

module.exports = GridBoard;
2 changes: 1 addition & 1 deletion tabletop/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var core = Object.assign({
NextPlayerView: require('./next_player_view'),
Player: require('./player'),
StartView: require('./start_view'),
StyleSheets: require('../../src/checkers/style.css'),
// StyleSheets: require('../../src/checkers/style.css'),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewjmeier I still can't run webpack with this line not commented. I didn't want to uncomment and merge when i haven't tested it, so wasn't sure what to do with this line

Tile: require('./tile'),
Token: require('./token'),
Trade: require('./trade'),
Expand Down
Loading