poker-extval 3.1.1 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/evaluator.js +93 -2
  2. package/package.json +1 -1
package/evaluator.js CHANGED
@@ -39,10 +39,11 @@ class HandEvaluator {
39
39
  * // Non-strict mode - all applicable hands marked
40
40
  * const nonStrictEvaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Kc', 'Qs'], false);
41
41
  */
42
- constructor(cards, strict = true) {
42
+ constructor(cards, strict = true, originalCards = null) {
43
43
  this.#validateCards(cards);
44
44
  this.cards = cards;
45
45
  this.strict = strict;
46
+ this.originalCards = originalCards || (cards.length > 5 ? cards : null);
46
47
  this.evaluation = this.#evaluateAllCombinations();
47
48
  }
48
49
 
@@ -198,6 +199,8 @@ class HandEvaluator {
198
199
  this.#isOpenEndedStraightDraw();
199
200
  this.#isInsideStraightDraw();
200
201
  this.#isStraightDraw();
202
+ this.#isComboDraw();
203
+ this.#isUnderPair();
201
204
  this.#isHighCard();
202
205
 
203
206
  // Add keyCards and kickerCards before restoring original evaluation
@@ -415,7 +418,7 @@ class HandEvaluator {
415
418
  const result = {};
416
419
  for (const combination of combinations) {
417
420
  const key = this.#formatHandKey(combination);
418
- const tempEvaluator = new HandEvaluator(combination, this.strict);
421
+ const tempEvaluator = new HandEvaluator(combination, this.strict, this.originalCards);
419
422
  const evaluationKey = Object.keys(tempEvaluator.evaluation)[0];
420
423
  result[key] = tempEvaluator.evaluation[evaluationKey];
421
424
  }
@@ -1430,6 +1433,33 @@ class HandEvaluator {
1430
1433
  return this.#getStraightDrawCards();
1431
1434
  }
1432
1435
 
1436
+ /**
1437
+ * Gets key cards for combo draw (flush draw + straight draw).
1438
+ * Returns the union of flush draw and straight draw cards.
1439
+ *
1440
+ * @private
1441
+ * @returns {string[]} Array of cards forming the combo draw, empty array otherwise
1442
+ */
1443
+ #getKeyCardsForComboDraw() {
1444
+ if (!this.evaluation.isComboDraw) return [];
1445
+ const flushCards = this.#getKeyCardsForFlushDraw();
1446
+ const straightCards = this.#getKeyCardsForStraightDraw();
1447
+ const allCards = [...flushCards, ...straightCards];
1448
+ const uniqueCards = [...new Set(allCards)];
1449
+ return uniqueCards.sort((a, b) => this.#getRankValue(b) - this.#getRankValue(a));
1450
+ }
1451
+
1452
+ /**
1453
+ * Gets key cards for under pair (the two cards forming the pair).
1454
+ *
1455
+ * @private
1456
+ * @returns {string[]} Array of 2 cards if under pair, empty array otherwise
1457
+ */
1458
+ #getKeyCardsForUnderPair() {
1459
+ if (!this.evaluation.isUnderPair) return [];
1460
+ return this.#getKeyCardsForPair();
1461
+ }
1462
+
1433
1463
  /**
1434
1464
  * Gets key cards for wheel straight (5 cards forming wheel).
1435
1465
  *
@@ -1507,6 +1537,8 @@ class HandEvaluator {
1507
1537
  isStraightWheel: this.#getKeyCardsForStraightWheel(),
1508
1538
  isOpenEndedStraightDrawWheel: this.#getKeyCardsForOpenEndedStraightDrawWheel(),
1509
1539
  isInsideStraightDrawWheel: this.#getKeyCardsForInsideStraightDrawWheel(),
1540
+ isComboDraw: this.#getKeyCardsForComboDraw(),
1541
+ isUnderPair: this.#getKeyCardsForUnderPair(),
1510
1542
  isHighCard: this.#getKeyCardsForHighCard()
1511
1543
  };
1512
1544
  }
@@ -1579,6 +1611,62 @@ class HandEvaluator {
1579
1611
 
1580
1612
  // ==================== HIGH CARD ====================
1581
1613
 
1614
+ /**
1615
+ * Determines if the hand has both a flush draw and a straight draw simultaneously.
1616
+ * Requires both isFlushDraw (not backdoor) and isStraightDraw to be true.
1617
+ *
1618
+ * @returns {boolean} True if the hand is a combo draw, false otherwise
1619
+ * @example
1620
+ * const evaluator = new HandEvaluator(['9s', '8s', '7s', '6s', 'Kh']);
1621
+ * evaluator.isComboDraw(); // Returns true (flush draw + straight draw)
1622
+ */
1623
+ #isComboDraw() {
1624
+ if (this.evaluation.isComboDraw !== undefined) return this.evaluation.isComboDraw;
1625
+ if (this.evaluation.isFlushDraw === undefined) this.#isFlushDraw();
1626
+ if (this.evaluation.isStraightDraw === undefined) this.#isStraightDraw();
1627
+ if (this.evaluation.isBackdoorFlushDraw === undefined) this.#isBackdoorFlushDraw();
1628
+ return this.evaluation.isComboDraw = this.evaluation.isFlushDraw &&
1629
+ this.evaluation.isStraightDraw &&
1630
+ !this.evaluation.isBackdoorFlushDraw;
1631
+ }
1632
+
1633
+ /**
1634
+ * Determines if the hand contains an under pair (pocket pair smaller than all board cards).
1635
+ * Only applicable when evaluating 6+ cards where the pair rank is smaller than all other cards.
1636
+ *
1637
+ * @returns {boolean} True if the hand is an under pair, false otherwise
1638
+ * @example
1639
+ * // Board: K♠ Q♠ J♠ 8♠, Hand: 77
1640
+ * const evaluator = new HandEvaluator(['Ks', 'Qh', 'Jd', '8c', '7c', '7h']);
1641
+ * evaluator.isUnderPair(); // Returns true (pair of 7s is smaller than all board cards)
1642
+ */
1643
+ #isUnderPair() {
1644
+ if (this.evaluation.isUnderPair !== undefined) return this.evaluation.isUnderPair;
1645
+ if (this.evaluation.isPair === undefined) this.#isPair();
1646
+ if (!this.evaluation.isPair || !this.originalCards || this.originalCards.length < 6) {
1647
+ return this.evaluation.isUnderPair = false;
1648
+ }
1649
+ const pairRank = this.#getPairRank();
1650
+ if (!pairRank) return this.evaluation.isUnderPair = false;
1651
+ const otherCards = this.originalCards.filter(c => c.slice(0, -1) !== pairRank);
1652
+ const minOtherRank = Math.min(...otherCards.map(c => this.#getRankValue(c)));
1653
+ return this.evaluation.isUnderPair = this.#getRankValue(pairRank + 's') < minOtherRank;
1654
+ }
1655
+
1656
+ /**
1657
+ * Gets the rank of the pair in the current hand.
1658
+ *
1659
+ * @private
1660
+ * @returns {string|null} The rank of the pair, or null if no pair exists
1661
+ */
1662
+ #getPairRank() {
1663
+ const rankCounts = this.#getRankCounts();
1664
+ for (const [rank, count] of Object.entries(rankCounts)) {
1665
+ if (count === 2) return rank;
1666
+ }
1667
+ return null;
1668
+ }
1669
+
1582
1670
  /**
1583
1671
  * Determines if the hand is high card only (no pairs, two pair, three of a kind, full house,
1584
1672
  * four of a kind, flush, or straight).
@@ -1616,4 +1704,7 @@ function evaluateHand(cards, strict = true) {
1616
1704
  }
1617
1705
 
1618
1706
  module.exports = { evaluateHand, HandEvaluator };
1707
+ module.exports.default = evaluateHand;
1708
+ module.exports.evaluateHand = evaluateHand; // Explicit (redundant but safe)
1709
+ module.exports.HandEvaluator = HandEvaluator; // Explicit (redundant but safe)
1619
1710
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poker-extval",
3
- "version": "3.1.1",
3
+ "version": "3.2.1",
4
4
  "description": "Poker hand evaluator with comprehensive test suite",
5
5
  "main": "evaluator.js",
6
6
  "files": [