@alexjamesmalcolm/poker-odds-machine
Version:
Poker odds machine (calculator)
204 lines • 8.02 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Calculator = void 0;
const types_1 = require("./types");
const util_1 = require("./util");
const evaluate_1 = require("./evaluate");
class Player {
constructor(name) {
this.dealt = new types_1.CardGroup();
this.name = name;
}
evaluate(board) {
const totalCardGroup = new types_1.CardGroup(this.dealt.cards.concat(board.cards));
this.bestHand = evaluate_1.evaluate(totalCardGroup);
return this.bestHand;
}
compare(p) {
if (!p.bestHand || !this.bestHand)
return 0;
if (p.bestHand.handRank === this.bestHand.handRank) {
for (let i = 0; i < this.bestHand.hand.cards.length; i++) {
if (p.bestHand.hand.cards[i].rank !==
this.bestHand.hand.cards[i].rank) {
return p.bestHand.hand.cards[i].rank >
this.bestHand.hand.cards[i].rank
? 1
: -1;
}
}
return 0;
}
return p.bestHand.handRank > this.bestHand.handRank ? 1 : -1;
}
}
class Game {
constructor(input) {
this.players = [];
this.input = input;
this.deck = new types_1.Deck(this.input.numDecks);
this.deck.shuffle();
this.board = new types_1.CardGroup(this.input.board);
this.board.cards.forEach((c) => this.deck.removeCard(c));
this.dealKnownCards();
this.buildRestOfBoard();
this.dealRestOfCards();
}
static getNpcName(i) {
return `NPC ${i}`;
}
play() {
for (const p of this.players) {
p.evaluate(this.board);
}
// shuffle player order. allows bias when compare() return 0 as ties
util_1.shuffle(this.players);
// compare hands
this.players.sort((a, b) => a.compare(b));
const winners = [this.players[0]];
for (let i = 1; i < this.players.length; i++) {
const res = this.players[i - 1].compare(this.players[i]);
if (res === 0) {
winners.push(this.players[i]);
}
else {
break;
}
}
return winners;
}
buildRestOfBoard() {
const currentBoardSize = this.board.cards.length;
for (let i = 0; i < this.input.boardSize - currentBoardSize; i++) {
this.board.addCards(this.deck.pop());
}
}
dealKnownCards() {
for (const s of this.input.hands) {
const dealtCards = new types_1.CardGroup(s);
dealtCards.cards.forEach((c) => this.deck.removeCard(c));
const p = new Player(dealtCards.toString());
p.dealt.addCardGroup(dealtCards);
this.players.push(p);
}
}
dealRestOfCards() {
// complete any incomplete players
for (const p of this.players) {
for (let i = 0; i < this.input.handSize - p.dealt.cards.length; i++) {
p.dealt.addCards(this.deck.pop());
}
}
for (let i = 0; i < this.input.numPlayers - this.input.hands.length; i++) {
const dealtCards = new types_1.CardGroup();
for (let j = 0; j < this.input.handSize; j++) {
dealtCards.addCards(this.deck.pop());
}
const p = new Player(Game.getNpcName(i + 1));
p.dealt.addCardGroup(dealtCards);
this.players.push(p);
}
}
}
class Calculator {
constructor(input) {
this.stats = {};
util_1.validateInput(input);
this.input = util_1.cleanInput(input);
for (const e of this.input.hands) {
this.setupStatsObj(e);
}
for (let i = 0; i < this.input.numPlayers - this.input.hands.length; i++) {
this.setupStatsObj(Game.getNpcName(i + 1));
}
}
simulate() {
for (let i = 0; i < this.input.iterations; i++) {
const g = new Game(this.input);
const winners = g.play();
this.addToCount(winners);
}
this.calculateStats();
return this.stats;
}
getStatsOfPlayer(player) {
if (player in this.stats) {
return this.stats[player];
}
return {
tieCount: 0,
winCount: 0,
};
}
addToCount(winners) {
var _a, _b;
const isTie = winners.length > 1;
for (const winner of winners) {
const statsOfWinner = this.getStatsOfPlayer(winner.name);
if (isTie) {
statsOfWinner.tieCount++;
if (this.input.returnTieHandStats &&
((_a = winner.bestHand) === null || _a === void 0 ? void 0 : _a.handRank) !== undefined) {
const statsOfWinnerWithTieHandStats = types_1.makeStatsTieHandStatsIfItIsNotAlready(statsOfWinner);
statsOfWinnerWithTieHandStats.tieHandStats[types_1.HandRanks[winner.bestHand.handRank]].count++;
}
}
else {
statsOfWinner.winCount++;
if (this.input.returnHandStats &&
((_b = winner.bestHand) === null || _b === void 0 ? void 0 : _b.handRank) !== undefined) {
const statsOfWinnerWithHandStats = types_1.makeStatsHandStatsIfItIsNotAlready(statsOfWinner);
statsOfWinnerWithHandStats.handStats[types_1.HandRanks[winner.bestHand.handRank]].count++;
}
}
}
}
calculateStats() {
for (const name in this.stats) {
const statsOfPlayer = this.stats[name];
// winner percent
statsOfPlayer.winPercent = this.calculatePercent(statsOfPlayer.winCount);
statsOfPlayer.tiePercent = this.calculatePercent(statsOfPlayer.tieCount);
// hand percent
if (this.input.returnHandStats) {
const statsOfWinnerWithHandStats = types_1.makeStatsHandStatsIfItIsNotAlready(statsOfPlayer);
for (const rank in statsOfWinnerWithHandStats.handStats) {
statsOfWinnerWithHandStats.handStats[rank].percent =
this.calculatePercent(statsOfWinnerWithHandStats.handStats[rank].count);
}
}
if (this.input.returnTieHandStats) {
const statsOfWinnerWithTieHandStats = types_1.makeStatsTieHandStatsIfItIsNotAlready(statsOfPlayer);
for (const rank in statsOfWinnerWithTieHandStats.tieHandStats) {
statsOfWinnerWithTieHandStats.tieHandStats[rank].percent =
this.calculatePercent(statsOfWinnerWithTieHandStats.tieHandStats[rank]
.count);
}
}
}
}
setupStatsObj(name) {
this.stats[name] = { winCount: 0, tieCount: 0 };
if (this.input.returnHandStats)
types_1.makeStatsHandStatsIfItIsNotAlready(this.stats[name]);
if (this.input.returnTieHandStats)
types_1.makeStatsTieHandStatsIfItIsNotAlready(this.stats[name]);
for (const r in types_1.HandRanks) {
if (typeof types_1.HandRanks[r] !== 'number')
continue;
if (this.input.returnHandStats) {
const statsWithHandStats = types_1.makeStatsHandStatsIfItIsNotAlready(this.stats[name]);
statsWithHandStats.handStats[r] = { count: 0 };
}
if (this.input.returnTieHandStats) {
const statsWithTieHandStats = types_1.makeStatsTieHandStatsIfItIsNotAlready(this.stats[name]);
statsWithTieHandStats.tieHandStats[r] = { count: 0 };
}
}
}
calculatePercent(count) {
return +((count / this.input.iterations) * 100).toFixed(4);
}
}
exports.Calculator = Calculator;
//# sourceMappingURL=Game.js.map