kaggle-environments 1.23.4__py3-none-any.whl → 1.23.6__py3-none-any.whl

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.

Potentially problematic release.


This version of kaggle-environments might be problematic. Click here for more details.

@@ -1,91 +1,65 @@
1
- function _getLastMovesACPC(bettingString, currentPlayer) {
2
- // We will store all human-readable moves here
3
- const allMoves = [];
1
+ const PLACEHOLDER_CARD = '2c';
4
2
 
5
- // Split the action string by street (e.g., ["r5c", "cr11f"])
3
+ function _getActionStringsFromACPC(bettingString, nextPlayerIndex, numPlayers = 2) {
4
+ const moves = [];
6
5
  const streets = bettingString.split('/');
7
-
8
- // Process each street's actions
9
6
  for (let streetIndex = 0; streetIndex < streets.length; streetIndex++) {
10
7
  const streetAction = streets[streetIndex];
11
8
  let i = 0;
12
-
13
- // Preflop (streetIndex 0), action is "open" due to blinds.
14
- // Postflop (streetIndex > 0), action is "not open" (first player checks or bets).
15
- let isAggressiveActionOpen = (streetIndex === 0);
16
-
17
- // 4. Parse the moves within the street
18
9
  while (i < streetAction.length) {
19
10
  const char = streetAction[i];
20
- let move = null;
21
-
22
- if (char === 'c') {
23
- // 'c' (call/check)
24
- if (isAggressiveActionOpen) {
25
- move = 'Call';
26
- } else {
27
- move = 'Check';
28
- }
29
- isAggressiveActionOpen = false; // 'c' never leaves action open
30
- i++;
31
- } else if (char === 'f') {
32
- // 'f' (fold)
33
- move = 'Fold';
34
- isAggressiveActionOpen = false; // 'f' ends the hand
35
- i++;
36
- } else if (char === 'r') {
37
- // 'r' (raise/bet)
11
+ if (char === 'r') {
38
12
  let amount = '';
39
13
  i++;
40
- // Continue to parse all digits of the raise amount
41
14
  while (i < streetAction.length && streetAction[i] >= '0' && streetAction[i] <= '9') {
42
15
  amount += streetAction[i];
43
16
  i++;
44
17
  }
45
- move = `Raise ${amount}`;
46
- isAggressiveActionOpen = true; // 'r' always leaves action open
18
+ moves.push(`r${amount}`);
47
19
  } else {
48
- // Should not happen with valid input, but good to prevent infinite loops
20
+ moves.push(char);
49
21
  i++;
50
- continue;
51
- }
52
-
53
- // 5. Store this move in the history
54
- if (move) {
55
- allMoves.push(move);
56
22
  }
57
23
  }
58
24
  }
59
25
 
60
- // 6. Get the last two moves from our complete list
61
- const lastMove = allMoves.length > 0 ? allMoves[allMoves.length - 1] : null;
62
- const secondLastMove = allMoves.length > 1 ? allMoves[allMoves.length - 2] : null;
26
+ const lastMove = moves.length > 0 ? moves[moves.length - 1] : null;
27
+ const actionStrings = Array(numPlayers).fill('');
63
28
 
64
- const lastMoves = currentPlayer === 0 ? [secondLastMove, lastMove] : [lastMove, secondLastMove];
29
+ if (lastMove) {
30
+ if (typeof nextPlayerIndex === 'number' && nextPlayerIndex >= 0) {
31
+ const lastActor = (nextPlayerIndex + numPlayers - 1) % numPlayers;
32
+ actionStrings[lastActor] = lastMove;
33
+ } else {
34
+ const inferredActor = (moves.length - 1) % numPlayers;
35
+ actionStrings[inferredActor] = lastMove;
36
+ }
37
+ }
65
38
 
66
- return lastMoves;
39
+ return actionStrings;
67
40
  }
68
41
 
69
- function _parseStepHistoryData(universalPokerJSON) {
42
+ function _parseStepHistoryData(universalPokerJSON, nextPlayerIndex, numPlayers = 2) {
70
43
  const result = {
71
44
  cards: [],
72
45
  communityCards: '',
73
46
  bets: [],
74
- lastMoves: ['', ''],
47
+ playerActionStrings: Array(numPlayers).fill(''),
75
48
  winOdds: [0, 0],
76
49
  };
77
50
 
78
- // Split the string into its main lines
51
+ if (!universalPokerJSON) {
52
+ return result;
53
+ }
54
+
79
55
  const lines = universalPokerJSON.acpc_state.trim().split('\n');
80
56
  if (lines.length < 2) {
81
- console.error("Invalid state string format.");
82
57
  return result;
83
58
  }
84
59
 
85
- const stateLine = lines[0]; // example: "STATE:0:r5c/cr11c/:6cKd|AsJc/7hQh6d/2c"
86
- const spentLine = lines[1]; // example: "Spent: [P0: 11 P1: 11 ]"
60
+ const stateLine = lines[0];
61
+ const spentLine = lines[1];
87
62
 
88
- // --- Parse the Spent Line ---
89
63
  if (spentLine) {
90
64
  const p0BetMatch = spentLine.match(/P0:\s*(\d+)/);
91
65
  const p1BetMatch = spentLine.match(/P1:\s*(\d+)/);
@@ -103,165 +77,334 @@ function _parseStepHistoryData(universalPokerJSON) {
103
77
  result.bets = bets;
104
78
  }
105
79
 
106
- // --- Parse the State Line ---
107
80
  if (stateLine) {
108
81
  const stateParts = stateLine.split(':');
82
+ const cardString = stateParts[stateParts.length - 1];
83
+ const cardSegments = cardString.split('/');
109
84
 
110
- // --- Parse Cards ---
111
- // The card string is always the last part
112
- const cardString = stateParts[stateParts.length - 1]; // example: "6cKd|AsJc/7hQh6d/2c"
113
-
114
- // Split card string by '/' to separate hand block from board blocks
115
- const cardSegments = cardString.split('/'); // example: ["6cKd|AsJc", "7hQh6d", "2c"]
116
-
117
- // Parse the first segment (player hands)
118
85
  if (cardSegments[0]) {
119
86
  const playerHands = cardSegments[0].split('|');
120
87
  if (playerHands.length >= 2) {
121
- // example: "6cKd"
122
88
  result.cards = [playerHands[0], playerHands[1]];
123
89
  }
124
90
  }
125
91
 
126
- // The rest of the segments are community cards, one per street
127
92
  result.communityCards = cardSegments
128
- .slice(1) // gets all elements AFTER the player hands
129
- .filter(Boolean) // removes any empty strings (e.g., from a trailing "/")
130
- .join(''); // joins the remaining segments into a single string
93
+ .slice(1)
94
+ .filter(Boolean)
95
+ .join('');
131
96
 
132
- // --- Parse Betting String --
133
- // The betting string is everything between the 2nd colon and the last colon.
134
- // This handles edge cases like "STATE:0:r5c/cr11c/:cards"
135
97
  const bettingString = stateParts.slice(2, stateParts.length - 1).join(':');
136
-
137
98
  if (bettingString) {
138
- result.lastMoves = _getLastMovesACPC(bettingString, universalPokerJSON.current_player);
99
+ result.playerActionStrings = _getActionStringsFromACPC(
100
+ bettingString,
101
+ nextPlayerIndex,
102
+ numPlayers
103
+ );
139
104
  }
140
105
  }
141
106
 
142
- // Parse win odds
143
- const p0WinOdds = Number(universalPokerJSON.odds[0]).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2 })
144
- const p1WinOdds = Number(universalPokerJSON.odds[1]).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2 })
107
+ const odds = universalPokerJSON.odds || [];
108
+ const p0WinOdds = Number(odds[0] ?? 0).toLocaleString(undefined, {
109
+ style: 'percent',
110
+ minimumFractionDigits: 2
111
+ });
112
+ const p1WinOdds = Number(odds[1] ?? 0).toLocaleString(undefined, {
113
+ style: 'percent',
114
+ minimumFractionDigits: 2
115
+ });
145
116
  result.winOdds = [p0WinOdds, p1WinOdds];
146
117
 
147
118
  return result;
148
119
  }
149
120
 
121
+ function splitCards(cardString) {
122
+ if (!cardString) {
123
+ return [];
124
+ }
125
+ return cardString.match(/.{1,2}/g) || [];
126
+ }
150
127
 
151
- function _getCurrentUniversalPokerFromStateHistory(stateHistory, step) {
152
- if (stateHistory) {
128
+ function isPlaceholderString(cardString) {
129
+ return typeof cardString === 'string' && /^((2c)+)$/i.test(cardString);
130
+ }
153
131
 
154
- const agentSteps = stateHistory.filter(s => JSON.parse(JSON.parse(s).current_universal_poker_json).current_player !== -1);
155
- const currentStep = agentSteps[step];
156
- return JSON.parse(JSON.parse(currentStep).current_universal_poker_json);
132
+ function sanitizeCardList(cards) {
133
+ return (cards || []).filter((card) => card);
134
+ }
135
+
136
+ function formatActionDisplay(actionString) {
137
+ if (!actionString) {
138
+ return '';
139
+ }
140
+ const playerMatch = actionString.match(/move=([^\s]+)/);
141
+ if (!playerMatch) {
142
+ return '';
143
+ }
144
+ const moveRaw = playerMatch[1];
145
+ const moveLower = moveRaw.toLowerCase();
146
+ if (moveLower.startsWith('bet') || moveLower.startsWith('raise')) {
147
+ const amountMatch = moveRaw.match(/\d+/);
148
+ return amountMatch ? `r${amountMatch[0]}` : 'r';
149
+ }
150
+ if (moveLower === 'call') {
151
+ return 'c';
152
+ }
153
+ if (moveLower === 'check') {
154
+ return 'k';
157
155
  }
158
- return null;
156
+ if (moveLower === 'fold') {
157
+ return 'f';
158
+ }
159
+ return moveRaw;
159
160
  }
160
161
 
162
+ function getBlinds(configuration) {
163
+ const blindConfig = configuration?.openSpielGameParameters?.universal_poker_game_string?.blind;
164
+ if (typeof blindConfig !== 'string') {
165
+ return { bigBlind: null, smallBlind: null };
166
+ }
167
+ const parts = blindConfig
168
+ .trim()
169
+ .split(/\s+/)
170
+ .map((entry) => Number(entry))
171
+ .filter((n) => !Number.isNaN(n));
172
+ if (parts.length >= 2) {
173
+ return { bigBlind: parts[0], smallBlind: parts[1] };
174
+ }
175
+ return { bigBlind: null, smallBlind: null };
176
+ }
161
177
 
162
- export const getPokerStateForStep = (environment, step) => {
163
- const numPlayers = 2;
164
- // --- Step Validation ---
165
- if (!environment || !environment.steps || !environment.steps[step] || !environment.info) {
166
- // return default state
167
- return null;
178
+ function getCommunityCardsFromUniversal(universal, numPlayers) {
179
+ const parsed = _parseStepHistoryData(universal, null, numPlayers);
180
+ const cards = splitCards(parsed.communityCards);
181
+ const actual = cards.filter((card) => card && card.toLowerCase() !== PLACEHOLDER_CARD);
182
+ if (actual.length < 3) {
183
+ return [];
168
184
  }
185
+ return actual;
186
+ }
169
187
 
170
- // --- Default State ---
171
- const stateUIData = {
172
- players: Array(numPlayers).fill(null).map((_, i) => {
173
- const agentName = environment?.info?.TeamNames?.[i] ||
174
- `Player ${i}`;
175
- const thumbnail = environment?.info?.Agents?.[i].ThumbnailUrl;
176
- return {
177
- id: `player${i}`,
178
- name: agentName,
179
- thumbnail: thumbnail,
180
- stack: 0,
181
- cards: [], // Will be filled with nulls or cards
182
- currentBet: 0,
183
- isDealer: i === 0,
184
- isTurn: false,
185
- reward: null
186
- };
187
- }),
188
- communityCards: [],
189
- pot: 0,
190
- isTerminal: false,
191
- blinds: [1, 2],
192
- lastMoves: [],
193
- rawObservation: null, // For debugging
194
- step: step,
195
- winOdds: [],
196
- fiveCardBestHands: [],
197
- currentPlayer: -1
188
+ function getHandCardsFromUniversal(universal, numPlayers) {
189
+ const parsed = _parseStepHistoryData(universal, null, numPlayers);
190
+ return (parsed.cards || []).map((cardString) => {
191
+ if (isPlaceholderString(cardString)) {
192
+ return [];
193
+ }
194
+ return sanitizeCardList(splitCards(cardString));
195
+ });
196
+ }
197
+
198
+ function buildTimeline(environment, numPlayers) {
199
+ const stateHistory = environment?.info?.stateHistory || [];
200
+ if (!stateHistory.length) {
201
+ return [];
202
+ }
203
+
204
+ const parsedStates = stateHistory.map((entry, idx) => {
205
+ const outer = JSON.parse(entry);
206
+ return {
207
+ idx,
208
+ outer,
209
+ universal: JSON.parse(outer.current_universal_poker_json)
210
+ };
211
+ });
212
+
213
+ const hands = [];
214
+ let currentHandNumber = parsedStates[0]?.outer?.hand_number ?? 0;
215
+ let currentStates = [];
216
+ parsedStates.forEach((stateInfo) => {
217
+ const handNumber = stateInfo.outer?.hand_number ?? currentHandNumber;
218
+ if (handNumber !== currentHandNumber) {
219
+ if (currentStates.length) {
220
+ hands.push({ handNumber: currentHandNumber, states: currentStates });
221
+ }
222
+ currentStates = [];
223
+ currentHandNumber = handNumber;
224
+ }
225
+ currentStates.push(stateInfo);
226
+ });
227
+ if (currentStates.length) {
228
+ hands.push({ handNumber: currentHandNumber, states: currentStates });
229
+ }
230
+
231
+ const processedSteps = environment.__processedSteps || environment.steps || [];
232
+ const actionsByHand = new Map();
233
+ processedSteps.forEach((step) => {
234
+ const handNumber = step?.hand ?? 0;
235
+ if (!actionsByHand.has(handNumber)) {
236
+ actionsByHand.set(handNumber, []);
237
+ }
238
+ if (!step?.isEndState && step?.step?.action && step.step.action.submission !== -1) {
239
+ const actionString = step.step.action.actionString || '';
240
+ const playerMatch = actionString.match(/player=(\d+)/);
241
+ const playerIndex = playerMatch ? parseInt(playerMatch[1], 10) : null;
242
+ actionsByHand.get(handNumber).push({
243
+ playerIndex,
244
+ actionText: formatActionDisplay(actionString),
245
+ stateHistoryIndex: step.stateHistoryIndex
246
+ });
247
+ }
248
+ });
249
+
250
+ const events = [];
251
+ let orderCounter = 0;
252
+ const pushEvent = (stateIndex, event) => {
253
+ events.push({
254
+ order: orderCounter++,
255
+ stateIndex,
256
+ highlightPlayer: event.highlightPlayer,
257
+ actionText: event.actionText,
258
+ hideHoleCards: event.hideHoleCards,
259
+ hideCommunity: event.hideCommunity
260
+ });
198
261
  };
199
262
 
200
- // We have two sources for current game state: stepHistory and steps
201
- // This is because neither source contains all the information we need
263
+ hands.forEach(({ handNumber, states }) => {
264
+ if (!states.length) {
265
+ return;
266
+ }
202
267
 
203
- const p0stateFromSteps = environment.steps[step][0];
204
- const p1stateFromSteps = environment.steps[step][1];
268
+ const firstState = states[0];
269
+ const dealer = firstState.outer?.dealer ?? 0;
270
+ const { bigBlind, smallBlind } = getBlinds(environment.configuration);
271
+ const smallBlindPlayer = dealer % numPlayers;
272
+ const bigBlindPlayer = (dealer + 1) % numPlayers;
273
+
274
+ pushEvent(firstState.idx, { highlightPlayer: null, actionText: '', hideHoleCards: true, hideCommunity: true });
275
+ pushEvent(firstState.idx, { highlightPlayer: smallBlindPlayer, actionText: smallBlind != null ? `SB ${smallBlind}` : 'SB', hideHoleCards: true, hideCommunity: true });
276
+ pushEvent(firstState.idx, { highlightPlayer: bigBlindPlayer, actionText: bigBlind != null ? `BB ${bigBlind}` : 'BB', hideHoleCards: true, hideCommunity: true });
277
+
278
+ const firstActionState = states.find((stateInfo) => stateInfo.universal.current_player !== -1) || firstState;
279
+ pushEvent(firstActionState.idx, { highlightPlayer: null, actionText: '', hideHoleCards: false, hideCommunity: true });
280
+
281
+ const actions = actionsByHand.get(handNumber) || [];
282
+ actions.forEach((action) => {
283
+ const targetIndex = typeof action.stateHistoryIndex === 'number' ? action.stateHistoryIndex : states[0].idx;
284
+ const postState = states.find((stateInfo) => stateInfo.idx > targetIndex) || states[states.length - 1];
285
+ pushEvent(postState.idx, {
286
+ highlightPlayer: action.playerIndex,
287
+ actionText: action.actionText,
288
+ hideHoleCards: false,
289
+ hideCommunity: false
290
+ });
291
+ });
292
+
293
+ let currentStageCommunityLength = 0;
294
+ states.forEach((stateInfo) => {
295
+ const communityCards = getCommunityCardsFromUniversal(stateInfo.universal, numPlayers);
296
+ const communityLength = communityCards.length;
297
+ if (communityLength > currentStageCommunityLength) {
298
+ currentStageCommunityLength = communityLength;
299
+ if (communityLength === 3 || communityLength === 4 || communityLength === 5) {
300
+ pushEvent(stateInfo.idx, {
301
+ highlightPlayer: null,
302
+ actionText: '',
303
+ hideHoleCards: false,
304
+ hideCommunity: false
305
+ });
306
+ }
307
+ }
308
+ });
309
+ });
310
+
311
+ events.sort((a, b) => a.order - b.order);
312
+ return events.map(({ stateIndex, highlightPlayer, actionText, hideHoleCards, hideCommunity }) => ({
313
+ stateIndex,
314
+ highlightPlayer,
315
+ actionText,
316
+ hideHoleCards: !!hideHoleCards,
317
+ hideCommunity: !!hideCommunity
318
+ }));
319
+ }
205
320
 
206
- const currentStateHistory = JSON.parse(environment.info.stateHistory[step]);
207
- const currentStateFromStateHistory = JSON.parse(currentStateHistory.current_universal_poker_json);
321
+ function getTimeline(environment, numPlayers) {
322
+ if (!environment.__timeline) {
323
+ environment.__timeline = buildTimeline(environment, numPlayers);
324
+ }
325
+ return environment.__timeline;
326
+ }
208
327
 
209
- // TODO: Handle the flop phase steps (chance steps)
328
+ function getUniversalState(environment, index) {
329
+ const entry = environment?.info?.stateHistory?.[index];
330
+ if (!entry) {
331
+ return null;
332
+ }
333
+ const outer = JSON.parse(entry);
334
+ return {
335
+ outer,
336
+ universal: JSON.parse(outer.current_universal_poker_json)
337
+ };
338
+ }
210
339
 
211
- const currentUniversalPokerJSON = _getCurrentUniversalPokerFromStateHistory(environment.info.stateHistory, step);
212
- const currentStepFromStateHistory = _parseStepHistoryData(currentUniversalPokerJSON);
340
+ export const getPokerStateForStep = (environment, step) => {
341
+ const numPlayers = 2;
342
+ if (!environment || !environment.info?.stateHistory) {
343
+ return null;
344
+ }
213
345
 
214
- const currentStepAgents = environment.steps[step];
215
- if (!currentStepAgents || currentStepAgents.length < numPlayers) {
216
- return stateUIData;
346
+ const timeline = getTimeline(environment, numPlayers);
347
+ const event = timeline[step];
348
+ if (!event) {
349
+ return null;
350
+ }
351
+ const stateInfo = getUniversalState(environment, event.stateIndex);
352
+ if (!stateInfo) {
353
+ return null;
217
354
  }
218
355
 
219
- const pot_size = currentStepFromStateHistory.bets.reduce((a, b) => a + b, 0);
220
- const player_contributions = currentStepFromStateHistory.bets;
221
- const starting_stacks = currentUniversalPokerJSON.starting_stacks;
222
- const player_hands = [
223
- currentStepFromStateHistory.cards[0]?.match(/.{1,2}/g) || [],
224
- currentStepFromStateHistory.cards[1]?.match(/.{1,2}/g) || []
225
- ];
226
- const board_cards = currentStepFromStateHistory.communityCards ? currentStepFromStateHistory.communityCards.match(/.{1,2}/g).reverse() : [];
227
-
228
- // TODO: Add odds, best_five_card_hands best_hand_rank_types
229
-
230
- // TODO: Add current player
231
-
232
- const isTerminal = false // TODO: read isTerminal from observation
233
- stateUIData.isTerminal = isTerminal;
234
- stateUIData.pot = pot_size || 0;
235
- stateUIData.communityCards = board_cards || [];
236
- stateUIData.lastMoves = currentStepFromStateHistory.lastMoves;
237
- stateUIData.blinds = currentStateFromStateHistory.blinds;
238
-
239
- // --- Update Players ---
240
- for (let i = 0; i < numPlayers; i++) {
241
- const pData = stateUIData.players[i];
242
- const contribution = player_contributions ? player_contributions[i] : 0;
243
- const startStack = starting_stacks ? starting_stacks[i] : 0;
244
-
245
- pData.currentBet = contribution;
246
- pData.stack = startStack - contribution;
247
- pData.cards = (player_hands[i] || []).map(c => c === "??" ? null : c);
248
- pData.isTurn = p0stateFromSteps.observation.currentPlayer === i; // TODO: this may need to be flipped to show the other player responding to this move, which will display instantly
249
- pData.isDealer = currentStateFromStateHistory.blinds[i] === 1; // infer dealer from small blind
250
-
251
- if (isTerminal) {
252
- const reward = environment.rewards ? environment.rewards[i] : null;
253
- pData.reward = reward;
254
- if (reward > 0) {
255
- pData.name = `${pData.name} wins 🎉`;
256
- pData.isWinner = true;
257
- pData.status = null;
258
- } else {
259
- pData.status = null;
260
- }
261
- } else if (pData.stack === 0 && pData.currentBet > 0) {
262
- pData.status = "All-in";
356
+ const parsedStateHistory = _parseStepHistoryData(
357
+ stateInfo.universal,
358
+ stateInfo.universal?.current_player,
359
+ numPlayers
360
+ );
361
+
362
+ const startingStacks = stateInfo.universal?.starting_stacks || Array(numPlayers).fill(0);
363
+ const contributions = stateInfo.universal?.player_contributions || parsedStateHistory.bets || Array(numPlayers).fill(0);
364
+ const rewards = stateInfo.outer?.hand_returns || [];
365
+ const communityCards = getCommunityCardsFromUniversal(stateInfo.universal, numPlayers);
366
+
367
+ const players = Array(numPlayers)
368
+ .fill(null)
369
+ .map((_, i) => {
370
+ const agentName = environment?.info?.TeamNames?.[i] || `Player ${i}`;
371
+ const thumbnail = environment?.info?.Agents?.[i]?.ThumbnailUrl;
372
+ return {
373
+ id: `player${i}`,
374
+ name: agentName,
375
+ thumbnail,
376
+ stack: startingStacks[i] - (contributions[i] || 0),
377
+ cards: [],
378
+ currentBet: contributions[i] || 0,
379
+ isDealer: stateInfo.outer?.dealer === i,
380
+ isTurn: stateInfo.universal?.current_player === i,
381
+ isLastActor: event.highlightPlayer === i,
382
+ reward: rewards[0]?.[i] ?? null,
383
+ actionDisplayText: event.highlightPlayer === i ? event.actionText : ''
384
+ };
385
+ });
386
+
387
+ const handCards = getHandCardsFromUniversal(stateInfo.universal, numPlayers);
388
+ players.forEach((player, index) => {
389
+ if (event.hideHoleCards) {
390
+ player.cards = [];
391
+ } else {
392
+ player.cards = handCards[index] || [];
263
393
  }
264
- }
394
+ });
265
395
 
266
- return stateUIData;
267
- }
396
+ const displayCommunity = event.hideCommunity ? [] : communityCards;
397
+
398
+ return {
399
+ players,
400
+ communityCards: displayCommunity,
401
+ pot: contributions.reduce((sum, value) => sum + (value || 0), 0),
402
+ isTerminal: false,
403
+ rawObservation: stateInfo.universal,
404
+ step,
405
+ winOdds: parsedStateHistory.winOdds,
406
+ fiveCardBestHands: [],
407
+ currentPlayer: stateInfo.universal?.current_player ?? -1,
408
+ winner: -1
409
+ };
410
+ };
@@ -1,37 +1,37 @@
1
- import { Player, GameAdapter, ReplayData } from '@kaggle-environments/core';
2
- import { renderer } from './repeated_poker_renderer.js';
3
- import { render } from 'preact';
1
+ import { Player, GameAdapter, ReplayData } from "@kaggle-environments/core";
2
+ import { renderer } from "./repeated_poker_renderer.js";
3
+ import { render } from "preact";
4
4
 
5
5
  class LegacyAdapter implements GameAdapter {
6
- private container: HTMLElement | null = null;
6
+ private container: HTMLElement | null = null;
7
7
 
8
- mount(container: HTMLElement): void {
9
- this.container = container;
10
- }
8
+ mount(container: HTMLElement): void {
9
+ this.container = container;
10
+ }
11
11
 
12
- render(step: number, replay: ReplayData, agents: any[]): void {
13
- if (!this.container) return;
14
- this.container.innerHTML = ''; // Clear container before rendering
15
- renderer({
16
- parent: this.container,
17
- environment: replay,
18
- step: step,
19
- agents: agents,
20
- // These are probably not used by poker but good to have
21
- width: this.container.clientWidth,
22
- height: this.container.clientHeight
23
- });
24
- }
12
+ render(step: number, replay: ReplayData, agents: any[]): void {
13
+ if (!this.container) return;
14
+ this.container.innerHTML = ""; // Clear container before rendering
15
+ renderer({
16
+ parent: this.container,
17
+ environment: replay,
18
+ step: step,
19
+ agents: agents,
20
+ // These are probably not used by poker but good to have
21
+ width: this.container.clientWidth,
22
+ height: this.container.clientHeight,
23
+ });
24
+ }
25
25
 
26
- unmount(): void {
27
- if (this.container) {
28
- render(null, this.container);
29
- }
30
- this.container = null;
26
+ unmount(): void {
27
+ if (this.container) {
28
+ render(null, this.container);
31
29
  }
30
+ this.container = null;
31
+ }
32
32
  }
33
33
 
34
- const app = document.getElementById('app');
34
+ const app = document.getElementById("app");
35
35
  if (app) {
36
- new Player(app, new LegacyAdapter());
36
+ new Player(app, new LegacyAdapter());
37
37
  }
@@ -151,6 +151,10 @@ export function renderer(options) {
151
151
  border-color: #20BEFF;
152
152
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 20px rgba(32, 190, 255, 0.5);
153
153
  }
154
+ .player-info-area.winner-player {
155
+ border-color: #FFEB70;
156
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 20px rgba(255, 235, 112, 0.6);
157
+ }
154
158
  .player-container-0 .player-info-area { flex-direction: column-reverse; }
155
159
  .player-name-wrapper {
156
160
  display: flex;
@@ -226,6 +230,7 @@ export function renderer(options) {
226
230
  text-align: center;
227
231
  height: 20pxrem; line-height: 20px;
228
232
  width: 150px;
233
+ height: 20px;
229
234
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
230
235
  }
231
236
  .blind-indicator { font-size: 0.7rem; color: #a0aec0; margin-top: 3px; }
@@ -520,7 +525,6 @@ export function renderer(options) {
520
525
  // --- State Parsing ---
521
526
  function _parseKagglePokerState(options) {
522
527
  const { environment, step } = options;
523
- const numPlayers = 2;
524
528
 
525
529
  // --- Default State ---
526
530
  const defaultStateUiData = {
@@ -531,7 +535,7 @@ export function renderer(options) {
531
535
  };
532
536
 
533
537
  // --- Step Validation ---
534
- if (!environment || !environment.steps || !environment.steps[step] || !environment.info?.stateHistory) {
538
+ if (!environment || !step) {
535
539
  return defaultStateUiData;
536
540
  }
537
541
 
@@ -554,13 +558,13 @@ export function renderer(options) {
554
558
  elements.gameLayout.style.transform = `scale(${scale})`;
555
559
  }
556
560
 
557
- function _renderPokerTableUI(data, passedOptions) {
561
+ function _renderPokerTableUI(data) {
558
562
  if (!elements.pokerTable || !data) return;
559
563
  const { players, communityCards, pot, isTerminal, step } = data;
560
564
 
561
565
  // Update step counter
562
566
  if (elements.stepCounter && step !== undefined) {
563
- elements.stepCounter.textContent = `Step: ${step}`;
567
+ elements.stepCounter.textContent = `Debug Step: ${step}`;
564
568
  }
565
569
 
566
570
  if (elements.diagnosticHeader && data.rawObservation) {
@@ -596,12 +600,10 @@ export function renderer(options) {
596
600
  players.forEach((playerData, index) => {
597
601
  const playerNameElement = elements.playerNames[index];
598
602
  if (playerNameElement) {
599
- const playerNameText =
600
- !playerData.isTurn && !isTerminal ? `${playerData.name} responding...` : playerData.name;
601
- playerNameElement.textContent = playerNameText;
603
+ playerNameElement.textContent = playerData.name;
602
604
 
603
- // Highlight current player's turn
604
- if (playerData.isTurn && !isTerminal) {
605
+ // Highlight the player who took the most recent action
606
+ if (playerData.isLastActor) {
605
607
  playerNameElement.classList.add('current-turn');
606
608
  } else {
607
609
  playerNameElement.classList.remove('current-turn');
@@ -647,24 +649,27 @@ export function renderer(options) {
647
649
  const playerInfoArea = elements.playerInfoAreas[index];
648
650
  if (playerInfoArea) {
649
651
  // Highlight active player's pod
650
- if (playerData.isTurn && !isTerminal) {
652
+ if (playerData.isLastActor) {
651
653
  playerInfoArea.classList.add('active-player');
652
654
  } else {
653
655
  playerInfoArea.classList.remove('active-player');
654
656
  }
655
657
 
658
+ // Highlight winner's pod
659
+ if (playerData.isWinner) {
660
+ playerInfoArea.classList.add('winner-player');
661
+ } else {
662
+ playerInfoArea.classList.remove('winner-player');
663
+ }
664
+
656
665
  playerInfoArea.querySelector('.player-stack-value').textContent = `${playerData.stack}`;
657
666
 
658
667
  const betDisplay = playerInfoArea.querySelector('.bet-display');
659
668
  if (playerData.currentBet > 0) {
660
- if (data.lastMoves[index]) {
661
- betDisplay.textContent = data.lastMoves[index];
669
+ if (playerData.actionDisplayText) {
670
+ betDisplay.textContent = playerData.actionDisplayText;
662
671
  } else {
663
- if (playerData.isDealer) {
664
- betDisplay.textContent = 'Small Blind';
665
- } else {
666
- betDisplay.textContent = 'Big Blind';
667
- }
672
+ betDisplay.textContent = '';
668
673
  }
669
674
  betDisplay.style.display = 'block';
670
675
  } else {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaggle-environments
3
- Version: 1.23.4
3
+ Version: 1.23.6
4
4
  Summary: Kaggle Environments
5
5
  Author-email: Kaggle <support@kaggle.com>
6
6
  Requires-Python: >=3.10
@@ -194,9 +194,9 @@ kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/
194
194
  kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json,sha256=3X9dsQOgFw_cZ_uXByZIsGrQ5jhFfAZZL7QC6ApJWak,133
195
195
  kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts,sha256=KhIjUn0WWhaoQzQ5YKuWjNndimRF0kFlYDgEnZ0cg7U,208
196
196
  kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json,sha256=jf4ilR6SmOYPNohkIGJvmKP5Gju5FY6sfSStX1qtFZg,28919900
197
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts,sha256=5NZlic4P9aSdMJpWxckaDrObEx2OJj8FNG49g-Z9_ow,1095
198
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.js,sha256=ZTaeLtDKqY8qrnxB3KshJVNfWRjo21e1vLcIRXlYkSI,26456
199
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js,sha256=vSVJsKyrWEHEJuZ5ESYXtHfhSZ60IgEC4eenf2w7ZDc,9139
197
+ kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts,sha256=Its2m61qv7RHlHUzIW6JkmySaHWq1h2bJ5sWY9woots,1000
198
+ kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.js,sha256=rEAJf5I7GKyot9H8BqyatneWvzKJFUfl7G9_hNPHA5Y,26482
199
+ kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js,sha256=6nTmNT2iD2wpc0li2RU-URHM8jlKd4MRJDsVMLRcMI8,12490
200
200
  kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.js,sha256=pXDAu4V2OppRCvMdJKQ56q1uFTJReMPIvBL6gwxIJoI,5734
201
201
  kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_1.svg,sha256=v9yCvpnaQAg8OSUJdJ5PhuTHm9_zXnww-9_7oR_DJpc,22160
202
202
  kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_10.svg,sha256=z3CP2h5eUGlgBdqNoWGcioekAyPgiuzhyRNr-nbutOE,22160
@@ -279,8 +279,8 @@ kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_p
279
279
  kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_no_tie_exile.yaml,sha256=sfSFlFU4F7doZ-wXUWBl-JgJtmpjrLR-SpCAqKnUYeQ,3662
280
280
  kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_roundbiddiscussion.yaml,sha256=UGSLfOhmC-4pRqWsJvOtZRU0YLUuOMAGeEHtxTf3wf8,3710
281
281
  kaggle_environments/static/player.html,sha256=Icl5yYscPe4BRoWt0HLOSRJWnznQq2MdTHHCaC2OrQQ,27753
282
- kaggle_environments-1.23.4.dist-info/entry_points.txt,sha256=h03sq76TdcHvXKcsre1Qm3lIni9dkWehu61xJqI-p8k,69
283
- kaggle_environments-1.23.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
284
- kaggle_environments-1.23.4.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
285
- kaggle_environments-1.23.4.dist-info/METADATA,sha256=g4GU2wwJIRPurJ62IXhZLMdwgQ53gucCZYUTQOZLQc0,916
286
- kaggle_environments-1.23.4.dist-info/RECORD,,
282
+ kaggle_environments-1.23.6.dist-info/entry_points.txt,sha256=h03sq76TdcHvXKcsre1Qm3lIni9dkWehu61xJqI-p8k,69
283
+ kaggle_environments-1.23.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
284
+ kaggle_environments-1.23.6.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
285
+ kaggle_environments-1.23.6.dist-info/METADATA,sha256=EQ9xVZR7e9fuaBqASk1B3rEJwOTii36QXXSU198jlLA,916
286
+ kaggle_environments-1.23.6.dist-info/RECORD,,