@block52/poker-vm-sdk 1.5.1 → 1.7.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 +66 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +122 -11
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +125 -10
- package/dist/index.js.map +1 -1
- package/dist/pokerSolver.d.ts +15 -3
- package/dist/pokerSolver.d.ts.map +1 -1
- package/dist/pokerchain.poker.v1/types/pokerchain/poker/v1/tx.d.ts +6 -0
- package/dist/pokerchain.poker.v1/types/pokerchain/poker/v1/tx.d.ts.map +1 -1
- package/dist/signingClient.d.ts +13 -2
- package/dist/signingClient.d.ts.map +1 -1
- package/dist/types/game.d.ts +11 -0
- package/dist/types/game.d.ts.map +1 -1
- package/dist/utils/gameFormatUtils.d.ts +23 -1
- package/dist/utils/gameFormatUtils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2847,6 +2847,7 @@ function createBaseMsgCreateGame() {
|
|
|
2847
2847
|
gameVariant: "",
|
|
2848
2848
|
entryFee: Long.UZERO,
|
|
2849
2849
|
name: "",
|
|
2850
|
+
bettingLimit: "",
|
|
2850
2851
|
};
|
|
2851
2852
|
}
|
|
2852
2853
|
const MsgCreateGame = {
|
|
@@ -2905,6 +2906,9 @@ const MsgCreateGame = {
|
|
|
2905
2906
|
if (message.name !== "") {
|
|
2906
2907
|
writer.uint32(154).string(message.name);
|
|
2907
2908
|
}
|
|
2909
|
+
if (message.bettingLimit !== "") {
|
|
2910
|
+
writer.uint32(162).string(message.bettingLimit);
|
|
2911
|
+
}
|
|
2908
2912
|
return writer;
|
|
2909
2913
|
},
|
|
2910
2914
|
decode(input, length) {
|
|
@@ -3040,6 +3044,13 @@ const MsgCreateGame = {
|
|
|
3040
3044
|
message.name = reader.string();
|
|
3041
3045
|
continue;
|
|
3042
3046
|
}
|
|
3047
|
+
case 20: {
|
|
3048
|
+
if (tag !== 162) {
|
|
3049
|
+
break;
|
|
3050
|
+
}
|
|
3051
|
+
message.bettingLimit = reader.string();
|
|
3052
|
+
continue;
|
|
3053
|
+
}
|
|
3043
3054
|
}
|
|
3044
3055
|
if ((tag & 7) === 4 || tag === 0) {
|
|
3045
3056
|
break;
|
|
@@ -3068,6 +3079,7 @@ const MsgCreateGame = {
|
|
|
3068
3079
|
gameVariant: isSet$2b(object.gameVariant) ? globalThis.String(object.gameVariant) : "",
|
|
3069
3080
|
entryFee: isSet$2b(object.entryFee) ? Long.fromValue(object.entryFee) : Long.UZERO,
|
|
3070
3081
|
name: isSet$2b(object.name) ? globalThis.String(object.name) : "",
|
|
3082
|
+
bettingLimit: isSet$2b(object.bettingLimit) ? globalThis.String(object.bettingLimit) : "",
|
|
3071
3083
|
};
|
|
3072
3084
|
},
|
|
3073
3085
|
toJSON(message) {
|
|
@@ -3126,6 +3138,9 @@ const MsgCreateGame = {
|
|
|
3126
3138
|
if (message.name !== "") {
|
|
3127
3139
|
obj.name = message.name;
|
|
3128
3140
|
}
|
|
3141
|
+
if (message.bettingLimit !== "") {
|
|
3142
|
+
obj.bettingLimit = message.bettingLimit;
|
|
3143
|
+
}
|
|
3129
3144
|
return obj;
|
|
3130
3145
|
},
|
|
3131
3146
|
create(base) {
|
|
@@ -3170,6 +3185,7 @@ const MsgCreateGame = {
|
|
|
3170
3185
|
message.blindLevelDuration = object.blindLevelDuration ?? 0;
|
|
3171
3186
|
message.gameVariant = object.gameVariant ?? "";
|
|
3172
3187
|
message.name = object.name ?? "";
|
|
3188
|
+
message.bettingLimit = object.bettingLimit ?? "";
|
|
3173
3189
|
message.entryFee = (object.entryFee !== undefined && object.entryFee !== null)
|
|
3174
3190
|
? Long.fromValue(object.entryFee)
|
|
3175
3191
|
: Long.UZERO;
|
|
@@ -56097,6 +56113,17 @@ exports.GameVariant = void 0;
|
|
|
56097
56113
|
GameVariant["TEXAS_HOLDEM"] = "texas-holdem";
|
|
56098
56114
|
GameVariant["OMAHA"] = "omaha";
|
|
56099
56115
|
})(exports.GameVariant || (exports.GameVariant = {}));
|
|
56116
|
+
/**
|
|
56117
|
+
* BettingLimit — the table's betting structure. Orthogonal to GameVariant: any
|
|
56118
|
+
* variant can be played at any limit (pot-limit Omaha, pot-limit Hold'em,
|
|
56119
|
+
* fixed-limit Hold'em, …). Absent on GameOptions ⇒ no-limit (current behavior).
|
|
56120
|
+
*/
|
|
56121
|
+
exports.BettingLimit = void 0;
|
|
56122
|
+
(function (BettingLimit) {
|
|
56123
|
+
BettingLimit["NO_LIMIT"] = "no-limit";
|
|
56124
|
+
BettingLimit["POT_LIMIT"] = "pot-limit";
|
|
56125
|
+
BettingLimit["FIXED_LIMIT"] = "fixed-limit";
|
|
56126
|
+
})(exports.BettingLimit || (exports.BettingLimit = {}));
|
|
56100
56127
|
exports.GameStatus = void 0;
|
|
56101
56128
|
(function (GameStatus) {
|
|
56102
56129
|
GameStatus["WAITING_FOR_PLAYERS"] = "waiting-for-players";
|
|
@@ -56468,6 +56495,30 @@ const parseGameVariant = (value) => {
|
|
|
56468
56495
|
return "unknown";
|
|
56469
56496
|
}
|
|
56470
56497
|
};
|
|
56498
|
+
/**
|
|
56499
|
+
* The betting structure a table plays. The engine treats an absent
|
|
56500
|
+
* `gameOptions.bettingLimit` as no-limit (poker-vm#2652), so this mirrors that
|
|
56501
|
+
* rule rather than inventing a default (block52/pokerchain#407).
|
|
56502
|
+
*
|
|
56503
|
+
* @param options - the table's gameOptions (or anything carrying bettingLimit)
|
|
56504
|
+
* @returns the table's BettingLimit
|
|
56505
|
+
*/
|
|
56506
|
+
const getBettingLimit = (options) => {
|
|
56507
|
+
return options?.bettingLimit ?? exports.BettingLimit.NO_LIMIT;
|
|
56508
|
+
};
|
|
56509
|
+
/**
|
|
56510
|
+
* Check whether a table is pot-limit (its max bet or raise is the pot cap).
|
|
56511
|
+
*/
|
|
56512
|
+
const isPotLimit = (options) => {
|
|
56513
|
+
return getBettingLimit(options) === exports.BettingLimit.POT_LIMIT;
|
|
56514
|
+
};
|
|
56515
|
+
/**
|
|
56516
|
+
* How many hole cards a variant deals each player: 4 for Omaha, 2 for Texas
|
|
56517
|
+
* Hold'em. Mirrors the engine's HoleCardsPerPlayer (poker-vm#2650).
|
|
56518
|
+
*/
|
|
56519
|
+
const holeCardsPerPlayer = (variant) => {
|
|
56520
|
+
return variant === exports.GameVariant.OMAHA ? 4 : 2;
|
|
56521
|
+
};
|
|
56471
56522
|
|
|
56472
56523
|
/**
|
|
56473
56524
|
* Check if a specific action is available in the legal actions list.
|
|
@@ -56723,6 +56774,41 @@ class PokerSolver {
|
|
|
56723
56774
|
}
|
|
56724
56775
|
return bestHand;
|
|
56725
56776
|
}
|
|
56777
|
+
/**
|
|
56778
|
+
* Find the best Omaha hand: EXACTLY 2 of the 4 hole cards and EXACTLY 3 of
|
|
56779
|
+
* the 5 board cards — C(4,2) x C(5,3) = 60 candidates, ranked like Hold'em.
|
|
56780
|
+
* Mirrors the engine's FindBestOmahaHand (poker-vm#2650).
|
|
56781
|
+
*/
|
|
56782
|
+
static findBestOmahaHand(holeCards, communityCards) {
|
|
56783
|
+
if (holeCards.length !== 4) {
|
|
56784
|
+
throw new Error("Omaha requires exactly 4 hole cards");
|
|
56785
|
+
}
|
|
56786
|
+
if (communityCards.length !== 5) {
|
|
56787
|
+
throw new Error("Omaha requires exactly 5 community cards");
|
|
56788
|
+
}
|
|
56789
|
+
let bestHand = null;
|
|
56790
|
+
for (const pair of this.getCombinationsFlexible(holeCards, 2)) {
|
|
56791
|
+
for (const triple of this.getCombinationsFlexible(communityCards, 3)) {
|
|
56792
|
+
const evaluation = this.evaluateHand([...pair, ...triple]);
|
|
56793
|
+
if (!bestHand || this.compareHands(evaluation, bestHand) > 0) {
|
|
56794
|
+
bestHand = evaluation;
|
|
56795
|
+
}
|
|
56796
|
+
}
|
|
56797
|
+
}
|
|
56798
|
+
if (!bestHand) {
|
|
56799
|
+
throw new Error("Failed to evaluate hand");
|
|
56800
|
+
}
|
|
56801
|
+
return bestHand;
|
|
56802
|
+
}
|
|
56803
|
+
/**
|
|
56804
|
+
* Best hand for a variant from hole cards and a full 5-card board.
|
|
56805
|
+
*/
|
|
56806
|
+
static bestHandForVariant(variant, holeCards, communityCards) {
|
|
56807
|
+
if (variant === exports.GameVariant.OMAHA) {
|
|
56808
|
+
return this.findBestOmahaHand(holeCards, communityCards);
|
|
56809
|
+
}
|
|
56810
|
+
return this.findBestHand([...holeCards, ...communityCards]);
|
|
56811
|
+
}
|
|
56726
56812
|
/**
|
|
56727
56813
|
* Evaluate a hand with any number of cards (2-7)
|
|
56728
56814
|
* This is useful for showing hand strength during all betting rounds
|
|
@@ -57117,12 +57203,14 @@ class PokerSolver {
|
|
|
57117
57203
|
}
|
|
57118
57204
|
/**
|
|
57119
57205
|
* Calculate win percentages for multiple players (2+) using Monte Carlo simulation
|
|
57120
|
-
* @param hands Array of hole cards for each player (each
|
|
57206
|
+
* @param hands Array of hole cards for each player (2 each for Hold'em, 4 for Omaha)
|
|
57121
57207
|
* @param communityCards Current community cards (0-5 cards)
|
|
57122
57208
|
* @param simulations Number of simulations to run (default: 10000)
|
|
57209
|
+
* @param variant The table's variant; omitted = Texas Hold'em. Omaha hands are
|
|
57210
|
+
* scored with the two-plus-three rule (ui#769).
|
|
57123
57211
|
* @returns Object containing win percentages for each player and overall tie percentage
|
|
57124
57212
|
*/
|
|
57125
|
-
static calculateMultiPlayerEquity(hands, communityCards = [], simulations = 10000) {
|
|
57213
|
+
static calculateMultiPlayerEquity(hands, communityCards = [], simulations = 10000, variant) {
|
|
57126
57214
|
// Validate inputs
|
|
57127
57215
|
if (hands.length < 2) {
|
|
57128
57216
|
throw new Error("Need at least 2 hands to calculate equity");
|
|
@@ -57130,9 +57218,10 @@ class PokerSolver {
|
|
|
57130
57218
|
if (hands.length > 10) {
|
|
57131
57219
|
throw new Error("Maximum 10 hands supported");
|
|
57132
57220
|
}
|
|
57221
|
+
const holeCount = holeCardsPerPlayer(variant);
|
|
57133
57222
|
for (let i = 0; i < hands.length; i++) {
|
|
57134
|
-
if (hands[i].length !==
|
|
57135
|
-
throw new Error(`Hand ${i} must have exactly
|
|
57223
|
+
if (hands[i].length !== holeCount) {
|
|
57224
|
+
throw new Error(`Hand ${i} must have exactly ${holeCount} cards`);
|
|
57136
57225
|
}
|
|
57137
57226
|
}
|
|
57138
57227
|
if (communityCards.length > 5) {
|
|
@@ -57159,10 +57248,7 @@ class PokerSolver {
|
|
|
57159
57248
|
// Deal remaining community cards
|
|
57160
57249
|
const fullCommunityCards = [...communityCards, ...shuffledDeck.slice(0, cardsNeeded)];
|
|
57161
57250
|
// Evaluate all hands
|
|
57162
|
-
const evaluations = hands.map(hand =>
|
|
57163
|
-
const fullHand = [...hand, ...fullCommunityCards];
|
|
57164
|
-
return this.findBestHand(fullHand);
|
|
57165
|
-
});
|
|
57251
|
+
const evaluations = hands.map(hand => this.bestHandForVariant(variant, hand, fullCommunityCards));
|
|
57166
57252
|
// Find winners using existing findWinners method
|
|
57167
57253
|
const winnerIndices = this.findWinners(evaluations);
|
|
57168
57254
|
// Update win counters
|
|
@@ -71025,9 +71111,14 @@ class SigningCosmosClient extends CosmosClient {
|
|
|
71025
71111
|
return this.sendTokens(fromAddress, toAddress, amount, undefined, memo);
|
|
71026
71112
|
}
|
|
71027
71113
|
/**
|
|
71028
|
-
* Create a new poker game
|
|
71114
|
+
* Create a new poker game.
|
|
71115
|
+
*
|
|
71116
|
+
* `bettingLimit` is the table's betting structure (block52/pokerchain#407).
|
|
71117
|
+
* Omit it for the variant's default: pot-limit for omaha (PLO), no-limit for
|
|
71118
|
+
* texas-holdem. Omitted, the field is not encoded at all, so a chain without
|
|
71119
|
+
* it accepts the tx unchanged. Fixed-limit is not playable yet (poker-vm#2654).
|
|
71029
71120
|
*/
|
|
71030
|
-
async createGame(gameFormat, gameVariant, minPlayers, maxPlayers, minBuyInB52USDC, maxBuyInB52USDC, smallBlindB52USDC, bigBlindB52USDC, timeout, rakeConfig, sngConfig, name) {
|
|
71121
|
+
async createGame(gameFormat, gameVariant, minPlayers, maxPlayers, minBuyInB52USDC, maxBuyInB52USDC, smallBlindB52USDC, bigBlindB52USDC, timeout, rakeConfig, sngConfig, name, bettingLimit) {
|
|
71031
71122
|
// Validate SNG/Tournament config BEFORE any network work — fail fast.
|
|
71032
71123
|
// SNG/Tournament games are DEFINED by startingStack + blindLevelDuration.
|
|
71033
71124
|
// Refuse to create one with missing/zero values rather than silently
|
|
@@ -71047,6 +71138,7 @@ class SigningCosmosClient extends CosmosClient {
|
|
|
71047
71138
|
throw new Error(`${gameFormat} games require a positive blindLevelDuration; got ${sngConfig.blindLevelDuration}.`);
|
|
71048
71139
|
}
|
|
71049
71140
|
}
|
|
71141
|
+
assertCreatableBettingLimit(bettingLimit);
|
|
71050
71142
|
await this.initializeSigningClient();
|
|
71051
71143
|
if (!this.signingClient || !this.wallet) {
|
|
71052
71144
|
throw new Error("Signing client not initialized");
|
|
@@ -71079,6 +71171,9 @@ class SigningCosmosClient extends CosmosClient {
|
|
|
71079
71171
|
// Optional ENS-style table name (block52/pokerchain#337). Empty = unnamed
|
|
71080
71172
|
// (no fee); a non-empty name costs $0.10/char and must be globally unique.
|
|
71081
71173
|
name: name ?? "",
|
|
71174
|
+
// Betting structure (block52/pokerchain#407). "" = the variant's default
|
|
71175
|
+
// on chain, and an empty proto3 string is not encoded at all.
|
|
71176
|
+
bettingLimit: bettingLimit ?? "",
|
|
71082
71177
|
});
|
|
71083
71178
|
// Create the transaction message
|
|
71084
71179
|
const msg = {
|
|
@@ -71098,6 +71193,7 @@ class SigningCosmosClient extends CosmosClient {
|
|
|
71098
71193
|
smallBlind: smallBlindB52USDC.toString(),
|
|
71099
71194
|
bigBlind: bigBlindB52USDC.toString(),
|
|
71100
71195
|
timeout,
|
|
71196
|
+
...(bettingLimit && { bettingLimit }),
|
|
71101
71197
|
...(rakeConfig && {
|
|
71102
71198
|
rakeFreeThreshold: rakeConfig.rakeFreeThreshold.toString(),
|
|
71103
71199
|
rakePercentage: rakeConfig.rakePercentage,
|
|
@@ -71974,6 +72070,21 @@ async function createSigningClientFromMnemonic(config, mnemonic) {
|
|
|
71974
72070
|
});
|
|
71975
72071
|
return createSigningCosmosClient(config, wallet);
|
|
71976
72072
|
}
|
|
72073
|
+
/**
|
|
72074
|
+
* Throws for a betting limit a table cannot be created with (block52/pokerchain#407).
|
|
72075
|
+
* Undefined is allowed: the chain applies the variant's default.
|
|
72076
|
+
*/
|
|
72077
|
+
function assertCreatableBettingLimit(bettingLimit) {
|
|
72078
|
+
if (bettingLimit === undefined) {
|
|
72079
|
+
return;
|
|
72080
|
+
}
|
|
72081
|
+
if (bettingLimit === exports.BettingLimit.FIXED_LIMIT) {
|
|
72082
|
+
throw new Error("Fixed-limit tables are not available yet (poker-vm#2654).");
|
|
72083
|
+
}
|
|
72084
|
+
if (bettingLimit !== exports.BettingLimit.NO_LIMIT && bettingLimit !== exports.BettingLimit.POT_LIMIT) {
|
|
72085
|
+
throw new Error(`Invalid betting limit: ${bettingLimit}.`);
|
|
72086
|
+
}
|
|
72087
|
+
}
|
|
71977
72088
|
|
|
71978
72089
|
// Generated by Ignite ignite.com/cli
|
|
71979
72090
|
const Client = IgniteClient.plugin([
|
|
@@ -72036,6 +72147,7 @@ exports.SigningCosmosClient = SigningCosmosClient;
|
|
|
72036
72147
|
exports.TxExecutionError = TxExecutionError;
|
|
72037
72148
|
exports.ValidatorBond = ValidatorBond;
|
|
72038
72149
|
exports.WithdrawalRequest = WithdrawalRequest;
|
|
72150
|
+
exports.assertCreatableBettingLimit = assertCreatableBettingLimit;
|
|
72039
72151
|
exports.assertExecuted = assertExecuted;
|
|
72040
72152
|
exports.buildMsgCreateValidator = buildMsgCreateValidator;
|
|
72041
72153
|
exports.computeGameNameFee = computeGameNameFee;
|
|
@@ -72047,14 +72159,17 @@ exports.formatGameVariantDisplay = formatGameVariantDisplay;
|
|
|
72047
72159
|
exports.generateWallet = generateWallet;
|
|
72048
72160
|
exports.getActionByType = getActionByType;
|
|
72049
72161
|
exports.getAddressFromMnemonic = getAddressFromMnemonic;
|
|
72162
|
+
exports.getBettingLimit = getBettingLimit;
|
|
72050
72163
|
exports.getDefaultCosmosConfig = getDefaultCosmosConfig;
|
|
72051
72164
|
exports.getGameFormat = getGameFormat;
|
|
72052
72165
|
exports.getGameFormatForCosmos = getGameFormatForCosmos;
|
|
72053
72166
|
exports.getGameFormatFromObject = getGameFormatFromObject;
|
|
72054
72167
|
exports.getGameVariant = getGameVariant;
|
|
72055
72168
|
exports.hasAction = hasAction;
|
|
72169
|
+
exports.holeCardsPerPlayer = holeCardsPerPlayer;
|
|
72056
72170
|
exports.isCashFormat = isCashFormat;
|
|
72057
72171
|
exports.isEmptyAddress = isEmptyAddress;
|
|
72172
|
+
exports.isPotLimit = isPotLimit;
|
|
72058
72173
|
exports.isSitAndGoFormat = isSitAndGoFormat;
|
|
72059
72174
|
exports.isTournamentFormat = isTournamentFormat;
|
|
72060
72175
|
exports.isValidMnemonic = isValidMnemonic;
|