kaggle-environments 1.22.6__py3-none-any.whl → 1.24.3__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.

Files changed (68) hide show
  1. kaggle_environments/envs/connectx/visualizer/default/index.html +13 -0
  2. kaggle_environments/envs/connectx/visualizer/default/package.json +22 -0
  3. kaggle_environments/envs/connectx/visualizer/default/replays/test-replay.json +1129 -0
  4. kaggle_environments/envs/connectx/visualizer/default/src/main.ts +12 -0
  5. kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +396 -0
  6. kaggle_environments/envs/connectx/visualizer/default/src/style.css +38 -0
  7. kaggle_environments/envs/connectx/visualizer/default/tsconfig.json +4 -0
  8. kaggle_environments/envs/connectx/visualizer/default/vite.config.ts +7 -0
  9. kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js +163 -88
  10. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/index.html +13 -0
  11. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +23 -0
  12. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json +1 -0
  13. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_first_steps.mjs +202 -0
  14. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_replay.mjs +215 -0
  15. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_steps_with_end_states.mjs +234 -0
  16. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +260 -0
  17. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.ts +61 -0
  18. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/debug_repeated_poker_renderer.ts +49 -0
  19. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_1.svg +22 -0
  20. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_10.svg +22 -0
  21. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_100.svg +48 -0
  22. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_25.svg +22 -0
  23. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_5.svg +22 -0
  24. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +36 -0
  25. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.ts +573 -0
  26. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/style.css +594 -0
  27. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json +7 -0
  28. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts +6 -0
  29. kaggle_environments/envs/werewolf/README.md +190 -0
  30. kaggle_environments/envs/werewolf/harness/__init__.py +0 -0
  31. kaggle_environments/envs/werewolf/harness/base.py +773 -0
  32. kaggle_environments/envs/werewolf/harness/litellm_models.yaml +51 -0
  33. kaggle_environments/envs/werewolf/harness/main.py +54 -0
  34. kaggle_environments/envs/werewolf/harness/test_base.py +35 -0
  35. kaggle_environments/envs/werewolf/runner.py +146 -0
  36. kaggle_environments/envs/werewolf/scripts/__init__.py +0 -0
  37. kaggle_environments/envs/werewolf/scripts/add_audio.py +425 -0
  38. kaggle_environments/envs/werewolf/scripts/configs/audio/standard.yaml +24 -0
  39. kaggle_environments/envs/werewolf/scripts/configs/run/block_basic.yaml +102 -0
  40. kaggle_environments/envs/werewolf/scripts/configs/run/comprehensive.yaml +100 -0
  41. kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_DisableDoctorSelfSave_DisableDoctorConsecutiveSave_large.yaml +104 -0
  42. kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_large.yaml +103 -0
  43. kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_small.yaml +103 -0
  44. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard.yaml +103 -0
  45. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_DisableDoctorConsecutiveSave.yaml +104 -0
  46. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam.yaml +105 -0
  47. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationNoReveal_DayExileNoReveal.yaml +105 -0
  48. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationRevealTeam_DayExileRevealTeam.yaml +105 -0
  49. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_disable_doctor_self_save.yaml +103 -0
  50. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting.yaml +103 -0
  51. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_no_tie_exile.yaml +103 -0
  52. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_roundbiddiscussion.yaml +105 -0
  53. kaggle_environments/envs/werewolf/scripts/configs/run/run_config.yaml +58 -0
  54. kaggle_environments/envs/werewolf/scripts/configs/run/vertex_api_example_config.yaml +115 -0
  55. kaggle_environments/envs/werewolf/scripts/measure_cost.py +251 -0
  56. kaggle_environments/envs/werewolf/scripts/plot_existing_trajectories.py +135 -0
  57. kaggle_environments/envs/werewolf/scripts/rerender_html.py +87 -0
  58. kaggle_environments/envs/werewolf/scripts/run.py +93 -0
  59. kaggle_environments/envs/werewolf/scripts/run_block.py +237 -0
  60. kaggle_environments/envs/werewolf/scripts/run_pairwise_matrix.py +222 -0
  61. kaggle_environments/envs/werewolf/scripts/self_play.py +196 -0
  62. kaggle_environments/envs/werewolf/scripts/utils.py +47 -0
  63. kaggle_environments/envs/werewolf/werewolf.json +1 -1
  64. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/METADATA +1 -1
  65. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/RECORD +68 -7
  66. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/WHEEL +0 -0
  67. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/entry_points.txt +0 -0
  68. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,573 @@
1
+ import poker_chip_1 from './images/poker_chip_1.svg';
2
+ import poker_chip_5 from './images/poker_chip_5.svg';
3
+ import poker_chip_10 from './images/poker_chip_10.svg';
4
+ import poker_chip_25 from './images/poker_chip_25.svg';
5
+ import poker_chip_100 from './images/poker_chip_100.svg';
6
+ import { RepeatedPokerStep, RepeatedPokerStepPlayer } from '@kaggle-environments/core';
7
+ import { acpcCardToDisplay, CardSuit, suitSVGs } from './components/utils';
8
+ import cssContent from "./style.css?inline";
9
+
10
+ // Add property to global window object
11
+ declare global {
12
+ interface Window {
13
+ __poker_styles_injected?: boolean;
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Options for the renderer
19
+ */
20
+ interface RendererOptions {
21
+ parent: HTMLElement;
22
+ steps: RepeatedPokerStep[]; // This is the main data object
23
+ step?: number;
24
+ width: number;
25
+ height: number;
26
+
27
+ }
28
+
29
+ /**
30
+ * Interface for the cached DOM elements
31
+ */
32
+ interface PokerTableElements {
33
+ gameLayout: HTMLElement | null;
34
+ pokerTableContainer: HTMLElement | null;
35
+ pokerTable: HTMLElement | null;
36
+ communityCardsContainer: HTMLElement | null;
37
+ potDisplay: HTMLElement | null;
38
+ playersContainer: HTMLElement | null;
39
+ playerContainers: HTMLElement[];
40
+ playerCardAreas: HTMLElement[];
41
+ playerInfoAreas: HTMLElement[];
42
+ playerNames: HTMLElement[];
43
+ playerThumbnails: HTMLElement[];
44
+ dealerButton: HTMLElement | null;
45
+ chipStacks: HTMLElement[];
46
+ diagnosticHeader: HTMLElement | null;
47
+ stepCounter: HTMLElement | null; // Note: stepCounter is in 'elements' but not created in _ensurePokerTableElements
48
+ legend: HTMLElement | null;
49
+ }
50
+
51
+ export function renderer(options: RendererOptions): void {
52
+ const chipImages: Record<number, string> = {
53
+ 1: poker_chip_1,
54
+ 5: poker_chip_5,
55
+ 10: poker_chip_10,
56
+ 25: poker_chip_25,
57
+ 100: poker_chip_100,
58
+ };
59
+
60
+ const elements: PokerTableElements = {
61
+ gameLayout: null,
62
+ pokerTableContainer: null,
63
+ pokerTable: null,
64
+ communityCardsContainer: null,
65
+ potDisplay: null,
66
+ playersContainer: null,
67
+ playerContainers: [],
68
+ playerCardAreas: [],
69
+ playerInfoAreas: [],
70
+ playerNames: [],
71
+ playerThumbnails: [],
72
+ dealerButton: null,
73
+ chipStacks: [],
74
+ diagnosticHeader: null,
75
+ stepCounter: null,
76
+ legend: null,
77
+ };
78
+
79
+ function _injectStyles(passedOptions: Partial<RendererOptions>): void {
80
+ if (typeof document === 'undefined' || window.__poker_styles_injected) {
81
+ return;
82
+ }
83
+ const style = document.createElement('style');
84
+ style.textContent = cssContent;
85
+ const parentForStyles =
86
+ passedOptions && passedOptions.parent ? passedOptions.parent.ownerDocument.head : document.head;
87
+ if (parentForStyles && !parentForStyles.querySelector('style[data-poker-renderer-styles]')) {
88
+ style.setAttribute('data-poker-renderer-styles', 'true');
89
+ parentForStyles.appendChild(style);
90
+ }
91
+ window.__poker_styles_injected = true;
92
+ }
93
+
94
+ function createCardElement(cardStr: string | null, isHidden: boolean = false): HTMLElement {
95
+ const cardDiv = document.createElement('div');
96
+ cardDiv.classList.add('card');
97
+ if (isHidden || !cardStr || cardStr === '?' || cardStr === '??') {
98
+ cardDiv.classList.add('card-back');
99
+ } else {
100
+ const { rank, suit } = acpcCardToDisplay(cardStr);
101
+ const rankSpan = document.createElement('span');
102
+ rankSpan.classList.add('card-rank');
103
+ rankSpan.textContent = rank;
104
+ cardDiv.appendChild(rankSpan);
105
+
106
+ const suitSpan = document.createElement('span');
107
+ suitSpan.classList.add('card-suit');
108
+
109
+ if (suitSVGs[suit as CardSuit]) {
110
+ suitSpan.innerHTML = suitSVGs[suit as CardSuit];
111
+ }
112
+
113
+ cardDiv.appendChild(suitSpan);
114
+
115
+ if (suit === 'hearts') cardDiv.classList.add('card-red');
116
+ else if (suit === 'spades') cardDiv.classList.add('card-black');
117
+ else if (suit === 'diamonds') cardDiv.classList.add('card-blue');
118
+ else if (suit === 'clubs') cardDiv.classList.add('card-green');
119
+ }
120
+ return cardDiv;
121
+ }
122
+
123
+ function updateChipStack(chipStackElement: HTMLElement, betAmount: number): void {
124
+ if (betAmount <= 0) {
125
+ chipStackElement.style.display = 'none';
126
+ return;
127
+ }
128
+
129
+ chipStackElement.style.display = 'flex';
130
+ const chipsContainer = chipStackElement.querySelector('.chip-stack-chips') as HTMLElement;
131
+ const labelElement = chipStackElement.querySelector('.chip-stack-label') as HTMLElement;
132
+
133
+ if (!chipsContainer || !labelElement) return;
134
+
135
+ chipsContainer.innerHTML = '';
136
+ labelElement.textContent = String(betAmount);
137
+
138
+ // Break down bet into denominations (100, 25, 10, 5, 1)
139
+ const denominations = [100, 25, 10, 5, 1];
140
+ let remaining = betAmount;
141
+ const chipCounts: { denom: number; count: number }[] = [];
142
+
143
+ for (const denom of denominations) {
144
+ const count = Math.floor(remaining / denom);
145
+ if (count > 0) {
146
+ chipCounts.push({ denom, count: Math.min(count, 5) }); // Max 5 of each denomination
147
+ remaining -= count * denom;
148
+ }
149
+ }
150
+
151
+ // Render chips separated by denomination (highest to lowest, left to right)
152
+ chipCounts.forEach(({ denom, count }) => {
153
+ const denomStack = document.createElement('div');
154
+ denomStack.className = 'chip-denomination-stack';
155
+
156
+ for (let i = 0; i < count; i++) {
157
+ const chip = document.createElement('div');
158
+ chip.className = 'chip';
159
+ const img = document.createElement('img');
160
+ img.src = chipImages[denom];
161
+ img.alt = `${denom} chip`;
162
+ chip.appendChild(img);
163
+ denomStack.appendChild(chip);
164
+ }
165
+
166
+ chipsContainer.appendChild(denomStack);
167
+ });
168
+ }
169
+
170
+ // --- Board Parsing and Rendering ---
171
+ function _ensurePokerTableElements(parentElement: HTMLElement): boolean {
172
+ if (!parentElement) return false;
173
+ parentElement.innerHTML = '';
174
+ parentElement.classList.add('poker-renderer-host');
175
+
176
+ elements.diagnosticHeader = document.createElement('h1');
177
+ elements.diagnosticHeader.id = 'poker-renderer-diagnostic-header';
178
+ elements.diagnosticHeader.textContent = 'Poker Table Initialized (Live Data)';
179
+ elements.diagnosticHeader.style.cssText =
180
+ 'color: lime; background-color: black; padding: 5px; font-size: 12px; position: absolute; top: 0px; left: 0px; z-index: 10001; display: none;'; // Hidden by default
181
+ parentElement.appendChild(elements.diagnosticHeader);
182
+
183
+ elements.gameLayout = document.createElement('div');
184
+ elements.gameLayout.className = 'poker-game-layout';
185
+ parentElement.appendChild(elements.gameLayout);
186
+
187
+ elements.pokerTableContainer = document.createElement('div');
188
+ elements.pokerTableContainer.className = 'poker-table-container';
189
+ elements.gameLayout.appendChild(elements.pokerTableContainer);
190
+
191
+ elements.playersContainer = document.createElement('div');
192
+ elements.playersContainer.className = 'players-container';
193
+ elements.gameLayout.appendChild(elements.playersContainer);
194
+
195
+ elements.pokerTable = document.createElement('div');
196
+ elements.pokerTable.className = 'poker-table';
197
+ elements.pokerTableContainer.appendChild(elements.pokerTable);
198
+
199
+ const muckLine = document.createElement('div');
200
+ muckLine.className = 'muck-line';
201
+ elements.pokerTable.appendChild(muckLine);
202
+
203
+ // Create chip stacks for each player inside the table
204
+ elements.chipStacks = [];
205
+ for (let i = 0; i < 2; i++) {
206
+ const chipStack = document.createElement('div');
207
+ chipStack.className = `chip-stack chip-stack-player${i}`;
208
+ chipStack.style.display = 'none';
209
+ chipStack.innerHTML = `
210
+ <div class="chip-stack-chips"></div>
211
+ <div class="chip-stack-label">0</div>
212
+ `;
213
+ elements.pokerTable.appendChild(chipStack);
214
+ elements.chipStacks.push(chipStack);
215
+ }
216
+
217
+ const communityArea = document.createElement('div');
218
+ communityArea.className = 'community-cards-area';
219
+ elements.pokerTable.appendChild(communityArea);
220
+
221
+ elements.potDisplay = document.createElement('div');
222
+ elements.potDisplay.className = 'pot-display';
223
+ communityArea.appendChild(elements.potDisplay);
224
+
225
+ elements.communityCardsContainer = document.createElement('div');
226
+ elements.communityCardsContainer.className = 'community-cards-container';
227
+ communityArea.appendChild(elements.communityCardsContainer);
228
+
229
+ elements.playerContainers = [];
230
+ elements.playerCardAreas = [];
231
+ elements.playerInfoAreas = [];
232
+ elements.playerNames = [];
233
+ elements.playerThumbnails = [];
234
+
235
+ for (let i = 0; i < 2; i++) {
236
+ // Create player container that groups all player elements
237
+ const playerContainer = document.createElement('div');
238
+ playerContainer.className = `player-container player-container-${i}`;
239
+ elements.playersContainer.appendChild(playerContainer);
240
+ elements.playerContainers.push(playerContainer);
241
+
242
+ // Player name wrapper with thumbnail
243
+ const playerNameWrapper = document.createElement('div');
244
+ playerNameWrapper.className = `player-name-wrapper`;
245
+ playerContainer.appendChild(playerNameWrapper);
246
+
247
+ // Player thumbnail
248
+ const playerThumbnail = document.createElement('img');
249
+ playerThumbnail.className = `player-thumbnail`;
250
+ playerThumbnail.style.display = 'none'; // Hidden by default
251
+ playerNameWrapper.appendChild(playerThumbnail);
252
+ elements.playerThumbnails.push(playerThumbnail);
253
+
254
+ // Player name
255
+ const playerName = document.createElement('div');
256
+ playerName.className = `player-name`;
257
+ playerName.textContent = `Player ${i}`;
258
+ playerNameWrapper.appendChild(playerName);
259
+ elements.playerNames.push(playerName);
260
+
261
+ // Info area containing bet, cards, and stack
262
+ const playerInfoArea = document.createElement('div');
263
+ playerInfoArea.className = `player-info-area`;
264
+ playerInfoArea.innerHTML = `
265
+ <div class="bet-display">Standby</div>
266
+ <div class="stack-cards-wrapper">
267
+ <div class="player-card-area">
268
+ <div class="player-cards-container"></div>
269
+ </div>
270
+ <div class="player-stats-container">
271
+ <div class="player-hand-rank"></div>
272
+ <div class="player-win-prob"></div>
273
+ <div class="player-tie-prob"></div>
274
+ </div>
275
+ <div class="player-stack">
276
+ <span class="player-stack-value">0</span>
277
+ </div>
278
+ </div>
279
+ `;
280
+ playerContainer.appendChild(playerInfoArea);
281
+ elements.playerInfoAreas.push(playerInfoArea);
282
+
283
+ // Get reference to card area (already in DOM)
284
+ const playerCardArea = playerInfoArea.querySelector('.player-card-area') as HTMLElement;
285
+ elements.playerCardAreas.push(playerCardArea);
286
+ }
287
+
288
+ elements.dealerButton = document.createElement('div');
289
+ elements.dealerButton.className = 'dealer-button';
290
+ elements.dealerButton.textContent = 'D';
291
+ elements.dealerButton.style.display = 'none';
292
+ elements.playersContainer.appendChild(elements.dealerButton);
293
+
294
+ elements.legend = document.createElement('div');
295
+ elements.legend.className = 'legend';
296
+ elements.legend.innerHTML = `
297
+ <div class="legend-title"></div>
298
+ <div class="legend-body"></div>
299
+ `;
300
+ elements.gameLayout.appendChild(elements.legend);
301
+
302
+ return true;
303
+ } // --- State Parsing ---
304
+
305
+ function _applyScale(parentElement: HTMLElement): void {
306
+ if (!parentElement || !elements.gameLayout) return;
307
+
308
+ const parentWidth = parentElement.clientWidth;
309
+ const parentHeight = parentElement.clientHeight;
310
+
311
+ const baseWidth = 1000;
312
+ const baseHeight = 1000;
313
+
314
+ const scaleX = parentWidth / baseWidth;
315
+ const scaleY = parentHeight / baseHeight;
316
+ const scale = Math.min(scaleX, scaleY);
317
+
318
+ elements.gameLayout.style.transform = `scale(${scale})`;
319
+ }
320
+
321
+ function _renderPokerTableUI(data: RepeatedPokerStep): void {
322
+ console.log('data is', data);
323
+ if (!elements.pokerTable || !data || !elements.legend) return;
324
+
325
+ // TODO: [TYPE_MISMATCH] The 'RepeatedPokerStep' type is missing many properties
326
+ // that the original JS code expects.
327
+ const {
328
+ players, // This exists in BaseGameStep
329
+ communityCards, // This is a string in RepeatedPokerStep, but JS expects string[]
330
+ pot, // This exists
331
+ winOdds, // This exists
332
+ fiveCardBestHands, // This exists
333
+ } = data;
334
+
335
+ // TODO: [TYPE_MISMATCH] Manually defining missing properties from the type.
336
+ const isTerminal = false; // 'isTerminal' is not in RepeatedPokerStep
337
+ const handCount = 0; // 'handCount' is not in RepeatedPokerStep
338
+ const winProb = winOdds; // 'winProb' is not in type, mapping 'winOdds'
339
+ const tieProb = null; // 'tieProb' is not in type
340
+ const handRank = fiveCardBestHands; // 'handRank' is not in type, mapping 'fiveCardBestHands'
341
+ const leaderInfo: any = null; // 'leaderInfo' is not in type. Using 'any' to allow compilation.
342
+
343
+ // Update legend
344
+ const legendTitle = elements.legend.querySelector('.legend-title') as HTMLElement;
345
+ const legendBody = elements.legend.querySelector('.legend-body') as HTMLElement;
346
+
347
+ if (!legendTitle || !legendBody) return;
348
+
349
+ legendTitle.innerHTML = ''; // Clear existing content
350
+
351
+ const handSpan = document.createElement('span');
352
+ handSpan.textContent = `Hand: ${handCount !== undefined && handCount !== null ? handCount + 1 : 'Standby'}`;
353
+ legendTitle.appendChild(handSpan);
354
+
355
+ if (leaderInfo) {
356
+ const leaderInfoDiv = document.createElement('div');
357
+ leaderInfoDiv.className = 'legend-leader-info';
358
+
359
+ if (leaderInfo.thumbnail) {
360
+ const leaderThumbnail = document.createElement('img');
361
+ leaderThumbnail.src = leaderInfo.thumbnail;
362
+ leaderThumbnail.className = 'legend-title-avatar';
363
+ leaderInfoDiv.appendChild(leaderThumbnail);
364
+ }
365
+
366
+ const leaderNameSpan = document.createElement('span');
367
+ const leaderName = leaderInfo.name.split(' ')[0];
368
+ leaderNameSpan.textContent = `${leaderName} is up ${leaderInfo.winnings}`;
369
+ leaderInfoDiv.appendChild(leaderNameSpan);
370
+ legendTitle.appendChild(leaderInfoDiv);
371
+ }
372
+
373
+ legendBody.innerHTML = ''; // Clear existing content
374
+
375
+ const table = document.createElement('div');
376
+ table.className = 'legend-table';
377
+
378
+ // ... (rest of legend rendering. It will be mostly empty due to missing 'previousHands') ...
379
+ // (Legend rendering code omitted for brevity as it relies on 'any' types)
380
+
381
+ if (elements.diagnosticHeader && (data as any).rawObservation) {
382
+ // Optional: Show diagnostics for debugging
383
+ // elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${(data as any).rawObservation.current_player} POT:${data.pot}`;
384
+ // elements.diagnosticHeader.style.display = 'block';
385
+ }
386
+
387
+ if (!elements.communityCardsContainer || !elements.potDisplay) return;
388
+
389
+ elements.communityCardsContainer.innerHTML = '';
390
+ // Always show 5 slots for the river
391
+ // Display cards left to right, with empty slots at the end
392
+ const numCommunityCards = 5;
393
+
394
+ // TODO: [TYPE_MISMATCH] 'communityCards' is a string, but the code expects an array of card strings - move this to the transformer
395
+ const communityCardsArray = communityCards.match(/.{1,2}/g) || [];
396
+ const numCards = communityCardsArray.length;
397
+
398
+ // Add actual cards
399
+ for (let i = 0; i < numCards; i++) {
400
+ elements.communityCardsContainer.appendChild(createCardElement(communityCardsArray[i]));
401
+ }
402
+
403
+ // Fill remaining slots with empty cards
404
+ for (let i = numCards; i < numCommunityCards; i++) {
405
+ const emptyCard = document.createElement('div');
406
+ emptyCard.classList.add('card', 'card-empty');
407
+ elements.communityCardsContainer.appendChild(emptyCard);
408
+ }
409
+
410
+ elements.potDisplay.textContent = `Total Pot : ${pot}`;
411
+
412
+ players.forEach((basePlayerData, index) => {
413
+ // The JS code expects properties from 'RepeatedPokerStepPlayer'.
414
+ // Casting 'basePlayerData' to 'RepeatedPokerStepPlayer' to access properties.
415
+ const playerData = basePlayerData as RepeatedPokerStepPlayer;
416
+
417
+ const playerNameElement = elements.playerNames[index];
418
+ if (playerNameElement) {
419
+ playerNameElement.textContent = playerData.name;
420
+
421
+ if (playerData.isTurn) {
422
+ playerNameElement.classList.add('current-turn');
423
+ } else {
424
+ playerNameElement.classList.remove('current-turn');
425
+ }
426
+
427
+ // Add winner class if player won
428
+ if (playerData.isWinner) {
429
+ playerNameElement.classList.add('winner');
430
+ } else {
431
+ playerNameElement.classList.remove('winner');
432
+ }
433
+ }
434
+
435
+ // Update thumbnail
436
+ const playerThumbnailElement = elements.playerThumbnails[index];
437
+ if (playerThumbnailElement && playerData.thumbnail) {
438
+ (playerThumbnailElement as HTMLImageElement).src = playerData.thumbnail;
439
+ playerThumbnailElement.style.display = 'block';
440
+ } else if (playerThumbnailElement) {
441
+ playerThumbnailElement.style.display = 'none';
442
+ }
443
+
444
+ // Update card area (left side)
445
+ const playerCardArea = elements.playerCardAreas[index];
446
+ if (playerCardArea) {
447
+ const playerCardsContainer = playerCardArea.querySelector('.player-cards-container') as HTMLElement;
448
+ if (!playerCardsContainer) return;
449
+ playerCardsContainer.innerHTML = '';
450
+
451
+ // In heads-up, we show both hands at the end.
452
+ const showCards = isTerminal || (playerData.cards && !playerData.cards.includes(null!));
453
+
454
+ // TODO: [TYPE_MISMATCH] 'playerData.cards' is a string, but code expects an array - move this to the transformer
455
+ const playerCardsArray = playerData.cards ? playerData.cards.match(/.{1,2}/g) : [null, null];
456
+
457
+ (playerCardsArray || [null, null]).forEach((cardStr) => {
458
+ playerCardsContainer.appendChild(createCardElement(cardStr, !showCards && cardStr !== null));
459
+ });
460
+ }
461
+
462
+ // Update chip stacks on the table
463
+ if (elements.chipStacks[index]) {
464
+ updateChipStack(elements.chipStacks[index], playerData.currentBet);
465
+ }
466
+
467
+ // Update info area (right side)
468
+ const playerInfoArea = elements.playerInfoAreas[index];
469
+ if (playerInfoArea) {
470
+ // Highlight active player's pod
471
+ if (playerData.isTurn) {
472
+ playerInfoArea.classList.add('active-player');
473
+ } else {
474
+ playerInfoArea.classList.remove('active-player');
475
+ }
476
+
477
+ // Highlight winner's pod
478
+ if (playerData.isWinner) {
479
+ playerInfoArea.classList.add('winner-player');
480
+ } else {
481
+ playerInfoArea.classList.remove('winner-player');
482
+ }
483
+
484
+ const stackValueEl = playerInfoArea.querySelector('.player-stack-value') as HTMLElement;
485
+ if (stackValueEl) {
486
+ stackValueEl.textContent = `${playerData.chipStack}`;
487
+ }
488
+
489
+ const betDisplay = playerInfoArea.querySelector('.bet-display') as HTMLElement;
490
+ if (betDisplay) {
491
+ if (playerData.currentBet > 0) {
492
+ if (playerData.actionDisplayText) {
493
+ betDisplay.textContent = playerData.actionDisplayText;
494
+ } else {
495
+ betDisplay.textContent = '';
496
+ }
497
+ betDisplay.style.display = 'block';
498
+ } else {
499
+ betDisplay.style.display = 'none';
500
+ }
501
+ }
502
+
503
+ const handRankElement = playerInfoArea.querySelector('.player-hand-rank') as HTMLElement;
504
+ if (handRankElement && handRank && handRank[index]) {
505
+ handRankElement.textContent = handRank[index];
506
+ } else if (handRankElement) {
507
+ handRankElement.textContent = '';
508
+ }
509
+
510
+ const winProbElement = playerInfoArea.querySelector('.player-win-prob') as HTMLElement;
511
+ if (winProbElement && winProb && winProb[index] && !isTerminal) {
512
+ winProbElement.textContent = `Win: ${winProb[index]}`;
513
+ } else if (winProbElement) {
514
+ winProbElement.textContent = '';
515
+ }
516
+
517
+ const tieProbElement = playerInfoArea.querySelector('.player-tie-prob') as HTMLElement;
518
+ if (tieProbElement && tieProb && !isTerminal) {
519
+ tieProbElement.textContent = `Tie: ${tieProb}`;
520
+ } else if (tieProbElement) {
521
+ tieProbElement.textContent = '';
522
+ }
523
+ }
524
+ });
525
+
526
+ const dealerPlayerIndex = players.findIndex((p) => (p as RepeatedPokerStepPlayer).isDealer);
527
+ if (elements.dealerButton && elements.playersContainer) {
528
+ if (dealerPlayerIndex !== -1) {
529
+ elements.dealerButton.style.display = 'block';
530
+ elements.dealerButton.classList.remove('dealer-player0', 'dealer-player1');
531
+ elements.dealerButton.classList.add(`dealer-player${dealerPlayerIndex}`);
532
+
533
+ const playerInfoArea = elements.playerInfoAreas[dealerPlayerIndex];
534
+ if (playerInfoArea) {
535
+ const boxRect = playerInfoArea.getBoundingClientRect();
536
+ const containerRect = elements.playersContainer.getBoundingClientRect();
537
+ const left = boxRect.left - containerRect.left - elements.dealerButton.offsetWidth - 20;
538
+ elements.dealerButton.style.left = `${left}px`;
539
+ }
540
+ } else {
541
+ elements.dealerButton.style.display = 'none';
542
+ }
543
+ }
544
+ }
545
+
546
+ // --- MAIN EXECUTION LOGIC ---
547
+ const { parent } = options;
548
+ if (!parent) {
549
+ console.error('Renderer: Parent element not provided.');
550
+ return;
551
+ }
552
+
553
+ _injectStyles(options);
554
+
555
+ if (!_ensurePokerTableElements(parent)) {
556
+ console.error('Renderer: Failed to ensure poker table elements.');
557
+ parent.innerHTML = '<p style="color:red;">Error: Could not create poker table structure.</p>';
558
+ return;
559
+ }
560
+
561
+ _renderPokerTableUI(options.steps[options.step ?? 0]);
562
+
563
+ // Apply initial scale
564
+ _applyScale(parent);
565
+
566
+ // Watch for container size changes and reapply scale
567
+ if (typeof ResizeObserver !== 'undefined') {
568
+ const resizeObserver = new ResizeObserver(() => {
569
+ _applyScale(parent);
570
+ });
571
+ resizeObserver.observe(parent);
572
+ }
573
+ }