poker-extval 1.1.0 → 2.0.0
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 +15 -15
- package/evaluator.js +164 -192
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,12 +49,6 @@ const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', 'Ts', '9s']);
|
|
|
49
49
|
// Access evaluation results
|
|
50
50
|
const evaluation = evaluator.evaluation;
|
|
51
51
|
// Object with keys for each 5-card combination
|
|
52
|
-
|
|
53
|
-
// Use utility methods
|
|
54
|
-
evaluator.sort(); // Sort cards by rank
|
|
55
|
-
evaluator.getDistance(); // Get distance between highest and lowest card
|
|
56
|
-
evaluator.countSuits(); // Count suits in hand
|
|
57
|
-
evaluator.countRanks(); // Count ranks in hand
|
|
58
52
|
```
|
|
59
53
|
|
|
60
54
|
### Evaluating Multiple Card Hands
|
|
@@ -126,12 +120,17 @@ The `evaluateHand()` function returns an object where:
|
|
|
126
120
|
- `isBackdoorFlushDraw` - Three cards of the same suit (two away from flush)
|
|
127
121
|
- `isOpenEndedStraightDraw` - One card away from straight on either end
|
|
128
122
|
- `isInsideStraightDraw` - One card away from straight (needed card in middle)
|
|
123
|
+
- `isStraightDraw` - Any type of straight draw (open-ended or inside, standard or wheel)
|
|
129
124
|
|
|
130
125
|
#### Wheel Straight Support
|
|
131
126
|
- `isStraightWheel` - Wheel straight (A-2-3-4-5)
|
|
132
127
|
- `isOpenEndedStraightDrawWheel` - Open-ended draw using wheel ranking
|
|
133
128
|
- `isInsideStraightDrawWheel` - Inside draw using wheel ranking
|
|
134
129
|
|
|
130
|
+
#### Card Arrays
|
|
131
|
+
- `keyCards` - Array of cards (sorted) that constitute the made hand or draw
|
|
132
|
+
- `kickerCards` - Array of cards (sorted) that don't constitute the made hand or draw
|
|
133
|
+
|
|
135
134
|
### Example Response
|
|
136
135
|
|
|
137
136
|
```javascript
|
|
@@ -159,7 +158,10 @@ The `evaluateHand()` function returns an object where:
|
|
|
159
158
|
"isBackdoorFlushDraw": false,
|
|
160
159
|
"isOpenEndedStraightDraw": false,
|
|
161
160
|
"isInsideStraightDraw": false,
|
|
162
|
-
"
|
|
161
|
+
"isStraightDraw": false,
|
|
162
|
+
"isHighCard": false,
|
|
163
|
+
"keyCards": ["As", "Ks", "Qs", "Js", "Ts"],
|
|
164
|
+
"kickerCards": []
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
167
|
```
|
|
@@ -265,16 +267,14 @@ new HandEvaluator(cards)
|
|
|
265
267
|
|
|
266
268
|
Creates a new HandEvaluator instance.
|
|
267
269
|
|
|
268
|
-
|
|
270
|
+
**Parameters:**
|
|
271
|
+
- `cards` (string[]): Array of 5 or more card strings
|
|
269
272
|
|
|
270
|
-
|
|
271
|
-
- `
|
|
272
|
-
- `
|
|
273
|
-
- `getDistanceWheel(cards?)` - Calculate distance using wheel ranking
|
|
274
|
-
- `countSuits()` - Count occurrences of each suit
|
|
275
|
-
- `countRanks()` - Count occurrences of each rank (sorted)
|
|
273
|
+
**Properties:**
|
|
274
|
+
- `evaluation` - Object mapping sorted hand strings to evaluation objects (same format as `evaluateHand()` return value)
|
|
275
|
+
- `cards` - Array of input cards
|
|
276
276
|
|
|
277
|
-
All
|
|
277
|
+
**Note**: All internal methods are private. Use the `evaluation` property to access evaluation results.
|
|
278
278
|
|
|
279
279
|
## License
|
|
280
280
|
|
package/evaluator.js
CHANGED
|
@@ -166,30 +166,30 @@ class HandEvaluator {
|
|
|
166
166
|
this.evaluation = {};
|
|
167
167
|
|
|
168
168
|
// Call all evaluation methods - they will populate this.evaluation
|
|
169
|
-
this
|
|
170
|
-
this
|
|
171
|
-
this
|
|
172
|
-
this
|
|
173
|
-
this
|
|
174
|
-
this
|
|
175
|
-
this
|
|
176
|
-
this
|
|
177
|
-
this
|
|
178
|
-
this
|
|
179
|
-
this
|
|
180
|
-
this
|
|
181
|
-
this
|
|
182
|
-
this
|
|
183
|
-
this
|
|
184
|
-
this
|
|
185
|
-
this
|
|
186
|
-
this
|
|
187
|
-
this
|
|
188
|
-
this
|
|
189
|
-
this
|
|
190
|
-
this
|
|
191
|
-
this
|
|
192
|
-
this
|
|
169
|
+
this.#isFourOfAKind();
|
|
170
|
+
this.#isFullHouse();
|
|
171
|
+
this.#isThreeOfAKind();
|
|
172
|
+
this.#isTwoPair();
|
|
173
|
+
this.#isPair();
|
|
174
|
+
this.#isFlush();
|
|
175
|
+
this.#isTopPair();
|
|
176
|
+
this.#isMiddlePair();
|
|
177
|
+
this.#isBottomPair();
|
|
178
|
+
this.#isTopAndMiddlePair();
|
|
179
|
+
this.#isTopAndBottomPair();
|
|
180
|
+
this.#isMiddleAndBottomPair();
|
|
181
|
+
this.#isTopThreeOfAKind();
|
|
182
|
+
this.#isMiddleThreeOfAKind();
|
|
183
|
+
this.#isBottomThreeOfAKind();
|
|
184
|
+
this.#isFlushDraw();
|
|
185
|
+
this.#isBackdoorFlushDraw();
|
|
186
|
+
this.#isStraight();
|
|
187
|
+
this.#isRoyalFlush();
|
|
188
|
+
this.#isStraightFlush();
|
|
189
|
+
this.#isOpenEndedStraightDraw();
|
|
190
|
+
this.#isInsideStraightDraw();
|
|
191
|
+
this.#isStraightDraw();
|
|
192
|
+
this.#isHighCard();
|
|
193
193
|
|
|
194
194
|
// Add keyCards and kickerCards before restoring original evaluation
|
|
195
195
|
// (these methods need access to this.evaluation)
|
|
@@ -281,18 +281,12 @@ class HandEvaluator {
|
|
|
281
281
|
* Sorts cards from highest to lowest rank using standard poker ranking (Ace high).
|
|
282
282
|
* Modifies the array in place. If no cards parameter is provided, sorts this.cards.
|
|
283
283
|
*
|
|
284
|
+
* @private
|
|
284
285
|
* @param {string[]} [cards=null] - Optional array of card strings to sort.
|
|
285
286
|
* If null or undefined, sorts this.cards instead.
|
|
286
287
|
* @returns {void}
|
|
287
|
-
* @example
|
|
288
|
-
* const evaluator = new HandEvaluator(['2s', 'As', 'Ks', '5s', 'Ts']);
|
|
289
|
-
* evaluator.sort(); // Modifies evaluator.cards to ['As', 'Ks', 'Ts', '5s', '2s']
|
|
290
|
-
*
|
|
291
|
-
* @example
|
|
292
|
-
* const cards = ['2s', 'As', 'Ks'];
|
|
293
|
-
* evaluator.sort(cards); // Modifies cards array to ['As', 'Ks', '2s']
|
|
294
288
|
*/
|
|
295
|
-
sort(cards = null) {
|
|
289
|
+
#sort(cards = null) {
|
|
296
290
|
const cardsToSort = cards || this.cards;
|
|
297
291
|
cardsToSort.sort((a, b) => this.#getRankValue(b) - this.#getRankValue(a));
|
|
298
292
|
}
|
|
@@ -302,14 +296,12 @@ class HandEvaluator {
|
|
|
302
296
|
* Modifies the array in place. Used for evaluating wheel straights (A-2-3-4-5).
|
|
303
297
|
* If no cards parameter is provided, sorts this.cards.
|
|
304
298
|
*
|
|
299
|
+
* @private
|
|
305
300
|
* @param {string[]} [cards=null] - Optional array of card strings to sort.
|
|
306
301
|
* If null or undefined, sorts this.cards instead.
|
|
307
302
|
* @returns {void}
|
|
308
|
-
* @example
|
|
309
|
-
* const evaluator = new HandEvaluator(['As', '2s', '3s', '4s', '5s']);
|
|
310
|
-
* evaluator.sortWheel(); // Modifies evaluator.cards to ['5s', '4s', '3s', '2s', 'As']
|
|
311
303
|
*/
|
|
312
|
-
sortWheel(cards = null) {
|
|
304
|
+
#sortWheel(cards = null) {
|
|
313
305
|
const cardsToSort = cards || this.cards;
|
|
314
306
|
cardsToSort.sort((a, b) => this.#getRankValueWheel(b) - this.#getRankValueWheel(a));
|
|
315
307
|
}
|
|
@@ -318,18 +310,12 @@ class HandEvaluator {
|
|
|
318
310
|
* Calculates the distance (rank difference) between the highest and lowest card.
|
|
319
311
|
* Uses standard poker ranking (Ace high). Distance of 4 indicates a possible straight.
|
|
320
312
|
*
|
|
313
|
+
* @private
|
|
321
314
|
* @param {string[]} [cards=null] - Optional array of card strings to evaluate.
|
|
322
315
|
* If null or undefined, uses this.cards instead.
|
|
323
316
|
* @returns {number} Distance between highest and lowest card (0-12)
|
|
324
|
-
* @example
|
|
325
|
-
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', 'Ts']);
|
|
326
|
-
* evaluator.getDistance(); // Returns 4 (A=13, T=9, 13-9=4)
|
|
327
|
-
*
|
|
328
|
-
* @example
|
|
329
|
-
* evaluator.getDistance(['As', '2s', '3s', '4s', '5s']);
|
|
330
|
-
* // Returns 12 (A=13, 2=1, 13-1=12)
|
|
331
317
|
*/
|
|
332
|
-
getDistance(cards = null) {
|
|
318
|
+
#getDistance(cards = null) {
|
|
333
319
|
if (cards) {
|
|
334
320
|
// If cards array provided, sort a copy and calculate distance
|
|
335
321
|
if (cards.length === 0) return 0;
|
|
@@ -338,7 +324,7 @@ class HandEvaluator {
|
|
|
338
324
|
}
|
|
339
325
|
// If no cards provided, use instance cards property
|
|
340
326
|
if (this.cards.length === 0) return 0;
|
|
341
|
-
this
|
|
327
|
+
this.#sort();
|
|
342
328
|
return this.#getRankValue(this.cards[0]) - this.#getRankValue(this.cards[this.cards.length - 1]);
|
|
343
329
|
}
|
|
344
330
|
|
|
@@ -346,14 +332,12 @@ class HandEvaluator {
|
|
|
346
332
|
* Calculates the distance (rank difference) between the highest and lowest card using wheel ranking.
|
|
347
333
|
* Uses wheel ranking (Ace low). Distance of 4 indicates a possible wheel straight (A-2-3-4-5).
|
|
348
334
|
*
|
|
335
|
+
* @private
|
|
349
336
|
* @param {string[]} [cards=null] - Optional array of card strings to evaluate.
|
|
350
337
|
* If null or undefined, uses this.cards instead.
|
|
351
338
|
* @returns {number} Distance between highest and lowest card using wheel ranking (0-12)
|
|
352
|
-
* @example
|
|
353
|
-
* const evaluator = new HandEvaluator(['As', '2s', '3s', '4s', '5s']);
|
|
354
|
-
* evaluator.getDistanceWheel(); // Returns 4 (5=5, A=1, 5-1=4) - wheel straight
|
|
355
339
|
*/
|
|
356
|
-
getDistanceWheel(cards = null) {
|
|
340
|
+
#getDistanceWheel(cards = null) {
|
|
357
341
|
if (cards) {
|
|
358
342
|
// If cards array provided, sort a copy using wheel values and calculate distance
|
|
359
343
|
if (cards.length === 0) return 0;
|
|
@@ -362,24 +346,18 @@ class HandEvaluator {
|
|
|
362
346
|
}
|
|
363
347
|
// If no cards provided, use instance cards property
|
|
364
348
|
if (this.cards.length === 0) return 0;
|
|
365
|
-
this
|
|
349
|
+
this.#sortWheel();
|
|
366
350
|
return this.#getRankValueWheel(this.cards[0]) - this.#getRankValueWheel(this.cards[this.cards.length - 1]);
|
|
367
351
|
}
|
|
368
352
|
|
|
369
353
|
/**
|
|
370
354
|
* Counts the occurrences of each suit in the hand.
|
|
371
355
|
*
|
|
356
|
+
* @private
|
|
372
357
|
* @returns {Object<string, number>} Object mapping suit to count:
|
|
373
358
|
* { s: count, h: count, d: count, c: count }
|
|
374
|
-
* @example
|
|
375
|
-
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', 'Ts']);
|
|
376
|
-
* evaluator.countSuits(); // Returns { s: 5 }
|
|
377
|
-
*
|
|
378
|
-
* @example
|
|
379
|
-
* const evaluator = new HandEvaluator(['As', 'Kh', 'Qd', 'Jc', 'Ts']);
|
|
380
|
-
* evaluator.countSuits(); // Returns { s: 2, h: 1, d: 1, c: 1 }
|
|
381
359
|
*/
|
|
382
|
-
countSuits() {
|
|
360
|
+
#countSuits() {
|
|
383
361
|
return this.cards.reduce((acc, card) => ({ ...acc, [card.slice(-1)]: (acc[card.slice(-1)] || 0) + 1 }), {});
|
|
384
362
|
}
|
|
385
363
|
|
|
@@ -387,17 +365,11 @@ class HandEvaluator {
|
|
|
387
365
|
* Counts the occurrences of each rank and returns sorted counts (descending).
|
|
388
366
|
* Used to identify pairs, three of a kind, four of a kind, etc.
|
|
389
367
|
*
|
|
368
|
+
* @private
|
|
390
369
|
* @returns {number[]} Array of rank counts sorted in descending order
|
|
391
|
-
* @example
|
|
392
|
-
* const evaluator = new HandEvaluator(['As', 'Ah', 'Ad', 'Kc', 'Ks']);
|
|
393
|
-
* evaluator.countRanks(); // Returns [3, 2] (three aces, two kings)
|
|
394
|
-
*
|
|
395
|
-
* @example
|
|
396
|
-
* const evaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Kc', 'Qs']);
|
|
397
|
-
* evaluator.countRanks(); // Returns [2, 2, 1] (two aces, two kings, one queen)
|
|
398
370
|
*/
|
|
399
|
-
countRanks() {
|
|
400
|
-
this
|
|
371
|
+
#countRanks() {
|
|
372
|
+
this.#sort();
|
|
401
373
|
const rankCounts = this.cards.reduce((acc, card) => (acc[card.slice(0, -1)] = (acc[card.slice(0, -1)] || 0) + 1, acc), {});
|
|
402
374
|
return Object.values(rankCounts).sort((a, b) => b - a);
|
|
403
375
|
}
|
|
@@ -412,7 +384,7 @@ class HandEvaluator {
|
|
|
412
384
|
* // Returns { A: 3, K: 2 }
|
|
413
385
|
*/
|
|
414
386
|
#getRankCounts() {
|
|
415
|
-
this
|
|
387
|
+
this.#sort();
|
|
416
388
|
return this.cards.reduce((acc, card) => (acc[card.slice(0, -1)] = (acc[card.slice(0, -1)] || 0) + 1, acc), {});
|
|
417
389
|
}
|
|
418
390
|
|
|
@@ -446,7 +418,7 @@ class HandEvaluator {
|
|
|
446
418
|
* // Returns [1, 1, 1, 2] (gap of 2 between J and 9)
|
|
447
419
|
*/
|
|
448
420
|
#getGaps() {
|
|
449
|
-
this
|
|
421
|
+
this.#sort();
|
|
450
422
|
const gaps = [];
|
|
451
423
|
for (let i = 0; i < 4; i++) {
|
|
452
424
|
gaps.push(this.#getRankValue(this.cards[i]) - this.#getRankValue(this.cards[i + 1]));
|
|
@@ -466,7 +438,7 @@ class HandEvaluator {
|
|
|
466
438
|
* // Returns [1, 1, 1, 1] (all gaps are 1)
|
|
467
439
|
*/
|
|
468
440
|
#getGapsWheel() {
|
|
469
|
-
this
|
|
441
|
+
this.#sortWheel();
|
|
470
442
|
const gaps = [];
|
|
471
443
|
for (let i = 0; i < 4; i++) {
|
|
472
444
|
gaps.push(this.#getRankValueWheel(this.cards[i]) - this.#getRankValueWheel(this.cards[i + 1]));
|
|
@@ -484,9 +456,9 @@ class HandEvaluator {
|
|
|
484
456
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Ad', 'Ac', 'Ks']);
|
|
485
457
|
* evaluator.isFourOfAKind(); // Returns true
|
|
486
458
|
*/
|
|
487
|
-
isFourOfAKind() {
|
|
459
|
+
#isFourOfAKind() {
|
|
488
460
|
if (this.evaluation.isFourOfAKind !== undefined) return this.evaluation.isFourOfAKind;
|
|
489
|
-
const ranks = this
|
|
461
|
+
const ranks = this.#countRanks();
|
|
490
462
|
return this.evaluation.isFourOfAKind = ranks[0] === 4 && ranks[1] === 1;
|
|
491
463
|
}
|
|
492
464
|
|
|
@@ -498,9 +470,9 @@ class HandEvaluator {
|
|
|
498
470
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Ad', 'Kc', 'Ks']);
|
|
499
471
|
* evaluator.isFullHouse(); // Returns true
|
|
500
472
|
*/
|
|
501
|
-
isFullHouse() {
|
|
473
|
+
#isFullHouse() {
|
|
502
474
|
if (this.evaluation.isFullHouse !== undefined) return this.evaluation.isFullHouse;
|
|
503
|
-
const ranks = this
|
|
475
|
+
const ranks = this.#countRanks();
|
|
504
476
|
return this.evaluation.isFullHouse = ranks[0] === 3 && ranks[1] === 2;
|
|
505
477
|
}
|
|
506
478
|
|
|
@@ -512,9 +484,9 @@ class HandEvaluator {
|
|
|
512
484
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Ad', 'Kc', 'Qs']);
|
|
513
485
|
* evaluator.isThreeOfAKind(); // Returns true
|
|
514
486
|
*/
|
|
515
|
-
isThreeOfAKind() {
|
|
487
|
+
#isThreeOfAKind() {
|
|
516
488
|
if (this.evaluation.isThreeOfAKind !== undefined) return this.evaluation.isThreeOfAKind;
|
|
517
|
-
const ranks = this
|
|
489
|
+
const ranks = this.#countRanks();
|
|
518
490
|
return this.evaluation.isThreeOfAKind = ranks[0] === 3 && ranks[1] === 1 && ranks[2] === 1;
|
|
519
491
|
}
|
|
520
492
|
|
|
@@ -526,9 +498,9 @@ class HandEvaluator {
|
|
|
526
498
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Kc', 'Qs']);
|
|
527
499
|
* evaluator.isTwoPair(); // Returns true
|
|
528
500
|
*/
|
|
529
|
-
isTwoPair() {
|
|
501
|
+
#isTwoPair() {
|
|
530
502
|
if (this.evaluation.isTwoPair !== undefined) return this.evaluation.isTwoPair;
|
|
531
|
-
const ranks = this
|
|
503
|
+
const ranks = this.#countRanks();
|
|
532
504
|
return this.evaluation.isTwoPair = ranks[0] === 2 && ranks[1] === 2 && ranks[2] === 1;
|
|
533
505
|
}
|
|
534
506
|
|
|
@@ -540,9 +512,9 @@ class HandEvaluator {
|
|
|
540
512
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Qc', 'Js']);
|
|
541
513
|
* evaluator.isPair(); // Returns true
|
|
542
514
|
*/
|
|
543
|
-
isPair() {
|
|
515
|
+
#isPair() {
|
|
544
516
|
if (this.evaluation.isPair !== undefined) return this.evaluation.isPair;
|
|
545
|
-
const ranks = this
|
|
517
|
+
const ranks = this.#countRanks();
|
|
546
518
|
return this.evaluation.isPair = ranks[0] === 2 && ranks[1] === 1 && ranks[2] === 1 && ranks[3] === 1;
|
|
547
519
|
}
|
|
548
520
|
|
|
@@ -557,9 +529,9 @@ class HandEvaluator {
|
|
|
557
529
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Qc', 'Js']);
|
|
558
530
|
* evaluator.isTopPair(); // Returns true (pair of aces, highest card)
|
|
559
531
|
*/
|
|
560
|
-
isTopPair() {
|
|
532
|
+
#isTopPair() {
|
|
561
533
|
if (this.evaluation.isTopPair !== undefined) return this.evaluation.isTopPair;
|
|
562
|
-
if (this.evaluation.isPair === undefined) this
|
|
534
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
563
535
|
if (!this.evaluation.isPair) return this.evaluation.isTopPair = false;
|
|
564
536
|
const rankCounts = this.#getRankCounts();
|
|
565
537
|
return this.evaluation.isTopPair = rankCounts[this.cards[0].slice(0, -1)] === 2;
|
|
@@ -574,10 +546,10 @@ class HandEvaluator {
|
|
|
574
546
|
* const evaluator = new HandEvaluator(['As', 'Kh', 'Kd', 'Qc', 'Js']);
|
|
575
547
|
* evaluator.isMiddlePair(); // Returns true (pair of kings, not highest or lowest)
|
|
576
548
|
*/
|
|
577
|
-
isMiddlePair() {
|
|
549
|
+
#isMiddlePair() {
|
|
578
550
|
if (this.evaluation.isMiddlePair !== undefined) return this.evaluation.isMiddlePair;
|
|
579
|
-
if (this.evaluation.isPair === undefined) this
|
|
580
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
551
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
552
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
581
553
|
if (!this.evaluation.isPair || this.evaluation.isTwoPair) return this.evaluation.isMiddlePair = false;
|
|
582
554
|
const ranks = this.#getRankCountsSorted();
|
|
583
555
|
return this.evaluation.isMiddlePair = ranks.length === 4 && (ranks[1].count === 2 || ranks[2].count === 2);
|
|
@@ -592,9 +564,9 @@ class HandEvaluator {
|
|
|
592
564
|
* const evaluator = new HandEvaluator(['As', 'Kh', 'Qd', '2c', '2s']);
|
|
593
565
|
* evaluator.isBottomPair(); // Returns true (pair of deuces, lowest card)
|
|
594
566
|
*/
|
|
595
|
-
isBottomPair() {
|
|
567
|
+
#isBottomPair() {
|
|
596
568
|
if (this.evaluation.isBottomPair !== undefined) return this.evaluation.isBottomPair;
|
|
597
|
-
if (this.evaluation.isPair === undefined) this
|
|
569
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
598
570
|
if (!this.evaluation.isPair) return this.evaluation.isBottomPair = false;
|
|
599
571
|
const rankCounts = this.#getRankCounts();
|
|
600
572
|
return this.evaluation.isBottomPair = rankCounts[this.cards[this.cards.length - 1].slice(0, -1)] === 2;
|
|
@@ -611,9 +583,9 @@ class HandEvaluator {
|
|
|
611
583
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Kc', 'Qs']);
|
|
612
584
|
* evaluator.isTopAndMiddlePair(); // Returns true (aces and kings)
|
|
613
585
|
*/
|
|
614
|
-
isTopAndMiddlePair() {
|
|
586
|
+
#isTopAndMiddlePair() {
|
|
615
587
|
if (this.evaluation.isTopAndMiddlePair !== undefined) return this.evaluation.isTopAndMiddlePair;
|
|
616
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
588
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
617
589
|
if (!this.evaluation.isTwoPair) return this.evaluation.isTopAndMiddlePair = false;
|
|
618
590
|
const ranks = this.#getRankCountsSorted();
|
|
619
591
|
return this.evaluation.isTopAndMiddlePair = ranks[0].count === 2 && ranks[1].count === 2;
|
|
@@ -628,9 +600,9 @@ class HandEvaluator {
|
|
|
628
600
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Kd', 'Qc', '2s', '2h']);
|
|
629
601
|
* evaluator.isTopAndBottomPair(); // Returns true (aces and deuces)
|
|
630
602
|
*/
|
|
631
|
-
isTopAndBottomPair() {
|
|
603
|
+
#isTopAndBottomPair() {
|
|
632
604
|
if (this.evaluation.isTopAndBottomPair !== undefined) return this.evaluation.isTopAndBottomPair;
|
|
633
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
605
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
634
606
|
if (!this.evaluation.isTwoPair) return this.evaluation.isTopAndBottomPair = false;
|
|
635
607
|
const ranks = this.#getRankCountsSorted();
|
|
636
608
|
return this.evaluation.isTopAndBottomPair = ranks[0].count === 2 && ranks[ranks.length - 1].count === 2;
|
|
@@ -645,9 +617,9 @@ class HandEvaluator {
|
|
|
645
617
|
* const evaluator = new HandEvaluator(['As', 'Kh', 'Kd', '2c', '2s']);
|
|
646
618
|
* evaluator.isMiddleAndBottomPair(); // Returns true (kings and deuces)
|
|
647
619
|
*/
|
|
648
|
-
isMiddleAndBottomPair() {
|
|
620
|
+
#isMiddleAndBottomPair() {
|
|
649
621
|
if (this.evaluation.isMiddleAndBottomPair !== undefined) return this.evaluation.isMiddleAndBottomPair;
|
|
650
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
622
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
651
623
|
if (!this.evaluation.isTwoPair) return this.evaluation.isMiddleAndBottomPair = false;
|
|
652
624
|
const ranks = this.#getRankCountsSorted();
|
|
653
625
|
return this.evaluation.isMiddleAndBottomPair = ranks.length === 3 && ranks[1].count === 2 && ranks[2].count === 2;
|
|
@@ -664,9 +636,9 @@ class HandEvaluator {
|
|
|
664
636
|
* const evaluator = new HandEvaluator(['As', 'Ah', 'Ad', 'Kc', 'Qs']);
|
|
665
637
|
* evaluator.isTopThreeOfAKind(); // Returns true (three aces)
|
|
666
638
|
*/
|
|
667
|
-
isTopThreeOfAKind() {
|
|
639
|
+
#isTopThreeOfAKind() {
|
|
668
640
|
if (this.evaluation.isTopThreeOfAKind !== undefined) return this.evaluation.isTopThreeOfAKind;
|
|
669
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
641
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
670
642
|
if (!this.evaluation.isThreeOfAKind) return this.evaluation.isTopThreeOfAKind = false;
|
|
671
643
|
const rankCounts = this.#getRankCounts();
|
|
672
644
|
return this.evaluation.isTopThreeOfAKind = rankCounts[this.cards[0].slice(0, -1)] === 3;
|
|
@@ -681,9 +653,9 @@ class HandEvaluator {
|
|
|
681
653
|
* const evaluator = new HandEvaluator(['As', 'Kh', 'Kd', 'Kc', 'Qs']);
|
|
682
654
|
* evaluator.isMiddleThreeOfAKind(); // Returns true (three kings)
|
|
683
655
|
*/
|
|
684
|
-
isMiddleThreeOfAKind() {
|
|
656
|
+
#isMiddleThreeOfAKind() {
|
|
685
657
|
if (this.evaluation.isMiddleThreeOfAKind !== undefined) return this.evaluation.isMiddleThreeOfAKind;
|
|
686
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
658
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
687
659
|
if (!this.evaluation.isThreeOfAKind) return this.evaluation.isMiddleThreeOfAKind = false;
|
|
688
660
|
const ranks = this.#getRankCountsSorted();
|
|
689
661
|
return this.evaluation.isMiddleThreeOfAKind = ranks.length === 3 && ranks[1].count === 3;
|
|
@@ -698,9 +670,9 @@ class HandEvaluator {
|
|
|
698
670
|
* const evaluator = new HandEvaluator(['As', 'Kh', '2d', '2c', '2s']);
|
|
699
671
|
* evaluator.isBottomThreeOfAKind(); // Returns true (three deuces)
|
|
700
672
|
*/
|
|
701
|
-
isBottomThreeOfAKind() {
|
|
673
|
+
#isBottomThreeOfAKind() {
|
|
702
674
|
if (this.evaluation.isBottomThreeOfAKind !== undefined) return this.evaluation.isBottomThreeOfAKind;
|
|
703
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
675
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
704
676
|
if (!this.evaluation.isThreeOfAKind) return this.evaluation.isBottomThreeOfAKind = false;
|
|
705
677
|
const rankCounts = this.#getRankCounts();
|
|
706
678
|
return this.evaluation.isBottomThreeOfAKind = rankCounts[this.cards[this.cards.length - 1].slice(0, -1)] === 3;
|
|
@@ -716,9 +688,9 @@ class HandEvaluator {
|
|
|
716
688
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', '9s']);
|
|
717
689
|
* evaluator.isFlush(); // Returns true (all spades)
|
|
718
690
|
*/
|
|
719
|
-
isFlush() {
|
|
691
|
+
#isFlush() {
|
|
720
692
|
if (this.evaluation.isFlush !== undefined) return this.evaluation.isFlush;
|
|
721
|
-
const suits = this
|
|
693
|
+
const suits = this.#countSuits();
|
|
722
694
|
return this.evaluation.isFlush = Object.values(suits).some(count => count === 5);
|
|
723
695
|
}
|
|
724
696
|
|
|
@@ -731,11 +703,11 @@ class HandEvaluator {
|
|
|
731
703
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', '9h']);
|
|
732
704
|
* evaluator.isFlushDraw(); // Returns true (4 spades, 1 heart)
|
|
733
705
|
*/
|
|
734
|
-
isFlushDraw() {
|
|
706
|
+
#isFlushDraw() {
|
|
735
707
|
if (this.evaluation.isFlushDraw !== undefined) return this.evaluation.isFlushDraw;
|
|
736
|
-
if (this.evaluation.isFlush === undefined) this
|
|
708
|
+
if (this.evaluation.isFlush === undefined) this.#isFlush();
|
|
737
709
|
if (this.evaluation.isFlush) return this.evaluation.isFlushDraw = false;
|
|
738
|
-
const suits = this
|
|
710
|
+
const suits = this.#countSuits();
|
|
739
711
|
return this.evaluation.isFlushDraw = Object.values(suits).some(count => count === 4);
|
|
740
712
|
}
|
|
741
713
|
|
|
@@ -748,12 +720,12 @@ class HandEvaluator {
|
|
|
748
720
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Jh', '9h']);
|
|
749
721
|
* evaluator.isBackdoorFlushDraw(); // Returns true (3 spades, 2 hearts)
|
|
750
722
|
*/
|
|
751
|
-
isBackdoorFlushDraw() {
|
|
723
|
+
#isBackdoorFlushDraw() {
|
|
752
724
|
if (this.evaluation.isBackdoorFlushDraw !== undefined) return this.evaluation.isBackdoorFlushDraw;
|
|
753
|
-
if (this.evaluation.isFlush === undefined) this
|
|
754
|
-
if (this.evaluation.isFlushDraw === undefined) this
|
|
725
|
+
if (this.evaluation.isFlush === undefined) this.#isFlush();
|
|
726
|
+
if (this.evaluation.isFlushDraw === undefined) this.#isFlushDraw();
|
|
755
727
|
if (this.evaluation.isFlush || this.evaluation.isFlushDraw) return this.evaluation.isBackdoorFlushDraw = false;
|
|
756
|
-
const suits = this
|
|
728
|
+
const suits = this.#countSuits();
|
|
757
729
|
return this.evaluation.isBackdoorFlushDraw = Object.values(suits).some(count => count === 3);
|
|
758
730
|
}
|
|
759
731
|
|
|
@@ -773,18 +745,18 @@ class HandEvaluator {
|
|
|
773
745
|
* const evaluator = new HandEvaluator(['As', '2s', '3s', '4s', '5s']);
|
|
774
746
|
* evaluator.isStraight(); // Returns true (wheel: A-2-3-4-5)
|
|
775
747
|
*/
|
|
776
|
-
isStraight() {
|
|
748
|
+
#isStraight() {
|
|
777
749
|
if (this.evaluation.isStraight !== undefined) return this.evaluation.isStraight;
|
|
778
|
-
if (this.evaluation.isPair === undefined) this
|
|
779
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
780
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
781
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
782
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
750
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
751
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
752
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
753
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
754
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
783
755
|
if (this.evaluation.isPair || this.evaluation.isTwoPair || this.evaluation.isThreeOfAKind || this.evaluation.isFullHouse || this.evaluation.isFourOfAKind) return this.evaluation.isStraight = false;
|
|
784
|
-
this
|
|
785
|
-
const distance = this
|
|
756
|
+
this.#sort();
|
|
757
|
+
const distance = this.#getDistance();
|
|
786
758
|
if (distance === 4) return this.evaluation.isStraight = true;
|
|
787
|
-
|
|
759
|
+
if (this.#isStraightWheel()) return this.evaluation.isStraight = true;
|
|
788
760
|
return this.evaluation.isStraight = false;
|
|
789
761
|
}
|
|
790
762
|
|
|
@@ -797,16 +769,16 @@ class HandEvaluator {
|
|
|
797
769
|
* const evaluator = new HandEvaluator(['As', '2s', '3s', '4s', '5s']);
|
|
798
770
|
* evaluator.isStraightWheel(); // Returns true (wheel: A-2-3-4-5)
|
|
799
771
|
*/
|
|
800
|
-
isStraightWheel() {
|
|
772
|
+
#isStraightWheel() {
|
|
801
773
|
if (this.evaluation.isStraightWheel !== undefined) return this.evaluation.isStraightWheel;
|
|
802
|
-
if (this.evaluation.isPair === undefined) this
|
|
803
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
804
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
805
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
806
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
774
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
775
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
776
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
777
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
778
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
807
779
|
if (this.evaluation.isPair || this.evaluation.isTwoPair || this.evaluation.isThreeOfAKind || this.evaluation.isFullHouse || this.evaluation.isFourOfAKind) return this.evaluation.isStraightWheel = false;
|
|
808
|
-
this
|
|
809
|
-
const distance = this
|
|
780
|
+
this.#sortWheel();
|
|
781
|
+
const distance = this.#getDistanceWheel();
|
|
810
782
|
return this.evaluation.isStraightWheel = distance === 4;
|
|
811
783
|
}
|
|
812
784
|
|
|
@@ -819,10 +791,10 @@ class HandEvaluator {
|
|
|
819
791
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', 'Ts']);
|
|
820
792
|
* evaluator.isRoyalFlush(); // Returns true
|
|
821
793
|
*/
|
|
822
|
-
isRoyalFlush() {
|
|
794
|
+
#isRoyalFlush() {
|
|
823
795
|
if (this.evaluation.isRoyalFlush !== undefined) return this.evaluation.isRoyalFlush;
|
|
824
|
-
if (this.evaluation.isFlush === undefined) this
|
|
825
|
-
if (this.evaluation.isStraight === undefined) this
|
|
796
|
+
if (this.evaluation.isFlush === undefined) this.#isFlush();
|
|
797
|
+
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
826
798
|
if (!this.evaluation.isFlush || !this.evaluation.isStraight) return this.evaluation.isRoyalFlush = false;
|
|
827
799
|
const ranks = new Set(this.cards.map(c => c.slice(0, -1)));
|
|
828
800
|
return this.evaluation.isRoyalFlush = ranks.has('A') && ranks.has('K') && ranks.has('Q') && ranks.has('J') && ranks.has('T');
|
|
@@ -837,11 +809,11 @@ class HandEvaluator {
|
|
|
837
809
|
* const evaluator = new HandEvaluator(['9s', '8s', '7s', '6s', '5s']);
|
|
838
810
|
* evaluator.isStraightFlush(); // Returns true
|
|
839
811
|
*/
|
|
840
|
-
isStraightFlush() {
|
|
812
|
+
#isStraightFlush() {
|
|
841
813
|
if (this.evaluation.isStraightFlush !== undefined) return this.evaluation.isStraightFlush;
|
|
842
|
-
if (this.evaluation.isFlush === undefined) this
|
|
843
|
-
if (this.evaluation.isStraight === undefined) this
|
|
844
|
-
if (this.evaluation.isRoyalFlush === undefined) this
|
|
814
|
+
if (this.evaluation.isFlush === undefined) this.#isFlush();
|
|
815
|
+
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
816
|
+
if (this.evaluation.isRoyalFlush === undefined) this.#isRoyalFlush();
|
|
845
817
|
return this.evaluation.isStraightFlush = this.evaluation.isFlush && this.evaluation.isStraight && !this.evaluation.isRoyalFlush;
|
|
846
818
|
}
|
|
847
819
|
|
|
@@ -857,24 +829,24 @@ class HandEvaluator {
|
|
|
857
829
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', '9h']);
|
|
858
830
|
* evaluator.isOpenEndedStraightDraw(); // Returns true (needs T or 9 to complete straight)
|
|
859
831
|
*/
|
|
860
|
-
isOpenEndedStraightDraw() {
|
|
832
|
+
#isOpenEndedStraightDraw() {
|
|
861
833
|
if (this.evaluation.isOpenEndedStraightDraw !== undefined) return this.evaluation.isOpenEndedStraightDraw;
|
|
862
|
-
if (this.evaluation.isPair === undefined) this
|
|
863
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
864
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
865
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
866
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
867
|
-
if (this.evaluation.isStraight === undefined) this
|
|
834
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
835
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
836
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
837
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
838
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
839
|
+
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
868
840
|
if (this.evaluation.isPair || this.evaluation.isTwoPair || this.evaluation.isThreeOfAKind || this.evaluation.isFullHouse || this.evaluation.isFourOfAKind || this.evaluation.isStraight) {
|
|
869
841
|
// Check wheel equivalent before returning false
|
|
870
|
-
if (this
|
|
842
|
+
if (this.#isOpenEndedStraightDrawWheel()) return this.evaluation.isOpenEndedStraightDraw = true;
|
|
871
843
|
return this.evaluation.isOpenEndedStraightDraw = false;
|
|
872
844
|
}
|
|
873
|
-
this
|
|
874
|
-
const result = this
|
|
845
|
+
this.#sort();
|
|
846
|
+
const result = this.#getDistance(this.cards.slice(0,4)) === 3 || this.#getDistance(this.cards.slice(1,5)) === 3;
|
|
875
847
|
if (result) return this.evaluation.isOpenEndedStraightDraw = true;
|
|
876
848
|
// Check wheel equivalent
|
|
877
|
-
if (this
|
|
849
|
+
if (this.#isOpenEndedStraightDrawWheel()) return this.evaluation.isOpenEndedStraightDraw = true;
|
|
878
850
|
return this.evaluation.isOpenEndedStraightDraw = false;
|
|
879
851
|
}
|
|
880
852
|
|
|
@@ -885,17 +857,17 @@ class HandEvaluator {
|
|
|
885
857
|
*
|
|
886
858
|
* @returns {boolean} True if the hand is a wheel-equivalent open-ended straight draw, false otherwise
|
|
887
859
|
*/
|
|
888
|
-
isOpenEndedStraightDrawWheel() {
|
|
860
|
+
#isOpenEndedStraightDrawWheel() {
|
|
889
861
|
if (this.evaluation.isOpenEndedStraightDrawWheel !== undefined) return this.evaluation.isOpenEndedStraightDrawWheel;
|
|
890
|
-
if (this.evaluation.isPair === undefined) this
|
|
891
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
892
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
893
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
894
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
895
|
-
if (this.evaluation.isStraightWheel === undefined) this
|
|
862
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
863
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
864
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
865
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
866
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
867
|
+
if (this.evaluation.isStraightWheel === undefined) this.#isStraightWheel();
|
|
896
868
|
if (this.evaluation.isPair || this.evaluation.isTwoPair || this.evaluation.isThreeOfAKind || this.evaluation.isFullHouse || this.evaluation.isFourOfAKind || this.evaluation.isStraightWheel) return this.evaluation.isOpenEndedStraightDrawWheel = false;
|
|
897
|
-
this
|
|
898
|
-
return this.evaluation.isOpenEndedStraightDrawWheel = this
|
|
869
|
+
this.#sortWheel();
|
|
870
|
+
return this.evaluation.isOpenEndedStraightDrawWheel = this.#getDistanceWheel(this.cards.slice(0,4)) === 3 || this.#getDistanceWheel(this.cards.slice(1,5)) === 3;
|
|
899
871
|
}
|
|
900
872
|
|
|
901
873
|
/**
|
|
@@ -908,25 +880,25 @@ class HandEvaluator {
|
|
|
908
880
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', '9h']);
|
|
909
881
|
* evaluator.isInsideStraightDraw(); // Returns true (needs T in the middle)
|
|
910
882
|
*/
|
|
911
|
-
isInsideStraightDraw() {
|
|
883
|
+
#isInsideStraightDraw() {
|
|
912
884
|
if (this.evaluation.isInsideStraightDraw !== undefined) return this.evaluation.isInsideStraightDraw;
|
|
913
|
-
if (this.evaluation.isPair === undefined) this
|
|
914
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
915
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
916
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
917
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
918
|
-
if (this.evaluation.isStraight === undefined) this
|
|
885
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
886
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
887
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
888
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
889
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
890
|
+
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
919
891
|
if (this.evaluation.isPair || this.evaluation.isTwoPair || this.evaluation.isThreeOfAKind || this.evaluation.isFullHouse || this.evaluation.isFourOfAKind || this.evaluation.isStraight) {
|
|
920
892
|
// Check wheel equivalent before returning false
|
|
921
|
-
if (this
|
|
893
|
+
if (this.#isInsideStraightDrawWheel()) return this.evaluation.isInsideStraightDraw = true;
|
|
922
894
|
return this.evaluation.isInsideStraightDraw = false;
|
|
923
895
|
}
|
|
924
896
|
|
|
925
|
-
this
|
|
926
|
-
const result = this
|
|
897
|
+
this.#sort();
|
|
898
|
+
const result = this.#getDistance(this.cards.slice(0,4)) === 4 || this.#getDistance(this.cards.slice(1,5)) === 4;
|
|
927
899
|
if (result) return this.evaluation.isInsideStraightDraw = true;
|
|
928
900
|
// Check wheel equivalent
|
|
929
|
-
if (this
|
|
901
|
+
if (this.#isInsideStraightDrawWheel()) return this.evaluation.isInsideStraightDraw = true;
|
|
930
902
|
return this.evaluation.isInsideStraightDraw = false;
|
|
931
903
|
}
|
|
932
904
|
|
|
@@ -937,18 +909,18 @@ class HandEvaluator {
|
|
|
937
909
|
*
|
|
938
910
|
* @returns {boolean} True if the hand is a wheel-equivalent inside straight draw, false otherwise
|
|
939
911
|
*/
|
|
940
|
-
isInsideStraightDrawWheel() {
|
|
912
|
+
#isInsideStraightDrawWheel() {
|
|
941
913
|
if (this.evaluation.isInsideStraightDrawWheel !== undefined) return this.evaluation.isInsideStraightDrawWheel;
|
|
942
|
-
if (this.evaluation.isPair === undefined) this
|
|
943
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
944
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
945
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
946
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
947
|
-
if (this.evaluation.isStraightWheel === undefined) this
|
|
914
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
915
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
916
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
917
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
918
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
919
|
+
if (this.evaluation.isStraightWheel === undefined) this.#isStraightWheel();
|
|
948
920
|
if (this.evaluation.isPair || this.evaluation.isTwoPair || this.evaluation.isThreeOfAKind || this.evaluation.isFullHouse || this.evaluation.isFourOfAKind || this.evaluation.isStraightWheel) return this.evaluation.isInsideStraightDrawWheel = false;
|
|
949
921
|
|
|
950
|
-
this
|
|
951
|
-
return this.evaluation.isInsideStraightDrawWheel = this
|
|
922
|
+
this.#sortWheel();
|
|
923
|
+
return this.evaluation.isInsideStraightDrawWheel = this.#getDistanceWheel(this.cards.slice(0,4)) === 4 || this.#getDistanceWheel(this.cards.slice(1,5)) === 4;
|
|
952
924
|
}
|
|
953
925
|
|
|
954
926
|
/**
|
|
@@ -964,10 +936,10 @@ class HandEvaluator {
|
|
|
964
936
|
* const evaluator = new HandEvaluator(['As', 'Ks', 'Qs', 'Js', '8h']);
|
|
965
937
|
* evaluator.isStraightDraw(); // Returns true (inside straight draw)
|
|
966
938
|
*/
|
|
967
|
-
isStraightDraw() {
|
|
939
|
+
#isStraightDraw() {
|
|
968
940
|
if (this.evaluation.isStraightDraw !== undefined) return this.evaluation.isStraightDraw;
|
|
969
|
-
if (this.evaluation.isOpenEndedStraightDraw === undefined) this
|
|
970
|
-
if (this.evaluation.isInsideStraightDraw === undefined) this
|
|
941
|
+
if (this.evaluation.isOpenEndedStraightDraw === undefined) this.#isOpenEndedStraightDraw();
|
|
942
|
+
if (this.evaluation.isInsideStraightDraw === undefined) this.#isInsideStraightDraw();
|
|
971
943
|
return this.evaluation.isStraightDraw = this.evaluation.isOpenEndedStraightDraw || this.evaluation.isInsideStraightDraw;
|
|
972
944
|
}
|
|
973
945
|
|
|
@@ -982,14 +954,14 @@ class HandEvaluator {
|
|
|
982
954
|
*/
|
|
983
955
|
#getStraightCards() {
|
|
984
956
|
// Try standard straight first
|
|
985
|
-
this
|
|
957
|
+
this.#sort();
|
|
986
958
|
const gaps = this.#getGaps();
|
|
987
959
|
if (gaps.every(g => g === 1)) {
|
|
988
960
|
return [...this.cards].sort((a, b) => this.#getRankValue(b) - this.#getRankValue(a));
|
|
989
961
|
}
|
|
990
962
|
|
|
991
963
|
// Try wheel straight
|
|
992
|
-
this
|
|
964
|
+
this.#sortWheel();
|
|
993
965
|
const gapsWheel = this.#getGapsWheel();
|
|
994
966
|
if (gapsWheel.every(g => g === 1)) {
|
|
995
967
|
// Convert back to standard sorting for return
|
|
@@ -1008,29 +980,29 @@ class HandEvaluator {
|
|
|
1008
980
|
*/
|
|
1009
981
|
#getStraightDrawCards() {
|
|
1010
982
|
// Try standard straight draw
|
|
1011
|
-
this
|
|
983
|
+
this.#sort();
|
|
1012
984
|
const firstFour = this.cards.slice(0, 4);
|
|
1013
985
|
const lastFour = this.cards.slice(1, 5);
|
|
1014
986
|
|
|
1015
|
-
const firstFourDist = this
|
|
987
|
+
const firstFourDist = this.#getDistance(firstFour);
|
|
1016
988
|
if (firstFourDist === 3 || firstFourDist === 4) {
|
|
1017
989
|
return [...firstFour].sort((a, b) => this.#getRankValue(b) - this.#getRankValue(a));
|
|
1018
990
|
}
|
|
1019
|
-
const lastFourDist = this
|
|
991
|
+
const lastFourDist = this.#getDistance(lastFour);
|
|
1020
992
|
if (lastFourDist === 3 || lastFourDist === 4) {
|
|
1021
993
|
return [...lastFour].sort((a, b) => this.#getRankValue(b) - this.#getRankValue(a));
|
|
1022
994
|
}
|
|
1023
995
|
|
|
1024
996
|
// Try wheel straight draw
|
|
1025
|
-
this
|
|
997
|
+
this.#sortWheel();
|
|
1026
998
|
const firstFourWheel = this.cards.slice(0, 4);
|
|
1027
999
|
const lastFourWheel = this.cards.slice(1, 5);
|
|
1028
1000
|
|
|
1029
|
-
const firstFourDistWheel = this
|
|
1001
|
+
const firstFourDistWheel = this.#getDistanceWheel(firstFourWheel);
|
|
1030
1002
|
if (firstFourDistWheel === 3 || firstFourDistWheel === 4) {
|
|
1031
1003
|
return [...firstFourWheel].sort((a, b) => this.#getRankValueWheel(b) - this.#getRankValueWheel(a));
|
|
1032
1004
|
}
|
|
1033
|
-
const lastFourDistWheel = this
|
|
1005
|
+
const lastFourDistWheel = this.#getDistanceWheel(lastFourWheel);
|
|
1034
1006
|
if (lastFourDistWheel === 3 || lastFourDistWheel === 4) {
|
|
1035
1007
|
return [...lastFourWheel].sort((a, b) => this.#getRankValueWheel(b) - this.#getRankValueWheel(a));
|
|
1036
1008
|
}
|
|
@@ -1051,7 +1023,7 @@ class HandEvaluator {
|
|
|
1051
1023
|
|
|
1052
1024
|
// Calculate these once and reuse
|
|
1053
1025
|
const rankCounts = this.#getRankCounts();
|
|
1054
|
-
const suits = this
|
|
1026
|
+
const suits = this.#countSuits();
|
|
1055
1027
|
|
|
1056
1028
|
// Use evaluation results directly - no re-checking
|
|
1057
1029
|
// Check made hands in priority order
|
|
@@ -1150,15 +1122,15 @@ class HandEvaluator {
|
|
|
1150
1122
|
* const evaluator = new HandEvaluator(['As', 'Kh', 'Qd', 'Jc', '9s']);
|
|
1151
1123
|
* evaluator.isHighCard(); // Returns true (no made hand)
|
|
1152
1124
|
*/
|
|
1153
|
-
isHighCard() {
|
|
1125
|
+
#isHighCard() {
|
|
1154
1126
|
if (this.evaluation.isHighCard !== undefined) return this.evaluation.isHighCard;
|
|
1155
|
-
if (this.evaluation.isPair === undefined) this
|
|
1156
|
-
if (this.evaluation.isTwoPair === undefined) this
|
|
1157
|
-
if (this.evaluation.isThreeOfAKind === undefined) this
|
|
1158
|
-
if (this.evaluation.isFullHouse === undefined) this
|
|
1159
|
-
if (this.evaluation.isFourOfAKind === undefined) this
|
|
1160
|
-
if (this.evaluation.isFlush === undefined) this
|
|
1161
|
-
if (this.evaluation.isStraight === undefined) this
|
|
1127
|
+
if (this.evaluation.isPair === undefined) this.#isPair();
|
|
1128
|
+
if (this.evaluation.isTwoPair === undefined) this.#isTwoPair();
|
|
1129
|
+
if (this.evaluation.isThreeOfAKind === undefined) this.#isThreeOfAKind();
|
|
1130
|
+
if (this.evaluation.isFullHouse === undefined) this.#isFullHouse();
|
|
1131
|
+
if (this.evaluation.isFourOfAKind === undefined) this.#isFourOfAKind();
|
|
1132
|
+
if (this.evaluation.isFlush === undefined) this.#isFlush();
|
|
1133
|
+
if (this.evaluation.isStraight === undefined) this.#isStraight();
|
|
1162
1134
|
return this.evaluation.isHighCard = !this.evaluation.isPair && !this.evaluation.isTwoPair && !this.evaluation.isThreeOfAKind && !this.evaluation.isFullHouse && !this.evaluation.isFourOfAKind && !this.evaluation.isFlush && !this.evaluation.isStraight;
|
|
1163
1135
|
}
|
|
1164
1136
|
}
|