@block52/poker-vm-sdk 1.12.0 → 1.12.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/dist/index.d.ts CHANGED
@@ -46220,7 +46220,11 @@ declare class PokerSolver {
46220
46220
  /**
46221
46221
  * Evaluate a 5-card poker hand
46222
46222
  */
46223
- private static evaluateHand;
46223
+ /**
46224
+ * Evaluate exactly 5 cards (a winner's best hand, WinnerDTO.cards). Use
46225
+ * findBestHand for 7.
46226
+ */
46227
+ static evaluateHand(cards: Card[]): HandEvaluation;
46224
46228
  /**
46225
46229
  * Check if cards form a straight (excluding low straight A-2-3-4-5)
46226
46230
  */
@@ -46490,11 +46494,47 @@ declare class PokerGameIntegration {
46490
46494
  hand2Evaluation: HandEvaluation;
46491
46495
  };
46492
46496
  /**
46493
- * Create a formatted hand description for UI display
46497
+ * The winning hand in words, from the winner's best five cards
46498
+ * (WinnerDTO.cards) and the board (communityCards): "Full House, Eights
46499
+ * over Sevens", "Diamond Flush, Six high", "Set of Sevens". The board tells
46500
+ * a set (pocket pair plus one on the board) from trips (one hole card plus a
46501
+ * board pair, or all three on the board), which the five cards alone can't.
46502
+ * @param cards The winner's five card mnemonics ("6D")
46503
+ * @param board The community cards
46504
+ * @returns The hand in words, or "" for an uncontested pot (no cards)
46505
+ */
46506
+ static describeWinningHand(cards: string[] | undefined, board: string[]): string;
46507
+ /**
46508
+ * Fill in each winner's name and description from its cards and the board.
46509
+ * The engine no longer writes the hand's wording into chain state
46510
+ * (poker-vm#2721), so callers run game state through this as it arrives and
46511
+ * keep reading winner.name / winner.description as before.
46512
+ *
46513
+ * A winner with five cards gets "Full House, Eights over Sevens" in both
46514
+ * fields. A winner without five cards (an uncontested pot, or an older state
46515
+ * that recorded hole cards) is returned unchanged.
46516
+ *
46517
+ * Returns a new state object; the input is not modified.
46518
+ * @param state Any game state with winners and community cards
46519
+ */
46520
+ static withWinnerDescriptions<T extends {
46521
+ winners: WinnerDTO[];
46522
+ communityCards: string[];
46523
+ }>(state: T): T;
46524
+ /**
46525
+ * The hand description in words: "Full House, Eights over Sevens", "Quad
46526
+ * Fours", "Diamond Flush, Six high", "Ace high". A flush names its suit from
46527
+ * the best hand. The rank and suit words mirror @block52/deck's rankName /
46528
+ * suitName.
46494
46529
  * @param evaluation Hand evaluation result
46495
46530
  * @returns Human-readable hand description
46496
46531
  */
46497
46532
  static formatHandDescription(evaluation: HandEvaluation): string;
46533
+ private static readonly RANK_WORDS;
46534
+ /** A high-ace rank spelled out ("Ace", "Ten"); plural gives "Aces", "Sixes". */
46535
+ private static rankWord;
46536
+ /** The suit word every card of a flush shares ("Diamond"), or "" when the hand is empty or mixed. */
46537
+ private static flushSuitWord;
46498
46538
  /**
46499
46539
  * Example usage with string cards (for testing/debugging)
46500
46540
  * @param playerCardStrings Array of player hands as mnemonic strings
package/dist/index.esm.js CHANGED
@@ -57114,6 +57114,10 @@ class PokerSolver {
57114
57114
  /**
57115
57115
  * Evaluate a 5-card poker hand
57116
57116
  */
57117
+ /**
57118
+ * Evaluate exactly 5 cards (a winner's best hand, WinnerDTO.cards). Use
57119
+ * findBestHand for 7.
57120
+ */
57117
57121
  static evaluateHand(cards) {
57118
57122
  if (cards.length !== 5) {
57119
57123
  throw new Error("Hand evaluation requires exactly 5 cards");
@@ -58191,37 +58195,116 @@ class PokerGameIntegration {
58191
58195
  };
58192
58196
  }
58193
58197
  /**
58194
- * Create a formatted hand description for UI display
58198
+ * The winning hand in words, from the winner's best five cards
58199
+ * (WinnerDTO.cards) and the board (communityCards): "Full House, Eights
58200
+ * over Sevens", "Diamond Flush, Six high", "Set of Sevens". The board tells
58201
+ * a set (pocket pair plus one on the board) from trips (one hole card plus a
58202
+ * board pair, or all three on the board), which the five cards alone can't.
58203
+ * @param cards The winner's five card mnemonics ("6D")
58204
+ * @param board The community cards
58205
+ * @returns The hand in words, or "" for an uncontested pot (no cards)
58206
+ */
58207
+ static describeWinningHand(cards, board) {
58208
+ if (!cards || cards.length === 0)
58209
+ return "";
58210
+ if (cards.length !== 5) {
58211
+ throw new Error(`describeWinningHand expects the winning five cards, got ${cards.length}`);
58212
+ }
58213
+ const evaluation = PokerSolver.evaluateHand(cards.map(c => Deck.fromString(c)));
58214
+ if (evaluation.handType === HandType.THREE_OF_A_KIND) {
58215
+ const tripRank = evaluation.rankValues[0];
58216
+ const onBoard = board.map(c => Deck.fromString(c)).filter(c => (c.rank === 1 ? 14 : c.rank) === tripRank).length;
58217
+ if (onBoard === 1)
58218
+ return `Set of ${this.rankWord(tripRank, true)}`;
58219
+ }
58220
+ return this.formatHandDescription(evaluation);
58221
+ }
58222
+ /**
58223
+ * Fill in each winner's name and description from its cards and the board.
58224
+ * The engine no longer writes the hand's wording into chain state
58225
+ * (poker-vm#2721), so callers run game state through this as it arrives and
58226
+ * keep reading winner.name / winner.description as before.
58227
+ *
58228
+ * A winner with five cards gets "Full House, Eights over Sevens" in both
58229
+ * fields. A winner without five cards (an uncontested pot, or an older state
58230
+ * that recorded hole cards) is returned unchanged.
58231
+ *
58232
+ * Returns a new state object; the input is not modified.
58233
+ * @param state Any game state with winners and community cards
58234
+ */
58235
+ static withWinnerDescriptions(state) {
58236
+ const winners = state.winners.map(winner => {
58237
+ if (!winner.cards || winner.cards.length !== 5)
58238
+ return winner;
58239
+ const description = this.describeWinningHand(winner.cards, state.communityCards);
58240
+ return { ...winner, name: description, description };
58241
+ });
58242
+ return { ...state, winners };
58243
+ }
58244
+ /**
58245
+ * The hand description in words: "Full House, Eights over Sevens", "Quad
58246
+ * Fours", "Diamond Flush, Six high", "Ace high". A flush names its suit from
58247
+ * the best hand. The rank and suit words mirror @block52/deck's rankName /
58248
+ * suitName.
58195
58249
  * @param evaluation Hand evaluation result
58196
58250
  * @returns Human-readable hand description
58197
58251
  */
58198
58252
  static formatHandDescription(evaluation) {
58199
- const { handType, rankValues, description } = evaluation;
58253
+ const { handType, rankValues, description, bestHand } = evaluation;
58254
+ const suit = this.flushSuitWord(bestHand);
58255
+ const suited = (hand) => (suit ? `${suit} ${hand}` : hand);
58200
58256
  switch (handType) {
58201
58257
  case HandType.ROYAL_FLUSH:
58202
- return "Royal Flush";
58258
+ return suit ? `Royal Flush in ${suit}s` : "Royal Flush";
58203
58259
  case HandType.STRAIGHT_FLUSH:
58204
- return `Straight Flush, ${PokerSolver.formatRank(rankValues[0])} high`;
58260
+ return `${suited("Straight Flush")}, ${this.rankWord(rankValues[0])} high`;
58205
58261
  case HandType.FOUR_OF_A_KIND:
58206
- return `Four ${PokerSolver.formatRank(rankValues[0])}s`;
58262
+ return `Quad ${this.rankWord(rankValues[0], true)}`;
58207
58263
  case HandType.FULL_HOUSE:
58208
- return `Full House, ${PokerSolver.formatRank(rankValues[0])}s over ${PokerSolver.formatRank(rankValues[1])}s`;
58264
+ return `Full House, ${this.rankWord(rankValues[0], true)} over ${this.rankWord(rankValues[1], true)}`;
58209
58265
  case HandType.FLUSH:
58210
- return `Flush, ${PokerSolver.formatRank(rankValues[0])} high`;
58266
+ return `${suited("Flush")}, ${this.rankWord(rankValues[0])} high`;
58211
58267
  case HandType.STRAIGHT:
58212
- return `Straight, ${PokerSolver.formatRank(rankValues[0])} high`;
58268
+ return `Straight, ${this.rankWord(rankValues[0])} high`;
58213
58269
  case HandType.THREE_OF_A_KIND:
58214
- return `Three ${PokerSolver.formatRank(rankValues[0])}s`;
58270
+ return `Trip ${this.rankWord(rankValues[0], true)}`;
58215
58271
  case HandType.TWO_PAIR:
58216
- return `Two Pair, ${PokerSolver.formatRank(rankValues[0])}s and ${PokerSolver.formatRank(rankValues[1])}s`;
58272
+ return `Two Pair, ${this.rankWord(rankValues[0], true)} and ${this.rankWord(rankValues[1], true)}`;
58217
58273
  case HandType.PAIR:
58218
- return `Pair of ${PokerSolver.formatRank(rankValues[0])}s`;
58274
+ return `Pair of ${this.rankWord(rankValues[0], true)}`;
58219
58275
  case HandType.HIGH_CARD:
58220
- return `${PokerSolver.formatRank(rankValues[0])} high`;
58276
+ return `${this.rankWord(rankValues[0])} high`;
58221
58277
  default:
58222
58278
  return description;
58223
58279
  }
58224
58280
  }
58281
+ /** A high-ace rank spelled out ("Ace", "Ten"); plural gives "Aces", "Sixes". */
58282
+ static rankWord(rank, plural = false) {
58283
+ const words = this.RANK_WORDS[rank === 1 ? 14 : rank];
58284
+ if (!words)
58285
+ return plural ? `${PokerSolver.formatRank(rank)}s` : PokerSolver.formatRank(rank);
58286
+ return plural ? words[1] : words[0];
58287
+ }
58288
+ /** The suit word every card of a flush shares ("Diamond"), or "" when the hand is empty or mixed. */
58289
+ static flushSuitWord(cards) {
58290
+ if (!cards || cards.length === 0)
58291
+ return "";
58292
+ const suit = cards[0].suit;
58293
+ if (cards.some(c => c.suit !== suit))
58294
+ return "";
58295
+ switch (suit) {
58296
+ case SUIT.CLUBS:
58297
+ return "Club";
58298
+ case SUIT.DIAMONDS:
58299
+ return "Diamond";
58300
+ case SUIT.HEARTS:
58301
+ return "Heart";
58302
+ case SUIT.SPADES:
58303
+ return "Spade";
58304
+ default:
58305
+ return "";
58306
+ }
58307
+ }
58225
58308
  /**
58226
58309
  * Example usage with string cards (for testing/debugging)
58227
58310
  * @param playerCardStrings Array of player hands as mnemonic strings
@@ -58242,6 +58325,21 @@ class PokerGameIntegration {
58242
58325
  return { winners, results };
58243
58326
  }
58244
58327
  }
58328
+ PokerGameIntegration.RANK_WORDS = {
58329
+ 14: ["Ace", "Aces"],
58330
+ 13: ["King", "Kings"],
58331
+ 12: ["Queen", "Queens"],
58332
+ 11: ["Jack", "Jacks"],
58333
+ 10: ["Ten", "Tens"],
58334
+ 9: ["Nine", "Nines"],
58335
+ 8: ["Eight", "Eights"],
58336
+ 7: ["Seven", "Sevens"],
58337
+ 6: ["Six", "Sixes"],
58338
+ 5: ["Five", "Fives"],
58339
+ 4: ["Four", "Fours"],
58340
+ 3: ["Three", "Threes"],
58341
+ 2: ["Two", "Twos"]
58342
+ };
58245
58343
  // Example usage:
58246
58344
  /*
58247
58345
  const example = PokerGameIntegration.exampleShowdown([