@block52/poker-vm-sdk 1.6.0 → 1.8.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/dist/index.d.ts CHANGED
@@ -44952,6 +44952,14 @@ interface MsgCreateGame {
44952
44952
  * (block52/pokerchain#407)
44953
44953
  */
44954
44954
  bettingLimit: string;
44955
+ /**
44956
+ * Scheduled start for a sit-and-go, unix seconds (field 21). With it,
44957
+ * min_players may be below max_players: the tournament starts when the table
44958
+ * fills or at this time with at least min_players registered, and is
44959
+ * cancelled with refunds if fewer have registered 15 minutes after it.
44960
+ * 0 = unscheduled: starts only when full. (poker-vm#2680)
44961
+ */
44962
+ startTime: Long;
44955
44963
  }
44956
44964
  declare const MsgCreateGame: MessageFns<MsgCreateGame>;
44957
44965
  /** MsgJoinGame defines the MsgJoinGame message. */
@@ -45249,7 +45257,8 @@ declare enum NonPlayerActionType {
45249
45257
  SIT_OUT = "sit-out",
45250
45258
  TIMEOUT = "timeout",
45251
45259
  TIME_BANK = "time-bank",
45252
- TOP_UP = "top-up"
45260
+ TOP_UP = "top-up",
45261
+ START = "start"
45253
45262
  }
45254
45263
  declare const AllPlayerActions: {
45255
45264
  DEAD_SMALL_BLIND: NonPlayerActionType.DEAD_SMALL_BLIND;
@@ -45265,6 +45274,7 @@ declare const AllPlayerActions: {
45265
45274
  TIMEOUT: NonPlayerActionType.TIMEOUT;
45266
45275
  TIME_BANK: NonPlayerActionType.TIME_BANK;
45267
45276
  TOP_UP: NonPlayerActionType.TOP_UP;
45277
+ START: NonPlayerActionType.START;
45268
45278
  SMALL_BLIND: PlayerActionType.SMALL_BLIND;
45269
45279
  BIG_BLIND: PlayerActionType.BIG_BLIND;
45270
45280
  FOLD: PlayerActionType.FOLD;
@@ -45364,6 +45374,7 @@ type GameOptions = {
45364
45374
  protocolFeeBps?: number;
45365
45375
  blindLevelDuration?: number;
45366
45376
  blindLevel?: number;
45377
+ scheduledStartTime?: number;
45367
45378
  sngStartTime?: number;
45368
45379
  levelStartTime?: number;
45369
45380
  timeBankMs?: number;
@@ -45399,6 +45410,7 @@ type GameOptionsDTO = {
45399
45410
  blindLevel?: number;
45400
45411
  nextSmallBlind?: string;
45401
45412
  nextBigBlind?: string;
45413
+ scheduledStartTime?: number;
45402
45414
  sngStartTime?: number;
45403
45415
  levelStartTime?: number;
45404
45416
  timeBankMs?: number;
@@ -46073,6 +46085,16 @@ declare class PokerSolver {
46073
46085
  * Find the best 5-card hand from 7 cards
46074
46086
  */
46075
46087
  static findBestHand(cards: Card[]): HandEvaluation;
46088
+ /**
46089
+ * Find the best Omaha hand: EXACTLY 2 of the 4 hole cards and EXACTLY 3 of
46090
+ * the 5 board cards — C(4,2) x C(5,3) = 60 candidates, ranked like Hold'em.
46091
+ * Mirrors the engine's FindBestOmahaHand (poker-vm#2650).
46092
+ */
46093
+ static findBestOmahaHand(holeCards: Card[], communityCards: Card[]): HandEvaluation;
46094
+ /**
46095
+ * Best hand for a variant from hole cards and a full 5-card board.
46096
+ */
46097
+ private static bestHandForVariant;
46076
46098
  /**
46077
46099
  * Evaluate a hand with any number of cards (2-7)
46078
46100
  * This is useful for showing hand strength during all betting rounds
@@ -46154,12 +46176,14 @@ declare class PokerSolver {
46154
46176
  static calculateWinPercentages(handA: Card[], handB: Card[], communityCards?: Card[], simulations?: number): [number, number, number];
46155
46177
  /**
46156
46178
  * Calculate win percentages for multiple players (2+) using Monte Carlo simulation
46157
- * @param hands Array of hole cards for each player (each must have exactly 2 cards)
46179
+ * @param hands Array of hole cards for each player (2 each for Hold'em, 4 for Omaha)
46158
46180
  * @param communityCards Current community cards (0-5 cards)
46159
46181
  * @param simulations Number of simulations to run (default: 10000)
46182
+ * @param variant The table's variant; omitted = Texas Hold'em. Omaha hands are
46183
+ * scored with the two-plus-three rule (ui#769).
46160
46184
  * @returns Object containing win percentages for each player and overall tie percentage
46161
46185
  */
46162
- static calculateMultiPlayerEquity(hands: Card[][], communityCards?: Card[], simulations?: number): {
46186
+ static calculateMultiPlayerEquity(hands: Card[][], communityCards?: Card[], simulations?: number, variant?: GameVariant): {
46163
46187
  winPercentages: number[];
46164
46188
  tiePercentage: number;
46165
46189
  };
@@ -46609,6 +46633,7 @@ interface SNGConfig {
46609
46633
  startingStack: bigint;
46610
46634
  blindLevelDuration: number;
46611
46635
  entryFee?: bigint;
46636
+ startTime?: number;
46612
46637
  }
46613
46638
  /**
46614
46639
  * Signing Cosmos Client that extends the read-only CosmosClient with transaction capabilities
package/dist/index.esm.js CHANGED
@@ -2846,6 +2846,7 @@ function createBaseMsgCreateGame() {
2846
2846
  entryFee: Long.UZERO,
2847
2847
  name: "",
2848
2848
  bettingLimit: "",
2849
+ startTime: Long.ZERO,
2849
2850
  };
2850
2851
  }
2851
2852
  const MsgCreateGame = {
@@ -2907,6 +2908,9 @@ const MsgCreateGame = {
2907
2908
  if (message.bettingLimit !== "") {
2908
2909
  writer.uint32(162).string(message.bettingLimit);
2909
2910
  }
2911
+ if (!message.startTime.equals(Long.ZERO)) {
2912
+ writer.uint32(168).int64(message.startTime.toString());
2913
+ }
2910
2914
  return writer;
2911
2915
  },
2912
2916
  decode(input, length) {
@@ -3049,6 +3053,13 @@ const MsgCreateGame = {
3049
3053
  message.bettingLimit = reader.string();
3050
3054
  continue;
3051
3055
  }
3056
+ case 21: {
3057
+ if (tag !== 168) {
3058
+ break;
3059
+ }
3060
+ message.startTime = Long.fromString(reader.int64().toString());
3061
+ continue;
3062
+ }
3052
3063
  }
3053
3064
  if ((tag & 7) === 4 || tag === 0) {
3054
3065
  break;
@@ -3078,6 +3089,7 @@ const MsgCreateGame = {
3078
3089
  entryFee: isSet$2b(object.entryFee) ? Long.fromValue(object.entryFee) : Long.UZERO,
3079
3090
  name: isSet$2b(object.name) ? globalThis.String(object.name) : "",
3080
3091
  bettingLimit: isSet$2b(object.bettingLimit) ? globalThis.String(object.bettingLimit) : "",
3092
+ startTime: isSet$2b(object.startTime) ? Long.fromValue(object.startTime) : Long.ZERO,
3081
3093
  };
3082
3094
  },
3083
3095
  toJSON(message) {
@@ -3139,6 +3151,9 @@ const MsgCreateGame = {
3139
3151
  if (message.bettingLimit !== "") {
3140
3152
  obj.bettingLimit = message.bettingLimit;
3141
3153
  }
3154
+ if (!message.startTime.equals(Long.ZERO)) {
3155
+ obj.startTime = (message.startTime || Long.ZERO).toString();
3156
+ }
3142
3157
  return obj;
3143
3158
  },
3144
3159
  create(base) {
@@ -3184,6 +3199,9 @@ const MsgCreateGame = {
3184
3199
  message.gameVariant = object.gameVariant ?? "";
3185
3200
  message.name = object.name ?? "";
3186
3201
  message.bettingLimit = object.bettingLimit ?? "";
3202
+ message.startTime = (object.startTime !== undefined && object.startTime !== null)
3203
+ ? Long.fromValue(object.startTime)
3204
+ : Long.ZERO;
3187
3205
  message.entryFee = (object.entryFee !== undefined && object.entryFee !== null)
3188
3206
  ? Long.fromValue(object.entryFee)
3189
3207
  : Long.UZERO;
@@ -56091,6 +56109,10 @@ var NonPlayerActionType;
56091
56109
  // current turn. Rejected off-turn, past the deadline, or with no bank left.
56092
56110
  NonPlayerActionType["TIME_BANK"] = "time-bank";
56093
56111
  NonPlayerActionType["TOP_UP"] = "top-up";
56112
+ // Scheduled single-table tournament (poker-vm#2680): any registered player
56113
+ // starts the sit-and-go once gameOptions.scheduledStartTime has passed and
56114
+ // at least minPlayers are seated. Offered in legalActions when it is due.
56115
+ NonPlayerActionType["START"] = "start";
56094
56116
  })(NonPlayerActionType || (NonPlayerActionType = {}));
56095
56117
  const AllPlayerActions = { ...PlayerActionType, ...NonPlayerActionType };
56096
56118
  /**
@@ -56772,6 +56794,41 @@ class PokerSolver {
56772
56794
  }
56773
56795
  return bestHand;
56774
56796
  }
56797
+ /**
56798
+ * Find the best Omaha hand: EXACTLY 2 of the 4 hole cards and EXACTLY 3 of
56799
+ * the 5 board cards — C(4,2) x C(5,3) = 60 candidates, ranked like Hold'em.
56800
+ * Mirrors the engine's FindBestOmahaHand (poker-vm#2650).
56801
+ */
56802
+ static findBestOmahaHand(holeCards, communityCards) {
56803
+ if (holeCards.length !== 4) {
56804
+ throw new Error("Omaha requires exactly 4 hole cards");
56805
+ }
56806
+ if (communityCards.length !== 5) {
56807
+ throw new Error("Omaha requires exactly 5 community cards");
56808
+ }
56809
+ let bestHand = null;
56810
+ for (const pair of this.getCombinationsFlexible(holeCards, 2)) {
56811
+ for (const triple of this.getCombinationsFlexible(communityCards, 3)) {
56812
+ const evaluation = this.evaluateHand([...pair, ...triple]);
56813
+ if (!bestHand || this.compareHands(evaluation, bestHand) > 0) {
56814
+ bestHand = evaluation;
56815
+ }
56816
+ }
56817
+ }
56818
+ if (!bestHand) {
56819
+ throw new Error("Failed to evaluate hand");
56820
+ }
56821
+ return bestHand;
56822
+ }
56823
+ /**
56824
+ * Best hand for a variant from hole cards and a full 5-card board.
56825
+ */
56826
+ static bestHandForVariant(variant, holeCards, communityCards) {
56827
+ if (variant === GameVariant.OMAHA) {
56828
+ return this.findBestOmahaHand(holeCards, communityCards);
56829
+ }
56830
+ return this.findBestHand([...holeCards, ...communityCards]);
56831
+ }
56775
56832
  /**
56776
56833
  * Evaluate a hand with any number of cards (2-7)
56777
56834
  * This is useful for showing hand strength during all betting rounds
@@ -57166,12 +57223,14 @@ class PokerSolver {
57166
57223
  }
57167
57224
  /**
57168
57225
  * Calculate win percentages for multiple players (2+) using Monte Carlo simulation
57169
- * @param hands Array of hole cards for each player (each must have exactly 2 cards)
57226
+ * @param hands Array of hole cards for each player (2 each for Hold'em, 4 for Omaha)
57170
57227
  * @param communityCards Current community cards (0-5 cards)
57171
57228
  * @param simulations Number of simulations to run (default: 10000)
57229
+ * @param variant The table's variant; omitted = Texas Hold'em. Omaha hands are
57230
+ * scored with the two-plus-three rule (ui#769).
57172
57231
  * @returns Object containing win percentages for each player and overall tie percentage
57173
57232
  */
57174
- static calculateMultiPlayerEquity(hands, communityCards = [], simulations = 10000) {
57233
+ static calculateMultiPlayerEquity(hands, communityCards = [], simulations = 10000, variant) {
57175
57234
  // Validate inputs
57176
57235
  if (hands.length < 2) {
57177
57236
  throw new Error("Need at least 2 hands to calculate equity");
@@ -57179,9 +57238,10 @@ class PokerSolver {
57179
57238
  if (hands.length > 10) {
57180
57239
  throw new Error("Maximum 10 hands supported");
57181
57240
  }
57241
+ const holeCount = holeCardsPerPlayer(variant);
57182
57242
  for (let i = 0; i < hands.length; i++) {
57183
- if (hands[i].length !== 2) {
57184
- throw new Error(`Hand ${i} must have exactly 2 cards`);
57243
+ if (hands[i].length !== holeCount) {
57244
+ throw new Error(`Hand ${i} must have exactly ${holeCount} cards`);
57185
57245
  }
57186
57246
  }
57187
57247
  if (communityCards.length > 5) {
@@ -57208,10 +57268,7 @@ class PokerSolver {
57208
57268
  // Deal remaining community cards
57209
57269
  const fullCommunityCards = [...communityCards, ...shuffledDeck.slice(0, cardsNeeded)];
57210
57270
  // Evaluate all hands
57211
- const evaluations = hands.map(hand => {
57212
- const fullHand = [...hand, ...fullCommunityCards];
57213
- return this.findBestHand(fullHand);
57214
- });
57271
+ const evaluations = hands.map(hand => this.bestHandForVariant(variant, hand, fullCommunityCards));
57215
57272
  // Find winners using existing findWinners method
57216
57273
  const winnerIndices = this.findWinners(evaluations);
57217
57274
  // Update win counters
@@ -70969,6 +71026,26 @@ function gaslessFee(gasLimit = DEFAULT_GAS_LIMIT) {
70969
71026
  gas: gasLimit.toString()
70970
71027
  };
70971
71028
  }
71029
+ /**
71030
+ * Fail fast on a sit-and-go field the chain would refuse (poker-vm#2680):
71031
+ * seats 2..9, min <= max, and a flexible field (min < max) needs a scheduled
71032
+ * start in the future. Mirrors x/poker/keeper/msg_server_create_game.go.
71033
+ */
71034
+ function assertCreatableSngField(minPlayers, maxPlayers, sngConfig, nowSeconds = Math.floor(Date.now() / 1000)) {
71035
+ if (maxPlayers < 2 || maxPlayers > 9) {
71036
+ throw new Error(`sit-and-go maxPlayers must be 2..9; got ${maxPlayers}.`);
71037
+ }
71038
+ if (minPlayers < 2 || minPlayers > maxPlayers) {
71039
+ throw new Error(`sit-and-go minPlayers must be 2..maxPlayers (${maxPlayers}); got ${minPlayers}.`);
71040
+ }
71041
+ const startTime = sngConfig?.startTime;
71042
+ if (minPlayers !== maxPlayers && !startTime) {
71043
+ throw new Error("sit-and-go with minPlayers < maxPlayers needs sngConfig.startTime (a scheduled start).");
71044
+ }
71045
+ if (startTime !== undefined && startTime <= nowSeconds) {
71046
+ throw new Error(`sngConfig.startTime ${startTime} must be in the future (now ${nowSeconds}).`);
71047
+ }
71048
+ }
70972
71049
  /**
70973
71050
  * Signing Cosmos Client that extends the read-only CosmosClient with transaction capabilities
70974
71051
  */
@@ -71100,6 +71177,7 @@ class SigningCosmosClient extends CosmosClient {
71100
71177
  if (!sngConfig.blindLevelDuration || sngConfig.blindLevelDuration <= 0) {
71101
71178
  throw new Error(`${gameFormat} games require a positive blindLevelDuration; got ${sngConfig.blindLevelDuration}.`);
71102
71179
  }
71180
+ assertCreatableSngField(minPlayers, maxPlayers, sngConfig);
71103
71181
  }
71104
71182
  assertCreatableBettingLimit(bettingLimit);
71105
71183
  await this.initializeSigningClient();
@@ -71137,6 +71215,9 @@ class SigningCosmosClient extends CosmosClient {
71137
71215
  // Betting structure (block52/pokerchain#407). "" = the variant's default
71138
71216
  // on chain, and an empty proto3 string is not encoded at all.
71139
71217
  bettingLimit: bettingLimit ?? "",
71218
+ // Scheduled start (poker-vm#2680), unix seconds. 0 = unscheduled, and
71219
+ // a zero proto3 int64 is not encoded at all.
71220
+ startTime: sngConfig?.startTime ? Long.fromNumber(sngConfig.startTime) : Long.ZERO,
71140
71221
  });
71141
71222
  // Create the transaction message
71142
71223
  const msg = {