poker-extval 3.1.0 → 3.1.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.
- package/evaluator.js +118 -7
- package/package.json +1 -1
package/evaluator.js
CHANGED
|
@@ -275,6 +275,121 @@ class HandEvaluator {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Gets the hand strength value for an evaluation.
|
|
280
|
+
*
|
|
281
|
+
* @private
|
|
282
|
+
* @param {Object} evaluation - The evaluation object
|
|
283
|
+
* @returns {number} Hand strength (10 = Royal Flush, 1 = High Card, 0 = no made hand)
|
|
284
|
+
*/
|
|
285
|
+
#getHandStrength(evaluation) {
|
|
286
|
+
const handStrength = {
|
|
287
|
+
isRoyalFlush: 10, isStraightFlush: 9, isFourOfAKind: 8,
|
|
288
|
+
isFullHouse: 7, isFlush: 6, isStraight: 5, isThreeOfAKind: 4,
|
|
289
|
+
isTwoPair: 3, isPair: 2, isHighCard: 1
|
|
290
|
+
};
|
|
291
|
+
for (const [hand, strength] of Object.entries(handStrength)) {
|
|
292
|
+
if (evaluation[hand]) return strength;
|
|
293
|
+
}
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Gets sorted key card ranks for an evaluation.
|
|
299
|
+
*
|
|
300
|
+
* @private
|
|
301
|
+
* @param {Object} evaluation - The evaluation object
|
|
302
|
+
* @returns {number[]} Array of rank values sorted descending
|
|
303
|
+
*/
|
|
304
|
+
#getKeyCardRanks(evaluation) {
|
|
305
|
+
const handStrength = {
|
|
306
|
+
isRoyalFlush: 10, isStraightFlush: 9, isFourOfAKind: 8,
|
|
307
|
+
isFullHouse: 7, isFlush: 6, isStraight: 5, isThreeOfAKind: 4,
|
|
308
|
+
isTwoPair: 3, isPair: 2, isHighCard: 1
|
|
309
|
+
};
|
|
310
|
+
for (const [hand] of Object.entries(handStrength)) {
|
|
311
|
+
if (evaluation[hand]) {
|
|
312
|
+
const keyCards = evaluation.keyCards[hand] || [];
|
|
313
|
+
return keyCards.map(c => this.#getRankValue(c)).sort((a, b) => b - a);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Gets sorted kicker ranks for an evaluation.
|
|
321
|
+
*
|
|
322
|
+
* @private
|
|
323
|
+
* @param {Object} evaluation - The evaluation object
|
|
324
|
+
* @returns {number[]} Array of rank values sorted descending
|
|
325
|
+
*/
|
|
326
|
+
#getKickerRanks(evaluation) {
|
|
327
|
+
const handStrength = {
|
|
328
|
+
isRoyalFlush: 10, isStraightFlush: 9, isFourOfAKind: 8,
|
|
329
|
+
isFullHouse: 7, isFlush: 6, isStraight: 5, isThreeOfAKind: 4,
|
|
330
|
+
isTwoPair: 3, isPair: 2, isHighCard: 1
|
|
331
|
+
};
|
|
332
|
+
for (const [hand] of Object.entries(handStrength)) {
|
|
333
|
+
if (evaluation[hand]) {
|
|
334
|
+
const kickers = evaluation.kickerCards[hand] || [];
|
|
335
|
+
return kickers.map(c => this.#getRankValue(c)).sort((a, b) => b - a);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return [];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Compares two evaluations to determine which is better.
|
|
343
|
+
*
|
|
344
|
+
* @private
|
|
345
|
+
* @param {Object} eval1 - First evaluation object
|
|
346
|
+
* @param {Object} eval2 - Second evaluation object
|
|
347
|
+
* @returns {number} Positive if eval2 is better, negative if eval1 is better, 0 if equal
|
|
348
|
+
*/
|
|
349
|
+
#compareEvaluations(eval1, eval2) {
|
|
350
|
+
const strength1 = this.#getHandStrength(eval1);
|
|
351
|
+
const strength2 = this.#getHandStrength(eval2);
|
|
352
|
+
if (strength1 !== strength2) return strength2 - strength1;
|
|
353
|
+
|
|
354
|
+
const keyRanks1 = this.#getKeyCardRanks(eval1);
|
|
355
|
+
const keyRanks2 = this.#getKeyCardRanks(eval2);
|
|
356
|
+
for (let i = 0; i < Math.max(keyRanks1.length, keyRanks2.length); i++) {
|
|
357
|
+
const rank1 = keyRanks1[i] || 0;
|
|
358
|
+
const rank2 = keyRanks2[i] || 0;
|
|
359
|
+
if (rank1 !== rank2) return rank2 - rank1;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const kickerRanks1 = this.#getKickerRanks(eval1);
|
|
363
|
+
const kickerRanks2 = this.#getKickerRanks(eval2);
|
|
364
|
+
for (let i = 0; i < Math.max(kickerRanks1.length, kickerRanks2.length); i++) {
|
|
365
|
+
const rank1 = kickerRanks1[i] || 0;
|
|
366
|
+
const rank2 = kickerRanks2[i] || 0;
|
|
367
|
+
if (rank1 !== rank2) return rank2 - rank1;
|
|
368
|
+
}
|
|
369
|
+
return 0;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Finds the best combination from a result object.
|
|
374
|
+
*
|
|
375
|
+
* @private
|
|
376
|
+
* @param {Object} result - Object mapping hand keys to evaluation objects
|
|
377
|
+
* @returns {Object} Object with only the best combination
|
|
378
|
+
*/
|
|
379
|
+
#findBestCombination(result) {
|
|
380
|
+
let bestKey = null;
|
|
381
|
+
let bestEval = null;
|
|
382
|
+
for (const [key, evaluation] of Object.entries(result)) {
|
|
383
|
+
const strength = this.#getHandStrength(evaluation);
|
|
384
|
+
const bestStrength = bestEval ? this.#getHandStrength(bestEval) : 0;
|
|
385
|
+
if (!bestEval || strength > bestStrength || (strength === bestStrength && this.#compareEvaluations(evaluation, bestEval) > 0)) {
|
|
386
|
+
bestKey = key;
|
|
387
|
+
bestEval = evaluation;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return bestKey ? { [bestKey]: bestEval } : result;
|
|
391
|
+
}
|
|
392
|
+
|
|
278
393
|
/**
|
|
279
394
|
* Evaluates all possible 5-card combinations from the input cards.
|
|
280
395
|
* For exactly 5 cards, evaluates directly. For more cards, generates all combinations
|
|
@@ -290,26 +405,22 @@ class HandEvaluator {
|
|
|
290
405
|
* // With 7 cards: returns object with 21 key-value pairs (C(7,5) = 21)
|
|
291
406
|
*/
|
|
292
407
|
#evaluateAllCombinations() {
|
|
293
|
-
// If exactly 5 cards, evaluate directly and wrap in the new format
|
|
294
408
|
if (this.cards.length === 5) {
|
|
295
409
|
const key = this.#formatHandKey(this.cards);
|
|
296
410
|
const evaluation = this.#evaluateSingleHand();
|
|
297
411
|
return { [key]: evaluation };
|
|
298
412
|
}
|
|
299
413
|
|
|
300
|
-
// For more than 5 cards, generate all combinations
|
|
301
414
|
const combinations = this.#generateCombinations(this.cards, 5);
|
|
302
415
|
const result = {};
|
|
303
416
|
for (const combination of combinations) {
|
|
304
417
|
const key = this.#formatHandKey(combination);
|
|
305
|
-
|
|
306
|
-
// This will evaluate directly since it's exactly 5 cards
|
|
307
|
-
const tempEvaluator = new HandEvaluator(combination);
|
|
308
|
-
// Extract the evaluation object from the single key-value pair
|
|
418
|
+
const tempEvaluator = new HandEvaluator(combination, this.strict);
|
|
309
419
|
const evaluationKey = Object.keys(tempEvaluator.evaluation)[0];
|
|
310
420
|
result[key] = tempEvaluator.evaluation[evaluationKey];
|
|
311
421
|
}
|
|
312
|
-
|
|
422
|
+
|
|
423
|
+
return this.strict ? this.#findBestCombination(result) : result;
|
|
313
424
|
}
|
|
314
425
|
|
|
315
426
|
/**
|