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.
Files changed (2) hide show
  1. package/evaluator.js +118 -7
  2. 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
- // Create a temporary evaluator with the 5-card combination
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
- return result;
422
+
423
+ return this.strict ? this.#findBestCombination(result) : result;
313
424
  }
314
425
 
315
426
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poker-extval",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Poker hand evaluator with comprehensive test suite",
5
5
  "main": "evaluator.js",
6
6
  "files": [