UNPKG

@xpressit/winning-poker-hand-rank

Version:
277 lines (276 loc) 8.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.rankOmahaHand = exports.rankEightOrBetter = exports.rankAceFiveLow = exports.getAceRank = exports.rankShortDeckHand = exports.convertToSixPlusHandRank = exports.rankTexasHand = exports.toFixedSixPlusRank = exports.toFixedTexasRank = exports.EIGHT_OR_BETTER_MAX = exports.SIXPLUS_FULL_HOUSE = exports.SIXPLUS_FLUSH = exports.INVALID = exports.HIGH_CARD = exports.NOTHING = exports.PAIR = exports.TWO_PAIR = exports.THREE_OF_A_KIND = exports.STRAIGHT = exports.FLUSH = exports.FULL_HOUSE = exports.FOUR_OF_A_KIND = exports.STRAIGHT_FLUSH = exports.ROYAL_FLUSH = void 0; const cactusFastRankHand_1 = require("./cactusFastRankHand"); exports.ROYAL_FLUSH = 1; exports.STRAIGHT_FLUSH = 10; exports.FOUR_OF_A_KIND = 166; exports.FULL_HOUSE = 322; exports.FLUSH = 1599; exports.STRAIGHT = 1609; exports.THREE_OF_A_KIND = 2467; exports.TWO_PAIR = 3325; exports.PAIR = 6185; exports.NOTHING = 7462; exports.HIGH_CARD = exports.NOTHING; exports.INVALID = 65535; exports.SIXPLUS_FLUSH = 166 + 1277; exports.SIXPLUS_FULL_HOUSE = exports.SIXPLUS_FLUSH + 156; exports.EIGHT_OR_BETTER_MAX = 512; const t7c5 = [ [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 5, 4, 6], [0, 1, 2, 3, 6, 4, 5], [0, 1, 2, 4, 5, 3, 6], [0, 1, 2, 4, 6, 3, 5], [0, 1, 2, 5, 6, 3, 4], [0, 1, 3, 4, 5, 2, 6], [0, 1, 3, 4, 6, 2, 5], [0, 1, 3, 5, 6, 2, 4], [0, 1, 4, 5, 6, 2, 3], [0, 2, 3, 4, 5, 1, 6], [0, 2, 3, 4, 6, 1, 5], [0, 2, 3, 5, 6, 1, 4], [0, 2, 4, 5, 6, 1, 3], [0, 3, 4, 5, 6, 1, 2], [1, 2, 3, 4, 5, 0, 6], [1, 2, 3, 4, 6, 0, 5], [1, 2, 3, 5, 6, 0, 4], [1, 2, 4, 5, 6, 0, 3], [1, 3, 4, 5, 6, 0, 2], [2, 3, 4, 5, 6, 0, 1], ]; const rank567cardHand = (hand, f = cactusFastRankHand_1.cactusFastRankHand) => { if (hand.length === 5) { const rank = f([hand[0], hand[1], hand[2], hand[3], hand[4]]); return { rank, madeHand: [hand[0], hand[1], hand[2], hand[3], hand[4]], }; } if (hand.length === 6) { const possibleHands = [ [hand[0], hand[1], hand[2], hand[3], hand[4]], [hand[0], hand[1], hand[2], hand[3], hand[5]], [hand[0], hand[1], hand[2], hand[4], hand[5]], [hand[0], hand[1], hand[3], hand[4], hand[5]], [hand[0], hand[2], hand[3], hand[4], hand[5]], [hand[1], hand[2], hand[3], hand[4], hand[5]], ]; const sortedHands = possibleHands .map((h) => ({ rank: f(h), madeHand: h, })) .sort((a, b) => a.rank - b.rank); return sortedHands[0]; } if (hand.length === 7) { let r = 0; let rank = 9999; let bestHand = [hand[0], hand[1], hand[2], hand[3], hand[4]]; for (let i = 0; i < 21; i++) { const inputHand = [ hand[t7c5[i][0]], hand[t7c5[i][1]], hand[t7c5[i][2]], hand[t7c5[i][3]], hand[t7c5[i][4]], ]; r = f(inputHand); if (r < rank) { rank = r; bestHand = inputHand; } } return { rank, madeHand: bestHand, }; } throw new Error(`Hand ranker doesn't support ${hand.length} cards`); }; const toFixedTexasRank = (r) => { if (r === exports.ROYAL_FLUSH) { return exports.ROYAL_FLUSH; } if (r <= exports.STRAIGHT_FLUSH) { return exports.STRAIGHT_FLUSH; } if (r <= exports.FOUR_OF_A_KIND) { return exports.FOUR_OF_A_KIND; } if (r <= exports.FULL_HOUSE) { return exports.FULL_HOUSE; } if (r <= exports.FLUSH) { return exports.FLUSH; } if (r <= exports.STRAIGHT) { return exports.STRAIGHT; } if (r <= exports.THREE_OF_A_KIND) { return exports.THREE_OF_A_KIND; } if (r <= exports.TWO_PAIR) { return exports.TWO_PAIR; } if (r <= exports.PAIR) { return exports.PAIR; } if (r != exports.INVALID) { return exports.NOTHING; } return exports.INVALID; }; exports.toFixedTexasRank = toFixedTexasRank; const toFixedSixPlusRank = (r) => { if (r === exports.ROYAL_FLUSH) { return exports.ROYAL_FLUSH; } if (r <= exports.STRAIGHT_FLUSH) { return exports.STRAIGHT_FLUSH; } if (r <= exports.FOUR_OF_A_KIND) { return exports.FOUR_OF_A_KIND; } if (r <= exports.SIXPLUS_FLUSH) { return exports.SIXPLUS_FLUSH; } if (r <= exports.SIXPLUS_FULL_HOUSE) { return exports.SIXPLUS_FULL_HOUSE; } if (r <= exports.STRAIGHT) { return exports.STRAIGHT; } if (r <= exports.THREE_OF_A_KIND) { return exports.THREE_OF_A_KIND; } if (r <= exports.TWO_PAIR) { return exports.TWO_PAIR; } if (r <= exports.PAIR) { return exports.PAIR; } if (r != exports.INVALID) { return exports.NOTHING; } return exports.INVALID; }; exports.toFixedSixPlusRank = toFixedSixPlusRank; const rankTexasHand = (pocket, board) => { return rank567cardHand([...pocket, ...board], cactusFastRankHand_1.cactusFastRankHand); }; exports.rankTexasHand = rankTexasHand; const convertToSixPlusHandRank = (handRank) => { if (handRank === 747) { handRank = 6; } else if (handRank === 6610) { handRank = 1605; } // Swap full_house with flush const fixedRank = (0, exports.toFixedTexasRank)(handRank); if (fixedRank === exports.FULL_HOUSE) { handRank = handRank - exports.FOUR_OF_A_KIND + 166 + 1277; } else if (fixedRank === exports.FLUSH) { handRank = handRank - exports.FULL_HOUSE + 166; } return handRank; }; exports.convertToSixPlusHandRank = convertToSixPlusHandRank; const rankShortDeckHand = (pocket, board) => { const f = (hand) => { const handRank = (0, cactusFastRankHand_1.cactusFastRankHand)(hand); return (0, exports.convertToSixPlusHandRank)(handRank); }; return rank567cardHand([...pocket, ...board], f); }; exports.rankShortDeckHand = rankShortDeckHand; const t4c2 = [ [0, 1, 2, 3], [0, 2, 1, 3], [0, 3, 1, 2], [1, 2, 0, 3], [1, 3, 0, 2], [2, 3, 0, 1], ]; const t5c3 = [ [0, 1, 2, 3, 4], [0, 1, 3, 2, 4], [0, 1, 4, 2, 3], [0, 2, 3, 1, 4], [0, 2, 4, 1, 3], [0, 3, 4, 1, 2], [1, 2, 3, 0, 4], [1, 2, 4, 0, 3], [1, 3, 4, 0, 2], [2, 3, 4, 0, 1], ]; // AceRank returns the card [Ace]-low index. const getAceRank = (card) => { // int(c>>8&0xf+1) % 13 return (((card >> 8) & 0xf) + 1) % 13; }; exports.getAceRank = getAceRank; const rankAceFiveLow = (mask, hand) => { let rank = 0; for (const card of hand) { const n = (0, exports.getAceRank)(card); rank |= (1 << n) | ((((mask & (1 << n)) >>> n) & 1) * 0x8000); mask |= 1 << n; } return rank; }; exports.rankAceFiveLow = rankAceFiveLow; // RankEightOrBetter is a 8-or-better low rank eval func. [Ace]'s are low, // [Straight]'s and [Flush]'s do not count. const rankEightOrBetter = (hand) => { return (0, exports.rankAceFiveLow)(0xff00, hand); }; exports.rankEightOrBetter = rankEightOrBetter; const rankOmahaHand = (pocket, board, low = false) => { let bestHand = [pocket[0], pocket[1], pocket[2], pocket[3], board[0]]; let bestRank = exports.INVALID; let lowBestHand = [pocket[0], pocket[1], pocket[2], pocket[3], board[0]]; let lowBestRank = exports.INVALID; for (let i = 0; i < 6; i++) { for (let j = 0; j < 10; j++) { const hand = [ pocket[t4c2[i][0]], pocket[t4c2[i][1]], board[t5c3[j][0]], board[t5c3[j][1]], board[t5c3[j][2]], ]; const rank = (0, cactusFastRankHand_1.cactusFastRankHand)(hand); if (rank < bestRank) { bestHand = hand; bestRank = rank; } if (low) { const lowRank = (0, exports.rankEightOrBetter)(hand); if (lowRank < lowBestRank) { lowBestHand = hand; lowBestRank = lowRank; } } } } if (low && lowBestRank < exports.EIGHT_OR_BETTER_MAX) { return { rank: bestRank, madeHand: bestHand, low: { rank: lowBestRank, madeHand: lowBestHand, }, }; } return { rank: bestRank, madeHand: bestHand, }; }; exports.rankOmahaHand = rankOmahaHand;