game.js | |
---|---|
var _ = require('underscore'),
Backbone = require('backbone'),
Board = require('./board'),
CommonGame = require('../common/game'); | |
extend for client'ness | var Game = module.exports = CommonGame.extend({
initialize:function(attrs) { |
super | CommonGame.prototype.initialize.apply(this, arguments);
this.gameClientId = Math.round(Math.random() * 100000);
console.log('oPlayer', this.get('oPlayerId')); |
nest models as POJSOs | this.board = new Board();
this.moves = [] |
when the game is created, the only player I know about it me | this.me = attrs.me; |
xPlayer goes first | this.set('activePlayerId', this.get('xPlayerId')); |
any time the next move changes, update the game | var self = this;
this.on('change:nextMove', function() { |
every game instance updates itself attenuate self notifications | if (this.get('nextMove').gameClientId == this.gameClientId){ |
broadcast this game's lastMove change | console.log('calling save');
self.save();
}
|
propogate changes in this game | self.updateGame();
});
},
isValidNextMove: function(nextMove) { |
need to players to move handles the case when tries to move before the game is joined | if (!this.get('xPlayerId') || !this.get('oPlayerId')) {
console.error('two players not present');
return false;
} |
if there is a winner, game is over | if (this.get('winnerId')) {
return false;
} |
insure players always take their turn | if (nextMove.playerId != this.get('activePlayerId')){
console.error('out of turn next - move player:', nextMove.playerId, ' active player: ', this.get('activePlayerId'));
return false;
}
if (!this.board.isCellAvailable()){
console.info('no available cell');
return false;
}
return true;
}, |
imperative wrapper for set('nextMove',move) | move:function(row, col, playerId){
var nextMove = {gameClientId: this.gameClientId,
playerId: playerId,
row: row, col: col};
if (this.isValidNextMove(nextMove)){ |
nextMoves come from UI or server | this.set('nextMove', nextMove);
}
},
isWinningMove:function(){ |
search for win by rows | var symbol = null;
for (var row = 0; row < (this.board.dimension-1); row++){
symbol = this.board.getCell(row,0);
var col = 1;
while(symbol && (symbol == this.board.getCell(row, col)) &&
(col < this.board.dimension)) {
if (col == (this.board.dimension-1)) { |
got a winner by row win | return true;
}
col++
}
} |
search for win by columns | for (col = 0; col < (this.board.dimension-1); col++){
symbol = this.board.getCell(0,col);
row = 1;
while(symbol && (symbol == this.board.getCell(row, col)) &&
(row < this.board.dimension)) {
if (row == (this.board.dimension-1)) { |
got a winner by row win | return true;
}
row++
}
} |
search for win by diagnals 1eft to right start at l/t | symbol = this.board.getCell(0,0);
var i = 1;
while (symbol && (symbol == this.board.getCell(i,i))){
if (i == (this.board.dimension-1)) { |
got a winner by diagnal win | return true;
}
i++;
} |
right to left, start at r/t | symbol = this.board.getCell(2,2);
i = 1;
while (symbol && (symbol == this.board.getCell(i,i))){
if (i == (this.board.dimension-1)) { |
got a winner by diagnal win | return true;
}
i--;
}
return false;
},
updateGame: function(){ |
play the next move | var nextMove = this.get('nextMove'); |
keep our move log | this.moves.push(nextMove);
var symbol = '';
if (nextMove.playerId == this.get('xPlayerId')) {
symbol = 'X';
} else {
symbol = 'O';
} |
Mark it O Smokey!! (or X) | console.log('updateGame - last move', nextMove.row, nextMove.col ,symbol);
this.board.setCell(nextMove.row, nextMove.col, symbol); |
when winning move activePlayer | this.set('winnerId', this.isWinningMove() ? this.get('activePlayerId') : null); |
if no winner, toggle the player for next turn | if (!this.get('winnerId')) { |
toggle the active player | this.set('activePlayerId',
(nextMove.playerId == this.get('xPlayerId')) ?
this.get('oPlayerId') :
this.get('xPlayerId'));
} |
signal that the game state has been updated, this is a custom event as it distinguishes from 'change' events that would be triggered off model changes like active state change | this.trigger('gameUpdate');
},
dumpGame: function() {
console.info('game state change');
this.board.dumpBoard();
console.info('active player', this.get('activePlayerId'));
if (this.get('winnerId')) {
console.log('winner', this.get('winnerId'));
} else {
console.log('no winner');
}
},
toJSON: function() { |
super | var json = CommonGame.prototype.toJSON.apply(this, arguments); |
don't sync the client computed values |
delete json.activePlayerId;
delete json.winnerId;
|
special case: indicates issue with modeling in intial unjoined game state, send else remove meId | if (this.get('xPlayerId') && this.get('oPlayerId')){
delete json.meId;
}
return json;
}, |
overide parse function | parse:function(attrs) { |
super | var parsed = CommonGame.prototype.parse.apply(this, arguments); |
we only sync the next move | |
state the client game computes | parsed.meId = this.get('meId');
parsed.winner = this.get('winnerId');
return parsed;
}
});
|