poker-extval 3.3.1 → 3.3.2
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.
- package/README.md +2 -0
- package/evaluator.js +46 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -213,6 +213,8 @@ The `evaluateHand()` function returns an object where:
|
|
|
213
213
|
|
|
214
214
|
**Note**: When `holeCards` are supplied, every draw (including `isComboDraw` and the wheel draws) must use at least one hole card. A draw made entirely of board cards is shared by every player, so it is not reported: 2-2 on a 9-8-7-6 board is not an open-ended straight draw, and A♦-Q♦ on a K♠-7♠-2♠ flop is not a backdoor flush draw. Without `holeCards` the evaluator cannot tell the board from the hand, so draws are detected from all cards.
|
|
215
215
|
|
|
216
|
+
**Note**: Straight draws count paired cards once, so a paired hand can still hold one: 5-4 on an 8-8-6 flop is a pair and an inside straight draw. With `holeCards`, a hole card that only pairs a board rank does not create a straight draw (9-2 on a 9-8-7-6 board has no straight draw of its own).
|
|
217
|
+
|
|
216
218
|
#### Wheel Straight Support
|
|
217
219
|
- `isStraightWheel` - Wheel straight (A-2-3-4-5)
|
|
218
220
|
- `isOpenEndedStraightDrawWheel` - Open-ended draw using wheel ranking
|
package/evaluator.js
CHANGED
|
@@ -1082,8 +1082,9 @@ class HandEvaluator {
|
|
|
1082
1082
|
/**
|
|
1083
1083
|
* Determines if the hand is an open-ended straight draw (one card away from a straight on either end).
|
|
1084
1084
|
* Checks both standard and wheel-equivalent open-ended draws.
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1085
|
+
* Paired cards count once, so a paired hand can still hold a straight draw.
|
|
1086
|
+
* When hole cards are supplied, a hole card must add a rank the board does not already have.
|
|
1087
|
+
* Returns false if the hand is already a straight.
|
|
1087
1088
|
*
|
|
1088
1089
|
* @returns {boolean} True if the hand is an open-ended straight draw, false otherwise
|
|
1089
1090
|
* @example
|
|
@@ -1098,7 +1099,7 @@ class HandEvaluator {
|
|
|
1098
1099
|
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
1099
1100
|
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
1100
1101
|
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
1101
|
-
if (this.evaluation.
|
|
1102
|
+
if (this.evaluation.isStraight) {
|
|
1102
1103
|
// Check wheel equivalent before returning false
|
|
1103
1104
|
if (this.#isOpenEndedStraightDrawWheel()) return this.evaluation.isOpenEndedStraightDraw = true;
|
|
1104
1105
|
return this.evaluation.isOpenEndedStraightDraw = false;
|
|
@@ -1113,7 +1114,7 @@ class HandEvaluator {
|
|
|
1113
1114
|
/**
|
|
1114
1115
|
* Determines if the hand is an open-ended straight draw using wheel ranking.
|
|
1115
1116
|
* Checks for wheel-equivalent open-ended draws (e.g., A-2-3-4 needs 5 or 2).
|
|
1116
|
-
* Returns false if the hand already
|
|
1117
|
+
* Paired cards count once. Returns false if the hand is already a wheel straight.
|
|
1117
1118
|
*
|
|
1118
1119
|
* @returns {boolean} True if the hand is a wheel-equivalent open-ended straight draw, false otherwise
|
|
1119
1120
|
*/
|
|
@@ -1125,15 +1126,16 @@ class HandEvaluator {
|
|
|
1125
1126
|
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
1126
1127
|
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
1127
1128
|
if (this.evaluation.isStraightWheel === undefined) this.#isStraightWheel();
|
|
1128
|
-
if (this.evaluation.
|
|
1129
|
+
if (this.evaluation.isStraightWheel) return this.evaluation.isOpenEndedStraightDrawWheel = false;
|
|
1129
1130
|
return this.evaluation.isOpenEndedStraightDrawWheel = this.#findStraightDrawWindow([3], true) !== null;
|
|
1130
1131
|
}
|
|
1131
1132
|
|
|
1132
1133
|
/**
|
|
1133
1134
|
* Determines if the hand is an inside straight draw (one card away from a straight, but the needed card is in the middle).
|
|
1134
1135
|
* Checks both standard and wheel-equivalent inside draws.
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1136
|
+
* Paired cards count once, so a paired hand can still hold a straight draw.
|
|
1137
|
+
* When hole cards are supplied, a hole card must add a rank the board does not already have.
|
|
1138
|
+
* Returns false if the hand is already a straight.
|
|
1137
1139
|
*
|
|
1138
1140
|
* @returns {boolean} True if the hand is an inside straight draw, false otherwise
|
|
1139
1141
|
* @example
|
|
@@ -1148,7 +1150,7 @@ class HandEvaluator {
|
|
|
1148
1150
|
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
1149
1151
|
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
1150
1152
|
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
1151
|
-
if (this.evaluation.
|
|
1153
|
+
if (this.evaluation.isStraight) {
|
|
1152
1154
|
// Check wheel equivalent before returning false
|
|
1153
1155
|
if (this.#isInsideStraightDrawWheel()) return this.evaluation.isInsideStraightDraw = true;
|
|
1154
1156
|
return this.evaluation.isInsideStraightDraw = false;
|
|
@@ -1164,7 +1166,7 @@ class HandEvaluator {
|
|
|
1164
1166
|
/**
|
|
1165
1167
|
* Determines if the hand is an inside straight draw using wheel ranking.
|
|
1166
1168
|
* Checks for wheel-equivalent inside draws (e.g., A-2-3-5 needs 4).
|
|
1167
|
-
* Returns false if the hand already
|
|
1169
|
+
* Paired cards count once. Returns false if the hand is already a wheel straight.
|
|
1168
1170
|
*
|
|
1169
1171
|
* @returns {boolean} True if the hand is a wheel-equivalent inside straight draw, false otherwise
|
|
1170
1172
|
*/
|
|
@@ -1176,7 +1178,7 @@ class HandEvaluator {
|
|
|
1176
1178
|
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
1177
1179
|
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
1178
1180
|
if (this.evaluation.isStraightWheel === undefined) this.#isStraightWheel();
|
|
1179
|
-
if (this.evaluation.
|
|
1181
|
+
if (this.evaluation.isStraightWheel) return this.evaluation.isInsideStraightDrawWheel = false;
|
|
1180
1182
|
|
|
1181
1183
|
return this.evaluation.isInsideStraightDrawWheel = this.#findStraightDrawWindow([4], true) !== null;
|
|
1182
1184
|
}
|
|
@@ -1696,9 +1698,11 @@ class HandEvaluator {
|
|
|
1696
1698
|
}
|
|
1697
1699
|
|
|
1698
1700
|
/**
|
|
1699
|
-
* Finds 4
|
|
1700
|
-
*
|
|
1701
|
-
*
|
|
1701
|
+
* Finds 4 cards of distinct, rank-adjacent ranks whose rank span is one of the given distances.
|
|
1702
|
+
* Paired cards count once (a hole card is preferred as the representative of its rank), so a
|
|
1703
|
+
* paired hand such as 8-8-6-5-4 still finds its 8-6-5-4 draw. When hole cards are supplied, a
|
|
1704
|
+
* window whose ranks are all already on the board is skipped, since a draw the board gives
|
|
1705
|
+
* every player is not the player's draw.
|
|
1702
1706
|
*
|
|
1703
1707
|
* @private
|
|
1704
1708
|
* @param {number[]} distances - Accepted rank spans for the 4 cards (3 = open-ended, 4 = inside)
|
|
@@ -1708,11 +1712,19 @@ class HandEvaluator {
|
|
|
1708
1712
|
#findStraightDrawWindow(distances, wheel) {
|
|
1709
1713
|
const rankValue = wheel ? c => this.#getRankValueWheel(c) : c => this.#getRankValue(c);
|
|
1710
1714
|
if (wheel) this.#sortWheel(); else this.#sort();
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
+
const distinct = [];
|
|
1716
|
+
for (const card of this.cards) {
|
|
1717
|
+
const last = distinct[distinct.length - 1];
|
|
1718
|
+
if (last && rankValue(last) === rankValue(card)) {
|
|
1719
|
+
if (this.holeCards && this.holeCards.includes(card)) distinct[distinct.length - 1] = card;
|
|
1720
|
+
continue;
|
|
1715
1721
|
}
|
|
1722
|
+
distinct.push(card);
|
|
1723
|
+
}
|
|
1724
|
+
for (let i = 0; i + 4 <= distinct.length; i++) {
|
|
1725
|
+
const window = distinct.slice(i, i + 4);
|
|
1726
|
+
const distance = rankValue(window[0]) - rankValue(window[3]);
|
|
1727
|
+
if (distances.includes(distance) && this.#addsRankToBoard(window)) return window;
|
|
1716
1728
|
}
|
|
1717
1729
|
return null;
|
|
1718
1730
|
}
|
|
@@ -1743,6 +1755,23 @@ class HandEvaluator {
|
|
|
1743
1755
|
return cards.some(c => this.holeCards.includes(c));
|
|
1744
1756
|
}
|
|
1745
1757
|
|
|
1758
|
+
/**
|
|
1759
|
+
* Determines whether a straight draw's cards include a rank the board does not already have.
|
|
1760
|
+
* A hole card that only pairs a board rank adds nothing to a straight draw, so when hole cards
|
|
1761
|
+
* are supplied the draw must contain a rank found only in the hole cards. Without hole cards
|
|
1762
|
+
* every draw qualifies.
|
|
1763
|
+
*
|
|
1764
|
+
* @private
|
|
1765
|
+
* @param {string[]} cards - The cards forming the draw
|
|
1766
|
+
* @returns {boolean} True if no hole cards were supplied or a drawing rank is missing from the board
|
|
1767
|
+
*/
|
|
1768
|
+
#addsRankToBoard(cards) {
|
|
1769
|
+
if (!this.holeCards) return true;
|
|
1770
|
+
const fullHand = this.originalCards || this.cards;
|
|
1771
|
+
const boardRanks = new Set(fullHand.filter(c => !this.holeCards.includes(c)).map(c => c.slice(0, -1)));
|
|
1772
|
+
return cards.some(c => !boardRanks.has(c.slice(0, -1)));
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1746
1775
|
// ==================== HIGH CARD ====================
|
|
1747
1776
|
|
|
1748
1777
|
/**
|