kaggle-environments 1.23.5__py3-none-any.whl → 1.23.7__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,63 +1,65 @@
1
- function _getActionStringsFromACPC(bettingString, currentPlayer) {
2
- const moves = [];
1
+ const PLACEHOLDER_CARD = '2c';
3
2
 
4
- // Split the action string by street (e.g., ["r5c", "cr11f"])
3
+ function _getActionStringsFromACPC(bettingString, nextPlayerIndex, numPlayers = 2) {
4
+ const moves = [];
5
5
  const streets = bettingString.split('/');
6
-
7
- // Process each street's actions
8
6
  for (let streetIndex = 0; streetIndex < streets.length; streetIndex++) {
9
7
  const streetAction = streets[streetIndex];
10
8
  let i = 0;
11
-
12
- // 4. Parse the moves within the street
13
9
  while (i < streetAction.length) {
14
10
  const char = streetAction[i];
15
-
16
11
  if (char === 'r') {
17
12
  let amount = '';
18
13
  i++;
19
- // parse all digits of the raise amount
20
14
  while (i < streetAction.length && streetAction[i] >= '0' && streetAction[i] <= '9') {
21
15
  amount += streetAction[i];
22
16
  i++;
23
17
  }
24
- moves.push(`r${amount}`)
18
+ moves.push(`r${amount}`);
25
19
  } else {
26
20
  moves.push(char);
27
21
  i++;
28
- continue;
29
22
  }
30
23
  }
31
24
  }
32
25
 
33
- // 6. Get the last two moves from our complete list
34
26
  const lastMove = moves.length > 0 ? moves[moves.length - 1] : null;
35
-
36
- const actionStrings = currentPlayer === 0 ? [lastMove, ''] : ['', lastMove];
27
+ const actionStrings = Array(numPlayers).fill('');
28
+
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
+ }
37
38
 
38
39
  return actionStrings;
39
40
  }
40
41
 
41
- function _parseStepHistoryData(universalPokerJSON) {
42
+ function _parseStepHistoryData(universalPokerJSON, nextPlayerIndex, numPlayers = 2) {
42
43
  const result = {
43
44
  cards: [],
44
45
  communityCards: '',
45
46
  bets: [],
46
- playerActionStrings: ['', ''],
47
+ playerActionStrings: Array(numPlayers).fill(''),
47
48
  winOdds: [0, 0],
48
49
  };
49
50
 
50
- // Split the string into its main lines
51
+ if (!universalPokerJSON) {
52
+ return result;
53
+ }
54
+
51
55
  const lines = universalPokerJSON.acpc_state.trim().split('\n');
52
56
  if (lines.length < 2) {
53
- console.error("Invalid state string format.");
54
57
  return result;
55
58
  }
56
59
 
57
- const stateLine = lines[0]; // example: "STATE:0:r5c/cr11c/:6cKd|AsJc/7hQh6d/2c"
58
- const spentLine = lines[1]; // example: "Spent: [P0: 11 P1: 11 ]"
60
+ const stateLine = lines[0];
61
+ const spentLine = lines[1];
59
62
 
60
- // --- Parse the Spent Line ---
61
63
  if (spentLine) {
62
64
  const p0BetMatch = spentLine.match(/P0:\s*(\d+)/);
63
65
  const p1BetMatch = spentLine.match(/P1:\s*(\d+)/);
@@ -75,167 +77,334 @@ function _parseStepHistoryData(universalPokerJSON) {
75
77
  result.bets = bets;
76
78
  }
77
79
 
78
- // --- Parse the State Line ---
79
80
  if (stateLine) {
80
81
  const stateParts = stateLine.split(':');
82
+ const cardString = stateParts[stateParts.length - 1];
83
+ const cardSegments = cardString.split('/');
81
84
 
82
- // --- Parse Cards ---
83
- // The card string is always the last part
84
- const cardString = stateParts[stateParts.length - 1]; // example: "6cKd|AsJc/7hQh6d/2c"
85
-
86
- // Split card string by '/' to separate hand block from board blocks
87
- const cardSegments = cardString.split('/'); // example: ["6cKd|AsJc", "7hQh6d", "2c"]
88
-
89
- // Parse the first segment (player hands)
90
85
  if (cardSegments[0]) {
91
86
  const playerHands = cardSegments[0].split('|');
92
87
  if (playerHands.length >= 2) {
93
- // example: "6cKd"
94
88
  result.cards = [playerHands[0], playerHands[1]];
95
89
  }
96
90
  }
97
91
 
98
- // The rest of the segments are community cards, one per street
99
92
  result.communityCards = cardSegments
100
- .slice(1) // gets all elements AFTER the player hands
101
- .filter(Boolean) // removes any empty strings (e.g., from a trailing "/")
102
- .join(''); // joins the remaining segments into a single string
93
+ .slice(1)
94
+ .filter(Boolean)
95
+ .join('');
103
96
 
104
- // --- Parse Betting String --
105
- // The betting string is everything between the 2nd colon and the last colon.
106
- // This handles edge cases like "STATE:0:r5c/cr11c/:cards"
107
97
  const bettingString = stateParts.slice(2, stateParts.length - 1).join(':');
108
-
109
98
  if (bettingString) {
110
- result.playerActionStrings = _getActionStringsFromACPC(bettingString);
99
+ result.playerActionStrings = _getActionStringsFromACPC(
100
+ bettingString,
101
+ nextPlayerIndex,
102
+ numPlayers
103
+ );
111
104
  }
112
105
  }
113
106
 
114
- // Parse win odds
115
- const p0WinOdds = Number(universalPokerJSON.odds[0]).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2 })
116
- 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
+ });
117
116
  result.winOdds = [p0WinOdds, p1WinOdds];
118
117
 
119
118
  return result;
120
119
  }
121
120
 
122
- export const getPokerStateForStep = (environment, step) => {
123
- const numPlayers = 2;
124
- // --- Step Validation ---
125
- if (!environment || !environment.steps || !environment.steps[step] || !environment.info) {
126
- // return default state
127
- return null;
121
+ function splitCards(cardString) {
122
+ if (!cardString) {
123
+ return [];
128
124
  }
125
+ return cardString.match(/.{1,2}/g) || [];
126
+ }
129
127
 
130
- const stepsWithEndStates = environment.steps;
128
+ function isPlaceholderString(cardString) {
129
+ return typeof cardString === 'string' && /^((2c)+)$/i.test(cardString);
130
+ }
131
131
 
132
- // --- Default State ---
133
- const stateUIData = {
134
- players: Array(numPlayers).fill(null).map((_, i) => {
135
- const agentName = environment?.info?.TeamNames?.[i] ||
136
- `Player ${i}`;
137
- const thumbnail = environment?.info?.Agents?.[i].ThumbnailUrl;
138
- return {
139
- id: `player${i}`,
140
- name: agentName,
141
- thumbnail: thumbnail,
142
- stack: 0,
143
- cards: [], // Will be filled with nulls or cards
144
- currentBet: 0,
145
- isDealer: i === 0,
146
- isTurn: false,
147
- reward: null,
148
- actionDisplayText: ""
149
- };
150
- }),
151
- communityCards: [],
152
- pot: 0,
153
- isTerminal: false,
154
- rawObservation: null, // For debugging
155
- step: step,
156
- winOdds: [],
157
- fiveCardBestHands: [],
158
- currentPlayer: -1,
159
- winner: -1,
160
- };
132
+ function sanitizeCardList(cards) {
133
+ return (cards || []).filter((card) => card);
134
+ }
161
135
 
162
- // We have two sources for current game state: stepHistory and steps
163
- // This is because neither source contains all the information we need
164
- const currentStepData = stepsWithEndStates[step > 2 ? step - 2 : 0]; // Skip over setup steps
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';
155
+ }
156
+ if (moveLower === 'fold') {
157
+ return 'f';
158
+ }
159
+ return moveRaw;
160
+ }
165
161
 
166
- const currentPlayer = currentStepData?.step?.observation?.currentPlayer || 0; // TODO: find better way to get current player
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
+ }
167
177
 
168
- const currentStateHistoryEntry = JSON.parse(currentStepData.stateHistory);
169
- const currentUniversalPokerJSON = JSON.parse(currentStateHistoryEntry.current_universal_poker_json);
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 [];
184
+ }
185
+ return actual;
186
+ }
170
187
 
171
- // TODO: Handle the flop phase steps (chance steps)
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
+ }
172
197
 
173
- const currentStepFromStateHistory = _parseStepHistoryData(currentUniversalPokerJSON);
198
+ function buildTimeline(environment, numPlayers) {
199
+ const stateHistory = environment?.info?.stateHistory || [];
200
+ if (!stateHistory.length) {
201
+ return [];
202
+ }
174
203
 
175
- const currentStepAgents = environment.steps[step];
176
- if (!currentStepAgents || currentStepAgents.length < numPlayers) {
177
- return stateUIData;
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 });
178
229
  }
179
230
 
180
- const pot_size = currentStepFromStateHistory.bets.reduce((a, b) => a + b, 0);
181
- const player_contributions = currentStepFromStateHistory.bets;
182
- const starting_stacks = currentUniversalPokerJSON.starting_stacks;
183
- const player_hands = [
184
- currentStepFromStateHistory.cards[0]?.match(/.{1,2}/g) || [],
185
- currentStepFromStateHistory.cards[1]?.match(/.{1,2}/g) || []
186
- ];
187
- const board_cards = currentStepFromStateHistory.communityCards ? currentStepFromStateHistory.communityCards.match(/.{1,2}/g).reverse() : [];
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
+ });
261
+ };
262
+
263
+ hands.forEach(({ handNumber, states }) => {
264
+ if (!states.length) {
265
+ return;
266
+ }
188
267
 
189
- // TODO: Add odds, best_five_card_hands best_hand_rank_types
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
+ }
190
320
 
191
- // TODO: Add current player
321
+ function getTimeline(environment, numPlayers) {
322
+ if (!environment.__timeline) {
323
+ environment.__timeline = buildTimeline(environment, numPlayers);
324
+ }
325
+ return environment.__timeline;
326
+ }
192
327
 
193
- const isTerminal = false // TODO: read isTerminal from observation
194
- stateUIData.isTerminal = isTerminal;
195
- stateUIData.pot = pot_size || 0;
196
- stateUIData.communityCards = board_cards || [];
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
+ }
197
339
 
198
- // --- Update Players ---
199
- for (let i = 0; i < numPlayers; i++) {
200
- const pData = stateUIData.players[i];
201
- const contribution = player_contributions ? player_contributions[i] : 0;
202
- const startStack = starting_stacks ? starting_stacks[i] : 0;
340
+ export const getPokerStateForStep = (environment, step) => {
341
+ const numPlayers = 2;
342
+ if (!environment || !environment.info?.stateHistory) {
343
+ return null;
344
+ }
203
345
 
204
- pData.currentBet = contribution;
205
- pData.stack = startStack - contribution;
206
- pData.cards = (player_hands[i] || []).map(c => c === "??" ? null : c);
207
- pData.isTurn = currentPlayer === i; // TODO: this may need to be flipped to show the other player responding to this move, which will display instantly
208
- pData.isDealer = currentStateHistoryEntry.dealer === i;
209
- pData.actionDisplayText = currentStepFromStateHistory.playerActionStrings[i];
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;
354
+ }
210
355
 
211
- if (currentStepData.isEndState) {
212
- pData.isTurn = false;
213
- pData.isWinner = currentStepData.winner === i;
214
- if (currentStepData.winner === i) {
215
- pData.actionDisplayText = "WINNER"
216
- } else {
217
- if (currentStepData.handConclusion === "fold") {
218
- pData.actionDisplayText = "FOLD"
219
- } else {
220
- pData.actionDisplayText = "LOSER"
221
- }
222
- }
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] || [];
223
393
  }
394
+ });
224
395
 
225
- if (isTerminal) {
226
- const reward = environment.rewards ? environment.rewards[i] : null;
227
- pData.reward = reward;
228
- if (reward > 0) {
229
- pData.name = `${pData.name} wins 🎉`;
230
- pData.isWinner = true;
231
- pData.status = null;
232
- } else {
233
- pData.status = null;
234
- }
235
- } else if (pData.stack === 0 && pData.currentBet > 0) {
236
- pData.status = "All-in";
237
- }
238
- }
396
+ const displayCommunity = event.hideCommunity ? [] : communityCards;
239
397
 
240
- return stateUIData;
241
- }
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
  }
@@ -525,7 +525,6 @@ export function renderer(options) {
525
525
  // --- State Parsing ---
526
526
  function _parseKagglePokerState(options) {
527
527
  const { environment, step } = options;
528
- const numPlayers = 2;
529
528
 
530
529
  // --- Default State ---
531
530
  const defaultStateUiData = {
@@ -536,7 +535,7 @@ export function renderer(options) {
536
535
  };
537
536
 
538
537
  // --- Step Validation ---
539
- if (!environment || !environment.steps || !environment.steps[step] || !environment.info?.stateHistory) {
538
+ if (!environment || !step) {
540
539
  return defaultStateUiData;
541
540
  }
542
541
 
@@ -559,7 +558,7 @@ export function renderer(options) {
559
558
  elements.gameLayout.style.transform = `scale(${scale})`;
560
559
  }
561
560
 
562
- function _renderPokerTableUI(data, passedOptions) {
561
+ function _renderPokerTableUI(data) {
563
562
  if (!elements.pokerTable || !data) return;
564
563
  const { players, communityCards, pot, isTerminal, step } = data;
565
564
 
@@ -603,8 +602,8 @@ export function renderer(options) {
603
602
  if (playerNameElement) {
604
603
  playerNameElement.textContent = playerData.name;
605
604
 
606
- // Highlight current player's turn
607
- if (playerData.isTurn && !isTerminal) {
605
+ // Highlight the player who took the most recent action
606
+ if (playerData.isLastActor) {
608
607
  playerNameElement.classList.add('current-turn');
609
608
  } else {
610
609
  playerNameElement.classList.remove('current-turn');
@@ -650,7 +649,7 @@ export function renderer(options) {
650
649
  const playerInfoArea = elements.playerInfoAreas[index];
651
650
  if (playerInfoArea) {
652
651
  // Highlight active player's pod
653
- if (playerData.isTurn && !isTerminal) {
652
+ if (playerData.isLastActor) {
654
653
  playerInfoArea.classList.add('active-player');
655
654
  } else {
656
655
  playerInfoArea.classList.remove('active-player');
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaggle-environments
3
- Version: 1.23.5
3
+ Version: 1.23.7
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=RmbMsVoJobYNypSiyv1kdG-hleRR5-jquIZJZZdVcyM,26598
199
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js,sha256=T-2pegCVHT1OP6PhllPS-3RRQYWe912v2dw5eR5tb0k,8051
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.5.dist-info/entry_points.txt,sha256=h03sq76TdcHvXKcsre1Qm3lIni9dkWehu61xJqI-p8k,69
283
- kaggle_environments-1.23.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
284
- kaggle_environments-1.23.5.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
285
- kaggle_environments-1.23.5.dist-info/METADATA,sha256=fO4oOApn4Mfm40bqXjJHUdnUYh9nqeKvB6ju2FHGLIc,916
286
- kaggle_environments-1.23.5.dist-info/RECORD,,
282
+ kaggle_environments-1.23.7.dist-info/entry_points.txt,sha256=h03sq76TdcHvXKcsre1Qm3lIni9dkWehu61xJqI-p8k,69
283
+ kaggle_environments-1.23.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
284
+ kaggle_environments-1.23.7.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
285
+ kaggle_environments-1.23.7.dist-info/METADATA,sha256=KUPMXM9qRhVqBjJCC1PG_zgu0bIt-aZjpTB6M_Npp4I,916
286
+ kaggle_environments-1.23.7.dist-info/RECORD,,