initial commit of poker game
This commit is contained in:
470
game-server/app/game/player.js
Normal file
470
game-server/app/game/player.js
Normal file
@@ -0,0 +1,470 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var Hand = require('./hand');
|
||||
|
||||
|
||||
module.exports = Player = function(playerName, chips, uid, table){
|
||||
this.playerName = playerName;
|
||||
this.id = uid;
|
||||
this.chips = chips;
|
||||
this.folded = false;
|
||||
this.allIn = false;
|
||||
this.talked = false;
|
||||
this.table = table; //Circular reference to allow reference back to parent object.
|
||||
this.cards = [];
|
||||
}
|
||||
|
||||
Player.prototype.GetChips = function(cash){
|
||||
this.chips += cash;
|
||||
};
|
||||
|
||||
Player.prototype.Check = function(){
|
||||
var checkAllow, v, i;
|
||||
checkAllow = true;
|
||||
for(v=0;v<this.table.game.bets.length;v += 1){
|
||||
if(this.table.game.bets[v] !== 0){
|
||||
checkAllow = false;
|
||||
}
|
||||
}
|
||||
if(checkAllow){
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
this.table.game.bets[i] = 0;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "check", playerName: this.playerName};
|
||||
this.table.actions.push(this.turnBet);
|
||||
progress(this.table);
|
||||
}else{
|
||||
logger.debug('check-not-allowed by '+this.id);
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.Fold = function(){
|
||||
var i, bet;
|
||||
//Move any current bet into the pot
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this.id === this.table.players[i].id){
|
||||
bet = parseInt(this.table.game.bets[i], 10);
|
||||
this.table.game.roundBets[i] += bet;
|
||||
this.table.game.bets[i] = 0;
|
||||
this.table.game.pot += bet;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
//Mark the player as folded
|
||||
this.folded = true;
|
||||
this.turnBet = {action: "fold", playerName: this.playerName};
|
||||
this.table.actions.push(this.turnBet);
|
||||
// attempt to progress the game
|
||||
progress(this.table);
|
||||
};
|
||||
|
||||
Player.prototype.Bet = function(bet){
|
||||
var i = this.getIndex();
|
||||
var maxBet = getMaxBet(this.table.game.bets);
|
||||
var totalBet = bet + maxBet;
|
||||
var currentBet = this.table.game.bets[i];
|
||||
if((currentBet + this.chips) > totalBet){
|
||||
this.table.players[i].chips -= (totalBet - currentBet);
|
||||
this.table.game.bets[i] = totalBet; // this.table.game.bets[i] += totalBet;
|
||||
this.talked = true;
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "bet", playerName: this.playerName, amount: totalBet};
|
||||
this.table.actions.push(this.turnBet);
|
||||
progress(this.table);
|
||||
}else{
|
||||
logger.debug('forced-all-in: '+this.id);
|
||||
this.AllIn();
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.getIndex = function(){
|
||||
var index;
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
Player.prototype.Call = function(){
|
||||
var maxBet, i;
|
||||
// console.log('bets', this.table.game.bets);
|
||||
maxBet = getMaxBet(this.table.game.bets);
|
||||
if(this.chips > maxBet){
|
||||
// console.log('higher chips', this.chips, maxBet);
|
||||
//Match the highest bet
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
if(this.table.game.bets[i] >= 0){
|
||||
this.chips += this.table.game.bets[i];
|
||||
}
|
||||
this.chips -= maxBet;
|
||||
this.table.game.bets[i] = maxBet;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "call", playerName: this.playerName, amount: maxBet};
|
||||
this.table.actions.push(this.turnBet);
|
||||
progress(this.table);
|
||||
}else{
|
||||
logger.debug('forced-all-in: '+this.id);
|
||||
this.AllIn();
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.AllIn = function(){
|
||||
var i, allInValue=0;
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
if(this.table.players[i].chips !== 0){
|
||||
allInValue = this.table.players[i].chips;
|
||||
this.table.game.bets[i] += this.table.players[i].chips;
|
||||
this.table.players[i].chips = 0;
|
||||
|
||||
this.allIn = true;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "allin", playerName: this.playerName, amount: allInValue};
|
||||
this.table.actions.push(this.turnBet);
|
||||
|
||||
progress(this.table);
|
||||
};
|
||||
|
||||
function progress(table){
|
||||
var i, j, cards, hand;
|
||||
if(table.game){
|
||||
table.eventEmitter.emit("turnEnd");
|
||||
table.stopTimer();
|
||||
if(checkForEndOfGame(table)){
|
||||
//Move all bets to the pot
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.pot += parseInt(table.game.bets[i], 10);
|
||||
table.game.roundBets[i] += parseInt(table.game.bets[i], 10);
|
||||
}
|
||||
completeGame(table);
|
||||
return;
|
||||
}
|
||||
if(checkForEndOfRound(table) === true){
|
||||
//Move all bets to the pot
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.pot += parseInt(table.game.bets[i], 10);
|
||||
table.game.roundBets[i] += parseInt(table.game.bets[i], 10);
|
||||
}
|
||||
if(table.game.roundName === 'River'){
|
||||
completeGame(table);
|
||||
return;
|
||||
}else if(table.game.roundName === 'Turn'){
|
||||
table.game.roundName = 'River';
|
||||
table.game.deck.pop(); //Burn a card
|
||||
table.game.board.push(table.game.deck.pop()); //Turn a card
|
||||
//table.game.bets.splice(0,table.game.bets.length-1);
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.bets[i] = 0;
|
||||
}
|
||||
for(i=0;i< table.players.length;i+=1){
|
||||
table.players[i].talked = false;
|
||||
}
|
||||
table.eventEmitter.emit( "deal" );
|
||||
}else if(table.game.roundName === 'Flop'){
|
||||
table.game.roundName = 'Turn';
|
||||
table.game.deck.pop(); //Burn a card
|
||||
table.game.board.push(table.game.deck.pop()); //Turn a card
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.bets[i] = 0;
|
||||
}
|
||||
for(i=0;i< table.players.length;i+=1){
|
||||
table.players[i].talked = false;
|
||||
}
|
||||
table.eventEmitter.emit( "deal" );
|
||||
}else if(table.game.roundName === 'Deal'){
|
||||
table.game.roundName = 'Flop';
|
||||
table.game.deck.pop(); //Burn a card
|
||||
for(i=0;i< 3;i+=1){ //Turn three cards
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
//table.game.bets.splice(0,table.game.bets.length-1);
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.bets[i] = 0;
|
||||
}
|
||||
for(i=0;i< table.players.length;i+=1){
|
||||
table.players[i].talked = false;
|
||||
}
|
||||
table.eventEmitter.emit( "deal" );
|
||||
}
|
||||
table.currentPlayer = getNextAvailablePlayer(table, table.startIndex, table.players.length);
|
||||
if(typeof table.currentPlayer !== 'number' && table.game.roundName !== 'GameEnd'){
|
||||
console.log('ALL IN GAME');
|
||||
completeBoard(table);
|
||||
return progress(table);
|
||||
}
|
||||
}
|
||||
table.eventEmitter.emit("turnStart");
|
||||
}
|
||||
}
|
||||
|
||||
function completeGame(table){
|
||||
table.game.roundName = 'GameEnd';
|
||||
table.game.bets.splice(0, table.game.bets.length);
|
||||
//Evaluate each hand
|
||||
for(j = 0; j < table.players.length; j += 1){
|
||||
cards = table.players[j].cards.concat(table.game.board);
|
||||
table.players[j].hand = new Hand(cards);
|
||||
}
|
||||
console.log('checkForWinner', table);
|
||||
checkForWinner(table);
|
||||
table.eventEmitter.emit('gameOver');
|
||||
}
|
||||
|
||||
function completeBoard(table){
|
||||
var i;
|
||||
if(table.game.board.length == 0){
|
||||
table.game.deck.pop();
|
||||
for(i=0;i<3;i+=1){
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
}
|
||||
if(table.game.board.length == 3){
|
||||
table.game.deck.pop();
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
if(table.game.board.length == 4){
|
||||
table.game.deck.pop();
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxBet(bets){
|
||||
var maxBet, i;
|
||||
maxBet = 0;
|
||||
for(i=0;i< bets.length;i+=1){
|
||||
if(bets[i] > maxBet){
|
||||
maxBet = bets[i];
|
||||
}
|
||||
}
|
||||
return maxBet;
|
||||
}
|
||||
|
||||
function checkForEndOfGame(table){
|
||||
var notFolded = [], allInPlayer = [], actionablePlayer = [], i;
|
||||
for(i = 0; i < table.players.length;i+=1){
|
||||
if(table.players[i].folded === false){
|
||||
notFolded.push(i);
|
||||
}
|
||||
if(table.players[i].allIn === true){
|
||||
allInPlayer.push(i);
|
||||
}
|
||||
if(table.players[i].folded === false && table.players[i].allIn === false){
|
||||
actionablePlayer.push(i);
|
||||
}
|
||||
}
|
||||
if(allInPlayer.length > 1){
|
||||
completeBoard(table);
|
||||
}
|
||||
return (notFolded.length === 1 || actionablePlayer.length === 0);
|
||||
}
|
||||
|
||||
function checkForEndOfRound(table){
|
||||
var endOfRound = true;
|
||||
var nextPlayer = getNextAvailablePlayer(table, (table.currentPlayer + 1), table.players.length);
|
||||
if(typeof nextPlayer === 'number'){
|
||||
table.currentPlayer = nextPlayer;
|
||||
endOfRound = false;
|
||||
}
|
||||
return endOfRound;
|
||||
}
|
||||
|
||||
function getNextAvailablePlayer(table, playerIndex, len, ctr){
|
||||
ctr = ctr || 0;
|
||||
var maxBet = getMaxBet(table.game.bets);
|
||||
var nextPlayer;
|
||||
if(playerIndex === len){
|
||||
playerIndex = 0;
|
||||
}
|
||||
if(table.players[playerIndex].folded === false && (table.players[playerIndex].talked === false || table.game.bets[playerIndex] !== maxBet) && table.players[playerIndex].allIn === false){
|
||||
nextPlayer = playerIndex;
|
||||
}
|
||||
ctr += 1;
|
||||
playerIndex += 1;
|
||||
if(typeof nextPlayer !== 'number' && ctr !== len){
|
||||
nextPlayer = getNextAvailablePlayer(table, playerIndex, len, ctr);
|
||||
}
|
||||
return nextPlayer;
|
||||
}
|
||||
|
||||
function checkForAllInPlayer(table, winners){
|
||||
var i, allInPlayer;
|
||||
allInPlayer = [];
|
||||
for(i=0;i< winners.length;i+=1){
|
||||
if(table.players[winners[i]].allIn === true){
|
||||
allInPlayer.push(winners[i]);
|
||||
}
|
||||
}
|
||||
return allInPlayer;
|
||||
}
|
||||
|
||||
function checkForWinner(table){
|
||||
var i, j, k, l, maxRank, notFolded, winners, part, prize, allInPlayer, minBets, roundEnd;
|
||||
//Identify winner(s)
|
||||
winners = [];
|
||||
notFolded = [];
|
||||
maxRank = 0.000;
|
||||
for(k = 0; k < table.players.length; k += 1){
|
||||
if(table.players[k].folded === false){
|
||||
notFolded.push(k);
|
||||
}
|
||||
if(table.players[k].hand.rank === maxRank && table.players[k].folded === false){
|
||||
winners.push(k);
|
||||
}
|
||||
if(table.players[k].hand.rank > maxRank && table.players[k].folded === false){
|
||||
maxRank = table.players[k].hand.rank;
|
||||
winners.splice(0, winners.length);
|
||||
winners.push(k);
|
||||
}
|
||||
}
|
||||
// handle mid-round fold
|
||||
if(winners.length === 0 && notFolded.length == 1){
|
||||
console.log('mid round fold');
|
||||
winners.push(notFolded[0]);
|
||||
}
|
||||
part = 0;
|
||||
prize = 0;
|
||||
console.log('roundBets', table.game.roundBets);
|
||||
allInPlayer = checkForAllInPlayer(table, winners);
|
||||
if(allInPlayer.length > 0){
|
||||
minBets = table.game.roundBets[winners[0]];
|
||||
for(j = 1; j < allInPlayer.length; j += 1){
|
||||
if(table.game.roundBets[winners[j]] !== 0 && table.game.roundBets[winners[j]] < minBets){
|
||||
minBets = table.game.roundBets[winners[j]];
|
||||
}
|
||||
}
|
||||
part = parseInt(minBets, 10);
|
||||
}else{
|
||||
part = parseInt(table.game.roundBets[winners[0]], 10);
|
||||
}
|
||||
console.log('part', part);
|
||||
for(l = 0; l < table.game.roundBets.length; l += 1){
|
||||
// handle user leave
|
||||
// console.log('more than 1 player', table.players.length > 1 && (table.players.length - table.playersToRemove.length > 1));
|
||||
if(table.game.roundBets[l] > part){
|
||||
prize += part;
|
||||
table.game.roundBets[l] -= part;
|
||||
}else{
|
||||
prize += table.game.roundBets[l];
|
||||
table.game.roundBets[l] = 0;
|
||||
}
|
||||
}
|
||||
console.log('prize', prize);
|
||||
console.log('winners', winners);
|
||||
|
||||
if(prize > 0){
|
||||
var remainder = prize % winners.length;
|
||||
var winnerHands = [];
|
||||
var highestIndex;
|
||||
var winnerPrize = Math.floor(prize / winners.length);
|
||||
if(remainder !== 0){
|
||||
console.log('chip remainder of '+remainder);
|
||||
for(i=0;i<winners.length;++i){
|
||||
winnerHands.push(table.players[winners[i]].cards);
|
||||
}
|
||||
highestIndex = getOddChipWinner(winnerHands);
|
||||
}
|
||||
|
||||
for(i=0;i<winners.length;++i){
|
||||
var winningPlayer = table.players[winners[i]];
|
||||
if(i === highestIndex){
|
||||
winnerPrize += remainder;
|
||||
console.log('player '+winningPlayer.playerName+' gets the remaining '+remainder+' chips');
|
||||
}
|
||||
winningPlayer.chips += winnerPrize;
|
||||
if(table.game.roundBets[winners[i]] === 0){
|
||||
winningPlayer.folded = true;
|
||||
table.gameWinners.push({
|
||||
playerName: winningPlayer.playerName,
|
||||
id: winningPlayer.id,
|
||||
amount: winnerPrize,
|
||||
hand: winningPlayer.hand,
|
||||
chips: winningPlayer.chips
|
||||
});
|
||||
}
|
||||
logger.debug('player '+table.players[winners[i]].playerName+'('+table.players[winners[i]].id+') wins '+winnerPrize+' chips');
|
||||
if(i === highestIndex)
|
||||
winnerPrize -= remainder;
|
||||
}
|
||||
}
|
||||
roundEnd = true;
|
||||
console.log('roundBets', table.game.roundBets);
|
||||
for(l = 0; l < table.game.roundBets.length;l+=1){
|
||||
if(table.game.roundBets[l] !== 0){
|
||||
roundEnd = false;
|
||||
}
|
||||
}
|
||||
if(roundEnd === false){
|
||||
checkForWinner(table);
|
||||
}
|
||||
}
|
||||
|
||||
function checkForBankrupt(table){
|
||||
var i;
|
||||
for(i=0;i<table.players.length;i+= 1){
|
||||
if(table.players[i].chips === 0){
|
||||
table.gameLosers.push(table.players[i]);
|
||||
logger.debug('player '+table.players[i].playerName+'('+table.players[i].id+') went bankrupt');
|
||||
// table.players.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getOddChipWinner(hands){
|
||||
var i, highestIndex, highestAmt = 0;
|
||||
console.log('getOddChipWinner', hands);
|
||||
for(i=0;i<hands.length;++i){
|
||||
var hand = hands[i];
|
||||
var rank1 = getCardRank(hand[0]);
|
||||
var rank2 = getCardRank(hand[1]);
|
||||
if(highestAmt < rank1){
|
||||
highestAmt = rank1;
|
||||
highestIndex = i;
|
||||
}
|
||||
if(highestAmt < rank2){
|
||||
highestAmt = rank2;
|
||||
highestIndex = i;
|
||||
}
|
||||
}
|
||||
console.log('odd chip owner result: '+highestIndex+' '+highestAmt);
|
||||
return highestIndex;
|
||||
}
|
||||
|
||||
function getCardRank(card){
|
||||
var rank = 0;
|
||||
switch(card[0]){
|
||||
case 'A': rank += 130; break;
|
||||
case 'K': rank += 120; break;
|
||||
case 'Q': rank += 110; break;
|
||||
case 'J': rank += 100; break;
|
||||
case 'T': rank += 90; break;
|
||||
case '9': rank += 80; break;
|
||||
case '8': rank += 70; break;
|
||||
case '7': rank += 60; break;
|
||||
case '6': rank += 50; break;
|
||||
case '5': rank += 40; break;
|
||||
case '4': rank += 30; break;
|
||||
case '3': rank += 20; break;
|
||||
case '2': rank += 10; break;
|
||||
}
|
||||
switch(card[1]){
|
||||
case 'S': rank += 4; break;
|
||||
case 'H': rank += 3; break;
|
||||
case 'D': rank += 2; break;
|
||||
case 'C': rank += 1; break;
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
Reference in New Issue
Block a user