UNPKG

poker-odds-calculator

Version:

A pre-flop and post-flop odds calculator for Texas Holdem

283 lines 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * HandRank */ const _ = require("lodash"); const Card_1 = require("./Card"); class HandRankAlias { } HandRankAlias.HIGH_CARD = 'HIGH_CARD'; HandRankAlias.PAIR = 'PAIR'; HandRankAlias.TWO_PAIRS = 'TWO_PAIRS'; HandRankAlias.TRIPS = 'TRIPS'; HandRankAlias.STRAIGHT = 'STRAIGHT'; HandRankAlias.FLUSH = 'FLUSH'; HandRankAlias.FULL_HOUSE = 'FULL_HOUSE'; HandRankAlias.QUADS = 'QUADS'; HandRankAlias.STRAIGHT_FLUSH = 'STRAIGHT_FLUSH'; exports.HandRankAlias = HandRankAlias; class HandRank { constructor(rank, alias, highcards) { this.rank = rank; this.alias = alias; this.highcards = highcards; } static evaluate(game, cardgroup) { cardgroup.sortCards('desc'); // Group card by ranks const countByRanks = cardgroup.countBy('rank'); const quadRanks = []; const tripRanks = []; const pairRanks = []; let straightCardsCount = 0; let straightMaxCardRank = 0; let straightLastCardRank = 0; const allRanks = Object.keys(countByRanks).reverse(); for (const rank of allRanks) { if (countByRanks[rank] === 2) { pairRanks.push(Number(rank)); } else if (countByRanks[rank] === 3) { tripRanks.push(Number(rank)); } else if (countByRanks[rank] === 4) { quadRanks.push(Number(rank)); } if (straightCardsCount !== 5) { if (straightLastCardRank === 0 || straightLastCardRank - 1 !== Number(rank)) { straightMaxCardRank = straightLastCardRank = Number(rank); straightCardsCount = 1; } else { straightCardsCount += 1; straightLastCardRank = Number(rank); } } } // Group card by suit const countBySuits = cardgroup.countBy('suit'); let flushSuit = 0; _.some(Object.keys(countBySuits), (suit) => { if (countBySuits[suit] >= 5) { flushSuit = Number(suit); return true; } return false; }); // Straight flush if (flushSuit > 0) { if (straightCardsCount >= 5) { const straightFlushCards = _.filter(cardgroup, (card) => { return card.getSuit() === flushSuit && card.getRank() <= straightMaxCardRank; }); if (straightFlushCards.length >= 5) { let isStraightFlush = true; for (let i = 1; i <= 4; i += 1) { if (straightFlushCards[i].getRank() !== straightFlushCards[i - 1].getRank() - 1) { isStraightFlush = false; break; } } if (isStraightFlush) { return new HandRank(game.STRAIGHT_FLUSH, HandRankAlias.STRAIGHT_FLUSH, straightFlushCards.slice(0, 5)); } } else if (straightFlushCards.length === 4 && ( // Five high straight (5-4-3-2-A) (game.A2345_STRAIGHT && straightFlushCards[0].getRank() === Card_1.Rank.FIVE) || // Five high straight (9-8-7-6-A) (game.A6789_STRAIGHT && straightFlushCards[0].getRank() === Card_1.Rank.NINE))) { const aceCards = _.filter(cardgroup, (card) => { return card.getSuit() === flushSuit && card.getRank() === Card_1.Rank.ACE; }); if (aceCards.length) { return new HandRank(game.STRAIGHT_FLUSH, HandRankAlias.STRAIGHT_FLUSH, straightFlushCards.concat(aceCards[0])); } } } else if (straightCardsCount === 4 && ( // Five high straight (5-4-3-2-A) (game.A2345_STRAIGHT && straightMaxCardRank === Card_1.Rank.FIVE) || // Nine high straight (9-8-7-6-A) (game.A6789_STRAIGHT && straightMaxCardRank === Card_1.Rank.NINE))) { const aceCards = _.filter(cardgroup, (card) => { return card.getSuit() === flushSuit && card.getRank() === Card_1.Rank.ACE; }); if (aceCards.length > 0) { const straightFlushCards = _.filter(cardgroup, (card) => { return card.getSuit() === flushSuit && card.getRank() <= straightMaxCardRank; }); if (straightFlushCards.length === 4) { return new HandRank(game.STRAIGHT_FLUSH, HandRankAlias.STRAIGHT_FLUSH, straightFlushCards.concat(aceCards[0]).slice(0, 5)); } } } } // Quads if (quadRanks.length === 1) { const quadCards = _.filter(cardgroup, (card) => card.getRank() === quadRanks[0]); const cards = _.reject(cardgroup, (card) => card.getRank() === quadRanks[0]); return new HandRank(game.QUADS, HandRankAlias.QUADS, quadCards.concat(cards).slice(0, 5)); } // Full house if (tripRanks.length === 1 && pairRanks.length >= 1) { const tripCards = _.filter(cardgroup, (card) => { return card.getRank() === tripRanks[0]; }); const pairCards = _.filter(cardgroup, (card) => { return card.getRank() === pairRanks[0]; }); return new HandRank(game.FULL_HOUSE, HandRankAlias.FULL_HOUSE, tripCards.concat(pairCards)); } else if (tripRanks.length > 1) { const tripCards = _.filter(cardgroup, (card) => { return card.getRank() === tripRanks[0]; }); const pairCards = _.filter(cardgroup, (card) => { return card.getRank() === tripRanks[1]; }); return new HandRank(game.FULL_HOUSE, HandRankAlias.FULL_HOUSE, tripCards.concat(pairCards.slice(0, 2))); } // Flush if (flushSuit > 0) { const flushCards = _.filter(cardgroup, (card) => { return card.getSuit() === flushSuit; }); return new HandRank(game.FLUSH, HandRankAlias.FLUSH, flushCards.slice(0, 5)); } // Straight if (straightCardsCount === 5) { const straightCards = _.uniqWith(_.filter(cardgroup, (card) => { return card.getRank() <= straightMaxCardRank; }), (c1, c2) => { return c1.getRank() === c2.getRank(); }); return new HandRank(game.STRAIGHT, HandRankAlias.STRAIGHT, straightCards.slice(0, 5)); } else if (straightCardsCount === 4 && ( // Five high straight (5-4-3-2-A) (game.A2345_STRAIGHT && straightMaxCardRank === Card_1.Rank.FIVE) || // Five high straight (9-8-7-6-A) (game.A6789_STRAIGHT && straightMaxCardRank === Card_1.Rank.NINE))) { const aceCards = _.filter(cardgroup, (card) => { return card.getRank() === Card_1.Rank.ACE; }); if (aceCards.length > 0) { const straightCards = _.uniqWith(_.filter(cardgroup, (card) => { return card.getRank() <= straightMaxCardRank; }), (c1, c2) => { return c1.getRank() === c2.getRank(); }); return new HandRank(game.STRAIGHT, HandRankAlias.STRAIGHT, straightCards.concat(aceCards[0]).slice(0, 5)); } } // Trips if (tripRanks.length === 1) { const tripCards = _.filter(cardgroup, (card) => { return card.getRank() === tripRanks[0]; }); const cards = _.reject(cardgroup, (card) => { return card.getRank() === tripRanks[0]; }); return new HandRank(game.TRIPS, HandRankAlias.TRIPS, tripCards.concat(cards).slice(0, 5)); } // Two pairs if (pairRanks.length >= 2) { const pairedHigherCards = _.filter(cardgroup, (card) => { return card.getRank() === pairRanks[0]; }); const pairedLowerCards = _.filter(cardgroup, (card) => { return card.getRank() === pairRanks[1]; }); const unpairedCards = _.reject(_.reject(cardgroup, (card) => card.getRank() === pairRanks[0]), (card) => card.getRank() === pairRanks[1]); return new HandRank(game.TWO_PAIRS, HandRankAlias.TWO_PAIRS, pairedHigherCards.concat(pairedLowerCards) .concat(unpairedCards) .slice(0, 5)); } // One pair if (pairRanks.length === 1) { const pairedCards = _.filter(cardgroup, (card) => { return card.getRank() === pairRanks[0]; }); const unpairedCards = _.reject(cardgroup, (card) => { return card.getRank() === pairRanks[0]; }); return new HandRank(game.PAIR, HandRankAlias.PAIR, pairedCards.concat(unpairedCards).slice(0, 5)); } // High card return new HandRank(game.HIGH_CARD, HandRankAlias.HIGH_CARD, cardgroup.slice(0, 5)); } getHighCards() { return this.highcards; } getRank() { return this.rank; } compareTo(handrank) { if (this.getRank() === handrank.getRank()) { for (let i = 0; i < 5; i += 1) { if (this.getHighCards()[i].getRank() !== handrank.getHighCards()[i].getRank()) { return this.getHighCards()[i].getRank() > handrank.getHighCards()[i].getRank() ? 1 : -1; } } return 0; } return this.getRank() > handrank.getRank() ? 1 : -1; } toString() { let showHighcards = 0; let s = ''; switch (this.alias) { case HandRankAlias.STRAIGHT_FLUSH: if (this.highcards[0].getRank() === Card_1.Rank.ACE) { s = 'Royal flush'; } else { s = _.capitalize(this.highcards[0].toString(false, true)) + ' high straight flush'; } break; case HandRankAlias.QUADS: s = 'Quad ' + this.highcards[0].toString(false, true, true); showHighcards = 1; break; case HandRankAlias.FULL_HOUSE: s = `Full house: ${this.highcards[0].toString(false, true, true)} full of ${this.highcards[4].toString(false, true, true)}`; break; case HandRankAlias.FLUSH: s = _.capitalize(this.highcards[0].toString(false, true)) + ' high flush'; break; case HandRankAlias.STRAIGHT: s = _.capitalize(this.highcards[0].toString(false, true)) + ' high straight'; break; case HandRankAlias.TRIPS: s = `Trip ${this.highcards[0].toString(false, true, true)}`; showHighcards = 2; break; case HandRankAlias.TWO_PAIRS: s = `Two pairs: ${this.highcards[0].toString(false, true, true)} and ${this.highcards[2].toString(false, true, true)}`; showHighcards = 1; break; case HandRankAlias.PAIR: s = `Pair of ${this.highcards[0].toString(false, true, true)}`; showHighcards = 3; break; default: s = 'High card'; showHighcards = 5; break; } if (showHighcards > 0) { const highcards = this.highcards.slice(5 - showHighcards, 5).map((h) => { return h.toString(false); }); s = s + ` (${highcards.join(',')} high)`; } return s; } } exports.HandRank = HandRank; //# sourceMappingURL=HandRank.js.map