poker-helper
Version:
utility functions for poker
977 lines (881 loc) • 32.5 kB
JavaScript
'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.isBusy = exports.isActive = undefined;var _defineProperty2 = require('babel-runtime/helpers/defineProperty');var _defineProperty3 = _interopRequireDefault(_defineProperty2);var _extends3 = require('babel-runtime/helpers/extends');var _extends4 = _interopRequireDefault(_extends3);var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);var _createClass2 = require('babel-runtime/helpers/createClass');var _createClass3 = _interopRequireDefault(_createClass2);var _assign = require('babel-runtime/core-js/object/assign');var _assign2 = _interopRequireDefault(_assign);var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
var _abPokersolver = require('ab-pokersolver');var _abPokersolver2 = _interopRequireDefault(_abPokersolver);
var _receiptCache = require('./receiptCache');var _receiptCache2 = _interopRequireDefault(_receiptCache);
var _receipt = require('./receipt');function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}
var EMPTY = '0x0000000000000000000000000000000000000000'; /* eslint-disable class-methods-use-this */
var VALUES = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'];
var SUITS = ['c', 'd', 'h', 's'];
var getPlayers = function getPlayers(helper, state, rawLineup) {var withSitouts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var lineup = withSitouts ? rawLineup : rawLineup.map(function (_ref) {var sitout = _ref.sitout,seat = (0, _objectWithoutProperties3.default)(_ref, ['sitout']);return seat;});
var players = lineup.reduce(function (list, seat, pos) {
if (seat.last) {
var last = helper.rc.get(seat.last);
var active =
state === 'showdown' && last.type === _receipt.Type.SHOW ||
state !== 'showdown' && (helper.isActivePlayer(lineup, pos) || seat.sitout === 'allin');
return [].concat((0, _toConsumableArray3.default)(list), [{ pos: pos, active: active, amount: last.amount.toNumber() }]);
}
return list;
}, []);
var activePlayers = players.filter(function (p) {return p.active;});
if (activePlayers.length === 0 && withSitouts) {
return getPlayers(helper, state, rawLineup, false);
}
return players;
};
/**
* findLatest find a receipt type used latest in an activeLineup
*
* @param lineup of type activeLineup
* @returns {{ pos: number, last: receipt }}
*/
var findLatest = function findLatest(activeLineup) {var minType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;var rc = arguments[2];
if (!activeLineup.sorted) {
throw new Error('active lineup expected.');
}
var lineup = activeLineup.lineup;
var latest = {};
for (var i = 0; i < lineup.length; i += 1) {
var lastRec = lineup[i].last ? rc.get(lineup[i].last) : null;
if (lastRec && lastRec.type >= minType && lastRec.type <= _receipt.Type.CHECK_RIVER) {
minType = lastRec.type; // eslint-disable-line no-param-reassign
latest = (0, _assign2.default)({}, { pos: i, oldPos: lineup[i].pos, last: lineup[i].last });
}
}
return latest;
};
/**
* isActive check if a seat in active
*
* @param lineup
* @param state
* @param receiptCache
* @returns bool
*/
var isActive = exports.isActive = function isActive(seat, state, rc) {
if (typeof seat === 'undefined' || seat === null) {
throw new Error('seat undefined');
}
// if we are at showdown and player is all in he is active
if (seat.sitout === 'allin' && state === 'showdown') {
return true;
}
// check seat state
if (seat.sitout || !seat.address || seat.address === EMPTY) {
return false;
}
// get last receipt
var receipt = seat.last && rc.get(seat.last);
if (!receipt || !receipt.type || !receipt.amount) {
if (state === 'waiting' || state === 'dealing') {// in waiting or dealing a player might not have a receipt yet
return true;
}
throw new Error('receipt undefined');
} else {
// check receipt type for receipts we don't want
return !(
receipt.type === _receipt.Type.FOLD ||
receipt.type === _receipt.Type.SHOW ||
receipt.type === _receipt.Type.SIT_OUT && state !== 'waiting' && state !== 'dealing');
}
};
/**
* isBusy check if a seat is busy
*
* @param lineup
* @param state
* @param receiptCache
* @returns bool
*/
var isBusy = exports.isBusy = function isBusy(seat) {
if (typeof seat === 'undefined' || seat === null) {
throw new Error('seat undefined');
}
// check seat state
if (!seat.address || seat.address === EMPTY) {
return false;
}
return true;
};
/**
* nextActive returns next active players
*
* @param lineup
* @param palyerPos as index in lineup
* @param state
* @param receiptCache
* @returns index in lineup
*/
var nextActive = function nextActive(lineup, playerPos, state, rc) {
var newPos = playerPos % lineup.length;
for (var i = newPos; i < lineup.length + newPos; i += 1) {
var pos = i % lineup.length;
if (isActive(lineup[pos], state, rc)) {
return pos;
}
}
throw new Error('no active player in lineup');
};
/**
* wasInvolved
*
* @param
* @returns
*/
var wasInvolved = function wasInvolved(seat, state) {
if (!seat) {
throw new Error('invalid lineup');
}
if (!seat.address) {
throw new Error('invalid seat');
}
// check seat state
if (seat.address === EMPTY || seat.sitout && seat.sitout !== 'allin') {
return false;
}
if (state === 'waiting' || state === 'dealing' || seat.last) {
return true;
}
return false;
};
var lineupFilters = {
active: isActive,
busy: isBusy,
involved: wasInvolved };
/**
* countPlayers counts the players in lineup
*
* @param lineup
* @param type
* @returns number of active players
*/
var countPlayers = function countPlayers(lineup, type, state, rc) {return (
lineup.
filter(function (seat) {return lineupFilters[type](seat, state, rc);}).
length);};
/**
* findNextPlayer
*
* @param
* @returns
*/
var findNextPlayer = function findNextPlayer(lineup, startPos, type, state, rc) {
var shiftPos = function shiftPos(pos) {return (startPos + pos) % lineup.length;};
var filter = lineupFilters[type];
if (!filter || lineup.length < 2) {
throw new Error('wrong state.');
}
return shiftPos(
lineup.
findIndex(function (seat, pos) {return filter(
lineup[shiftPos(pos)],
state,
rc);}));
};
/**
* findBbPos
*
* @param
* @returns
*/
var findBbPos = function findBbPos(lineup, dealer, state, type, rc) {
if (dealer === undefined || !lineup) {
throw new Error('invalid params.');
}
if (dealer < 0 || dealer >= lineup.length || lineup.length < 2) {
throw new Error('invalid more params.');
}
var lineupType = type === 'tournament' ? 'busy' : 'involved';
var next = findNextPlayer(lineup, dealer + 1, lineupType, state, rc);
if (next === dealer) {
throw new Error('only one player found.');
}
var activePlayerCount = countPlayers(lineup, lineupType, state, rc);
if (activePlayerCount === 2) {
return next;
}
var nextNext = findNextPlayer(lineup, next + 1, lineupType, state, rc);
if (nextNext === next) {
throw new Error('only one player found.');
}
return nextNext;
};
/**
* activeLineup returns normalized lineup with active players
*
* @param lineup
* @param dealer position as index to lineup
* @param state
* @returns activeLineup array
*/
var activeLineup = function activeLineup(lineup, dealer, state, rc) {
var activePlayers = [];
try {
var startPos = void 0;
if (state === 'preflop') {
// BB is last to act
try {
var bbPos = findBbPos(lineup, dealer, state, rc);
startPos = nextActive(lineup, bbPos + 1, state, rc);
} catch (err) {
// not able to find bb in lineup, not enough players?
}
}
if (state !== 'preflop' || typeof startPos === 'undefined') {
// BU is last to act
startPos = nextActive(lineup, dealer + 1, state, rc);
}
for (var i = startPos; i < lineup.length + startPos; i += 1) {
var pos = i % lineup.length;
if (isActive(lineup[pos], state, rc)) {
var player = (0, _assign2.default)({}, lineup[pos], { pos: pos });
activePlayers.push(player);
}
}
} catch (err) {
if (err.message === 'no active player in lineup') {
return [];
}
throw err;
}
return activePlayers;
};
/**
* evenLineup
*
* @param
* @returns
*/
var evenLineup = function evenLineup(lineup, rc) {
var prev = void 0;
for (var i = 0; i < lineup.length; i += 1) {
var amount = lineup[i].last ? rc.get(lineup[i].last).amount.toNumber() : 0;
if (prev !== undefined && prev !== amount) {
return false;
}
prev = amount;
}
return true;
};
/**
* countNoReceipts counts the players in lineup without receipt
*
* @param lineup
* @param type
* @returns number of active players
*/
var countNoReceipts = function countNoReceipts(lineup, rc) {return (
lineup.filter(function (seat) {return isActive(seat, 'waiting', rc) && !seat.last;}).length);};
/**
* checks if a certain type of receipt exists
*
* @param lineup
* @param rc
* @returns bool
*/
var checkForReceipt = function checkForReceipt(lineup, type, rc) {return lineup.some(function (seat) {
var receipt = seat.last ? rc.get(seat.last) : null;
return receipt && receipt.type === type;
});};
/**
* countReceipt counts receipts of type in lineup
*
* @param lineup
* @param type - as lower case
* @param rc
* @returns bool
*/
var countReceipts = function countReceipts(lineup, type, rc) {
if (!lineup) {
throw new Error('invalid lineup');
}
return lineup.filter(function (seat) {return seat.last && rc.get(seat.last).type === type;}).length;
};
/**
* maxAllIn gets the amount betted by the latest all-in
*
* @param lineup
* @returns amount of last all-in
*/
var maxAllIn = function maxAllIn(lineup, rc) {return lineup.reduce(function (maxBet, seat) {
if (seat.sitout && seat.sitout === 'allin') {
var amount = seat.last ? rc.get(seat.last).amount.toNumber() : 0;
if (amount > maxBet) {
return amount;
}
}
return maxBet;
}, 0);};var
PokerHelper = function () {
function PokerHelper(receiptCache) {(0, _classCallCheck3.default)(this, PokerHelper);
this.rc = receiptCache || new _receiptCache2.default();
}
// ########## SEAT STATE HELPERS ##########
/**
* isActivePlayer
*
* @param
* @returns
*/(0, _createClass3.default)(PokerHelper, [{ key: 'isActivePlayer', value: function isActivePlayer(
lineup, pos, state) {
if (typeof pos === 'undefined' || !lineup) {
throw new Error('lineup undefined');
}
if (pos < 0 || pos >= lineup.length || lineup.length < 2) {
throw new Error('bad param pos: ' + pos);
}
// TODO: pass correct hand state
return isActive(lineup[pos], state, this.rc);
}
/**
* inLineup
*
* @param
* @returns
*/ }, { key: 'inLineup', value: function inLineup(
signer, lineup) {
return lineup.findIndex(function (seat) {return seat.address === signer;});
}
/**
* getMyMaxBet
*
* @param
* @returns
*/ }, { key: 'getMyMaxBet', value: function getMyMaxBet(
lineup, address) {
if (!lineup || !address) {
throw new Error('invalid params.');
}
var myPos = this.getMyPos(lineup, address);
if (myPos < 0) {
throw new Error('address ' + address + ' not in lineup.');
}
var receipt = lineup[myPos].last ? this.rc.get(lineup[myPos].last) : undefined;
return receipt ? receipt.amount.toNumber() : 0;
}
/**
* getMyPos
*
* @param
* @returns
*/ }, { key: 'getMyPos', value: function getMyPos(
lineup, address) {
for (var i = 0; i < lineup.length; i += 1) {
if (lineup[i].address === address) {
return i;
}
}
throw new Error('pos of ' + address + ' not found.');
}
// ########## LINEUP STATE HELPERS ##########
/**
* findMinRaiseAmount
*
* @param
* @returns
*/ }, { key: 'findMinRaiseAmount', value: function findMinRaiseAmount(
lineup, dealer, lastRoundMaxBet, state) {
if (!lineup || dealer === undefined) {
throw new Error('invalid params.');
}
var lastRoundMaxBetInt = parseInt(lastRoundMaxBet, 10);
// TODO: pass correct state
var max = this.getMaxBet(lineup, state);
if (max.amount === lastRoundMaxBetInt) {
throw new Error('can not find minRaiseAmount.');
}
// finding second highest bet
var secondMax = lastRoundMaxBetInt;
for (var i = max.pos + 1; i < lineup.length + max.pos; i += 1) {
var pos = i % lineup.length;
var last = lineup[pos].last ? this.rc.get(lineup[pos].last).amount.toNumber() : 0;
if (last > secondMax && last < max.amount) {
secondMax = last;
}
}
return max.amount - secondMax;
}
/**
* getMaxBet
*
* @param
* @returns
*/ }, { key: 'getMaxBet', value: function getMaxBet(
lineup, state) {var _this = this;
var startPos = state === 'preflop' && lineup.length > 2 ? 2 : 0;
var seats = [].concat((0, _toConsumableArray3.default)(
lineup.slice(startPos, lineup.length)), (0, _toConsumableArray3.default)(
lineup.slice(0, startPos)));
var result = seats.reduce(function (memo, seat, i) {
if (!seat.last) {
return memo;
}
var last = _this.rc.get(seat.last);
var amount = last.type !== _receipt.Type.SIT_OUT ? last.amount.toNumber() : 0;
// if we are in dealing the last 0 bet is the max bet
if (amount >= memo.amount || amount === 0 && state === 'dealing') {
return { amount: amount, pos: (i + startPos) % lineup.length };
}
return memo;
}, { pos: -1, amount: 0 });
if (result.pos === -1) {
throw new Error('could not find max bet.');
}
return result;
}
/**
* calculatePotsize
*
* @param
* @returns
*/ }, { key: 'calculatePotsize', value: function calculatePotsize(
lineup) {var _this2 = this;
return lineup.reduce(function (potSize, seat) {
var receipt = seat.last ? _this2.rc.get(seat.last) : undefined;
return potSize + (receipt ? receipt.amount.toNumber() : 0);
}, 0);
}
/**
* isTurn
*
* @param
* @returns
*/ }, { key: 'isTurn', value: function isTurn(
lineup, dealer, state, bbAmount, addr) {
var pos = this.getMyPos(lineup, addr);
return this.getWhosTurn(lineup, dealer, state, bbAmount) === pos;
}
/**
* getWhosTurn
*
* @param
* @returns
*/ }, { key: 'getWhosTurn', value: function getWhosTurn(
lineup, dealer, state, bbAmount) {
if (this.isHandComplete(lineup, dealer, state)) {
throw new Error('no ones turn if hand complete.');
}
var activePlayers = activeLineup(lineup, dealer, state, this.rc);
var maxBet = void 0;
if (state !== 'waiting') {
maxBet = this.getMaxBet(activePlayers, state);
if (!evenLineup(activePlayers, this.rc)) {
// if betting amounts are not even return next player of to the maxBettor
var next = activePlayers[(maxBet.pos + 1) % activePlayers.length];
var last = this.rc.get(next.last);
if (last && last.amount.toNumber() === maxBet.amount) {
next.pos = nextActive(lineup, next.pos + 1, state, this.rc);
}
return next.pos;
}
}
var stateChecksMap = {
preflop: _receipt.Type.CHECK_PRE,
flop: _receipt.Type.CHECK_FLOP,
turn: _receipt.Type.CHECK_TURN,
river: _receipt.Type.CHECK_RIVER };
var checkType = stateChecksMap[state] || 0;
var checker = findLatest({ sorted: true, lineup: activePlayers }, checkType, this.rc);
if (checker.last) {
return activePlayers[(checker.pos + 1) % activePlayers.length].pos;
}
if (state === 'preflop') {
if (!bbAmount) throw new Error('BB amount cannot be undefined');
if (!maxBet) {
maxBet = this.getMaxBet(activePlayers, state);
}
var maxAllInAmount = maxAllIn(lineup, this.rc);
var maxAmount = maxAllInAmount > maxBet.amount ? maxAllInAmount : maxBet.amount;
if (maxAmount === parseInt(bbAmount, 10)) {
return this.getBbPos(lineup, dealer, state);
}
}
if (activePlayers.length === 2 && state === 'waiting') {
return activePlayers[1].pos;
}
return activePlayers[0].pos;
}
/**
* nextPlayer
*
* @param
* @returns
*/ }, { key: 'nextPlayer', value: function nextPlayer(
lineup, startPos, type, state) {
return findNextPlayer(lineup, startPos, type, state, this.rc);
}
/**
* getSbPos
*
* @param
* @returns
*/ }, { key: 'getSbPos', value: function getSbPos(
lineup, dealer, state) {var type = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'cashgame';
var lineupType = type === 'tournament' ? 'busy' : 'involved';
if (typeof dealer === 'undefined' || !lineup) {
throw new Error('dealer or lineup undefined');
}
if (dealer < 0 || dealer >= lineup.length || lineup.length < 2) {
throw new Error('lineup not valid.');
}
var next = this.nextPlayer(lineup, dealer + 1, lineupType, state);
var activePlayerCount = countPlayers(lineup, lineupType, state, this.rc);
if (activePlayerCount < 2) {
throw new Error('can not find SB if involved player count < 2');
}
if (activePlayerCount === 2) {
return dealer;
}
return next;
}
/**
* getBbPos
*
* @param
* @returns
*/ }, { key: 'getBbPos', value: function getBbPos(
lineup, dealer, state) {var type = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'cashgame';
return findBbPos(lineup, dealer, state, type, this.rc);
}
// ########### COUNTS ###############
/**
* countActivePlayers counts the active players in lineup
* used in oracle
*
* @param lineup
* @returns number of active players
*/ }, { key: 'countActivePlayers', value: function countActivePlayers(
lineup, state) {var _this3 = this;
return lineup.filter(function (_, pos) {return _this3.isActivePlayer(lineup, pos, state);}).length;
}
/**
* countAllIn counts the number of players that are allin
* for countAllIns
*
* @param lineup
* @returns number of all-in players
*/ }, { key: 'countAllIn', value: function countAllIn(
lineup) {
if (!lineup) {
throw new Error('invalid lineup');
}
return lineup.filter(function (seat) {return seat.sitout && seat.sitout === 'allin';}).length;
}
// ########### HAND STATE RELATED ############
/**
* isBettingDone checks if a round of betting has completed.
*
* @param lineup
* @param dealer
* @param state
* @param max
* @param bbAmount
* @returns boolean
*/ }, { key: 'isBettingDone', value: function isBettingDone(
lineup, dealer, state, bbAmount) {
if (this.isHandComplete(lineup, dealer, state)) {
return true;
}
var activePlayers = activeLineup(lineup, dealer, state, this.rc);
var maxBet = void 0;
if (state === 'waiting' || state === 'preflop') {
try {
maxBet = this.getMaxBet(activePlayers, state);
} catch (err) {
if (state === 'waiting') {
return false;
}
// try with all players, in case everyone all-in
maxBet = this.getMaxBet(lineup, state);
}
}
if (state === 'waiting') {
return maxBet.amount > 0;
}
if (state === 'dealing') {
var noRecCount = countNoReceipts(lineup, this.rc);
if (noRecCount === 0) {
return true;
}
}
var allInPlayerCount = this.countAllIn(lineup);
if (allInPlayerCount > 0 && activePlayers.length === 1) {
// see if last active player matched latest all-in
var maxAllInAmount = maxAllIn(lineup, this.rc);
if (!maxBet) {
maxBet = this.getMaxBet(activePlayers, state);
}
return maxAllInAmount <= maxBet.amount;
}
var allEven = evenLineup(activePlayers, this.rc);
if (!allEven) {
return false;
}
var checker = findLatest({ sorted: true, lineup: activePlayers }, _receipt.Type.CHECK_PRE, this.rc);
if (checker.last) {
// prefop betting done if check found
if (state === 'preflop') {
return true;
}
// on other streets wait until all active players have checked
var checkType = state === 'preflop' ? // eslint-disable-line
_receipt.Type.CHECK_PRE : state === 'flop' ? // eslint-disable-line
_receipt.Type.CHECK_FLOP : state === 'turn' ?
_receipt.Type.CHECK_TURN : _receipt.Type.CHECK_RIVER;
var checkCount = countReceipts(lineup, checkType, this.rc);
if (checkCount === activePlayers.length) {
return true;
}
return false;
}
if (state === 'preflop') {
if (!bbAmount) throw new Error('BB amount cannot be undefined');
var bbPos = this.getBbPos(lineup, dealer, state);
var bbRec = this.rc.get(lineup[bbPos].last);
if (isActive(lineup[bbPos], state, this.rc) &&
bbRec.type !== _receipt.Type.CHECK_PRE &&
maxBet.amount === parseInt(bbAmount, 10)) {
return false;
}
}
if (allInPlayerCount > 0 && activePlayers.length === 0) {
return true;
}
if (allEven) {
return true;
}
throw Error('could not determine betting state');
}
/**
* isHandComplete checks if the hand is complete.
* the complete state is met when the second to last player folded or timed out,
* or once everyone has shown in showdown.
* replaces: checkForNextHand
*
* @param lineup
* @param dealer
* @param state
* @returns boolean
*/ }, { key: 'isHandComplete', value: function isHandComplete(
lineup, dealer, state) {
var activePlayers = activeLineup(lineup, dealer, state, this.rc);
var allInPlayerCount = this.countAllIn(lineup);
if (state === 'showdown') {
if (checkForReceipt(lineup, _receipt.Type.SHOW, this.rc)) {
return activePlayers.length === 0 && allInPlayerCount === 0;
}
return activePlayers.length <= 1 && allInPlayerCount === 0;
}
return (
activePlayers.length <= 1 && allInPlayerCount === 0 ||
activePlayers.length === 0 && allInPlayerCount === 1);
}
/**
* renderHand
*
* @param
* @returns
*/ }, { key: 'renderHand', value: function renderHand(
handId, lineupParam, dealer,
sb, state, changed, deck, preMaxBet, flopMaxBet, turnMaxBet, riverMaxBet,
distribution, netting) {
var lineup = lineupParam.slice();
if (state === 'showdown') {
for (var i = 0; i < lineup.length; i += 1) {
if (lineup[i].last) {
var last = this.rc.get(lineup[i].last);
if (last.type === _receipt.Type.SHOW) {
lineup[i].cards = [];
lineup[i].cards.push(deck[i * 2]);
lineup[i].cards.push(deck[i * 2 + 1]);
}
}
}
}
var rv = {
handId: handId,
lineup: lineup,
dealer: dealer,
state: state,
changed: changed,
sb: sb,
cards: [] };
if (state === 'flop') {
rv.preMaxBet = preMaxBet;
rv.cards.push(deck[20]);
rv.cards.push(deck[21]);
rv.cards.push(deck[22]);
}
if (state === 'turn') {
rv.preMaxBet = preMaxBet;
rv.flopMaxBet = flopMaxBet;
rv.cards.push(deck[20]);
rv.cards.push(deck[21]);
rv.cards.push(deck[22]);
rv.cards.push(deck[23]);
}
if (state === 'river') {
rv.preMaxBet = preMaxBet;
rv.flopMaxBet = flopMaxBet;
rv.turnMaxBet = turnMaxBet;
rv.cards.push(deck[20]);
rv.cards.push(deck[21]);
rv.cards.push(deck[22]);
rv.cards.push(deck[23]);
rv.cards.push(deck[24]);
}
if (state === 'showdown') {
rv.preMaxBet = preMaxBet;
rv.flopMaxBet = flopMaxBet;
rv.turnMaxBet = turnMaxBet;
rv.riverMaxBet = riverMaxBet;
rv.cards.push(deck[20]);
rv.cards.push(deck[21]);
rv.cards.push(deck[22]);
rv.cards.push(deck[23]);
rv.cards.push(deck[24]);
}
if (distribution) {
rv.distribution = distribution;
}
if (netting) {
rv.netting = netting;
}
return rv;
}
/**
* user PokerSolver do determine winner.
*
* @param lineup
* @param dealer
* @param board
* @returns winners array
*/ }, { key: 'getWinners', value: function getWinners(
lineup, dealer, board) {
if (!lineup) {
throw new Error('invalid params');
}
var boardCards = board.map(function (c) {return VALUES[c % 13] + SUITS[Math.floor([c / 13])];});
var winners = [];
var players = [];
_abPokersolver2.default.Hand.winners(lineup.filter(function (obj) {return obj.cards;}).map(function (player) {
var pHand = [];
var card1 = VALUES[player.cards[0] % 13] + SUITS[Math.floor([player.cards[0] / 13])];
var card2 = VALUES[player.cards[1] % 13] + SUITS[Math.floor([player.cards[1] / 13])];
pHand.push.apply(pHand, (0, _toConsumableArray3.default)(boardCards).concat([card1, card2]));
var handObj = _abPokersolver2.default.Hand.solve(pHand);
players.push((0, _assign2.default)(player, { hand: handObj }));
return handObj;
})).forEach(function (wHand) {
players.forEach(function (player) {
if (player.hand === wHand) {
var winner = {
addr: player.address,
hand: player.hand.descr };
winners.push(winner);
}
});
});
return winners;
}
/**
* calcDistribution evaluates a hand and creates a distribution
*
* @param lineup
* @param state
* @param boardCards
* @param rakePerMil
* @param rakeAddr
* @returns signed distribution
*/ }, { key: 'calcDistribution', value: function calcDistribution(
lineup, state, boardCards, rakePerMil, rakeAddr) {
if (!state || !lineup) {
throw new Error('invalid params');
}
// create pots
var players = getPlayers(this, state, lineup);
var pots = players.filter(function (p) {return p.active;}).reduce(function (list, player) {
if (!(list.indexOf(player.amount) !== -1)) {
return [].concat((0, _toConsumableArray3.default)(list), [player.amount]);
}
return list;
}, []).sort(function (a, b) {return a - b;});
if (pots.reduce(function (a, b) {return a + b;}, 0) === 0) {
// zero pots, can't be distributed
// return money to players
return players.reduce(function (result, player) {return (0, _extends4.default)({},
result, (0, _defineProperty3.default)({},
lineup[player.pos].address, player.amount));}, (0, _defineProperty3.default)({},
rakeAddr, 0));
}
var evals = pots.map(function (pot) {return {
limit: pot,
size: 0,
chal: [],
winners: [] };});
// distribute players on evals
// while all players amounts is not distributed
while (players.filter(function (p) {return p.amount > 0;}).length > 0) {
for (var i = 0; i < evals.length; i += 1) {
for (var j = 0; j < players.length; j += 1) {
if (players[j].amount > 0) {
var limit = i > 0 ? evals[i].limit - evals[i - 1].limit : evals[i].limit;
var contribution = Math.min(limit, players[j].amount);
evals[i].size += contribution;
players[j].amount -= contribution;
if (players[j].active) {
evals[i].chal.push(players[j].pos);
}
}
}
}
}
// solve hands
for (var _i = 0; _i < evals.length; _i += 1) {
if (evals[_i].chal.length > 1) {
var hands = [];
for (var _j = 0; _j < evals[_i].chal.length; _j += 1) {
var h = [];
// hole cards
var card = lineup[evals[_i].chal[_j]].cards[0];
h.push(VALUES[card % 13] + SUITS[Math.floor(card / 13)]);
card = lineup[evals[_i].chal[_j]].cards[1];
h.push(VALUES[card % 13] + SUITS[Math.floor(card / 13)]);
// board cards
h.push(VALUES[boardCards[0] % 13] + SUITS[Math.floor(boardCards[0] / 13)]);
h.push(VALUES[boardCards[1] % 13] + SUITS[Math.floor(boardCards[1] / 13)]);
h.push(VALUES[boardCards[2] % 13] + SUITS[Math.floor(boardCards[2] / 13)]);
h.push(VALUES[boardCards[3] % 13] + SUITS[Math.floor(boardCards[3] / 13)]);
h.push(VALUES[boardCards[4] % 13] + SUITS[Math.floor(boardCards[4] / 13)]);
hands.push(_abPokersolver2.default.Hand.solve(h));
}
var wnrs = _abPokersolver2.default.Hand.winners(hands);
for (var _j2 = 0; _j2 < wnrs.length; _j2 += 1) {
var pos = evals[_i].chal[hands.indexOf(wnrs[_j2])];
evals[_i].winners.push(pos);
}
} else {
evals[_i].winners.push(evals[_i].chal[0]);
}
}
// sum up pots by players and calc rake
var winners = {};
for (var _i2 = 0; _i2 < evals.length; _i2 += 1) {
var total = evals[_i2].size;
for (var _j3 = 0; _j3 < evals[_i2].winners.length; _j3 += 1) {
var addr = lineup[evals[_i2].winners[_j3]].address;
if (!winners[addr]) {
winners[addr] = 0;
}
var share = Math.floor((evals[_i2].size -
evals[_i2].size / 1000 * rakePerMil) / evals[_i2].winners.length);
total -= share;
winners[addr] += share;
}
if (!winners[rakeAddr]) {
winners[rakeAddr] = 0;
}
winners[rakeAddr] += total;
}
return winners;
} }]);return PokerHelper;}();exports.default = PokerHelper;