kaggle-environments 1.23.5__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 (22) hide show
  1. kaggle_environments/envs/connectx/visualizer/default/src/main.ts +2 -1
  2. kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +16 -1
  3. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +1 -0
  4. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_first_steps.mjs +202 -0
  5. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_replay.mjs +215 -0
  6. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_steps_with_end_states.mjs +234 -0
  7. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +192 -173
  8. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.ts +61 -0
  9. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/debug_repeated_poker_renderer.ts +49 -0
  10. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +24 -25
  11. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.ts +573 -0
  12. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/style.css +594 -0
  13. kaggle_environments/envs/werewolf/harness/base.py +7 -1
  14. kaggle_environments/envs/werewolf/harness/main.py +54 -0
  15. kaggle_environments/envs/werewolf/werewolf.json +1 -1
  16. {kaggle_environments-1.23.5.dist-info → kaggle_environments-1.24.3.dist-info}/METADATA +1 -1
  17. {kaggle_environments-1.23.5.dist-info → kaggle_environments-1.24.3.dist-info}/RECORD +20 -14
  18. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.js +0 -19
  19. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.js +0 -724
  20. {kaggle_environments-1.23.5.dist-info → kaggle_environments-1.24.3.dist-info}/WHEEL +0 -0
  21. {kaggle_environments-1.23.5.dist-info → kaggle_environments-1.24.3.dist-info}/entry_points.txt +0 -0
  22. {kaggle_environments-1.23.5.dist-info → kaggle_environments-1.24.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,724 +0,0 @@
1
- import { getPokerStateForStep } from "./components/getRepeatedPokerStateForStep";
2
- import { acpcCardToDisplay, suitSVGs } from "./components/utils";
3
- import poker_chip_1 from "./images/poker_chip_1.svg";
4
- import poker_chip_5 from "./images/poker_chip_5.svg";
5
- import poker_chip_10 from "./images/poker_chip_10.svg";
6
- import poker_chip_25 from "./images/poker_chip_25.svg";
7
- import poker_chip_100 from "./images/poker_chip_100.svg";
8
-
9
- export function renderer(options) {
10
- const chipImages = {
11
- 1: poker_chip_1,
12
- 5: poker_chip_5,
13
- 10: poker_chip_10,
14
- 25: poker_chip_25,
15
- 100: poker_chip_100
16
- };
17
-
18
- const elements = {
19
- gameLayout: null,
20
- pokerTableContainer: null,
21
- pokerTable: null,
22
- communityCardsContainer: null,
23
- potDisplay: null,
24
- playersContainer: null,
25
- playerCardAreas: [],
26
- playerInfoAreas: [],
27
- playerThumbnails: [],
28
- dealerButton: null,
29
- chipStacks: [],
30
- diagnosticHeader: null,
31
- stepCounter: null
32
- };
33
-
34
- const css = `
35
- @font-face {
36
- font-family: 'Zeitung Pro';
37
- src:
38
- url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
39
- format("woff2"),
40
- url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
41
- format("woff"),
42
- url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
43
- format("opentype");
44
- font-weight: normal;
45
- font-style: normal;
46
- }
47
- @font-face {
48
- font-family: 'Zeitung Pro';
49
- src:
50
- url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
51
- format("woff2"),
52
- url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
53
- format("woff"),
54
- url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
55
- format("opentype");
56
- font-weight: bold;
57
- font-style: normal;
58
- }
59
-
60
- .poker-renderer-host {
61
- width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
62
- font-family: 'Zeitung Pro', sans-serif; background-color: #28303F; color: #fff;
63
- overflow: hidden; box-sizing: border-box; position: relative;
64
- }
65
- .poker-game-layout {
66
- width: 1000px;
67
- height: 900px;
68
- display: flex;
69
- align-items: center;
70
- justify-content: center;
71
- position: relative;
72
- transform-origin: center center;
73
- }
74
- .poker-table-container {
75
- width: 100%;
76
- height: 400px;
77
- display: flex;
78
- align-items: center;
79
- justify-content: center;
80
- }
81
- .poker-table {
82
- width: 900px;
83
- height: 400px;
84
- background: radial-gradient(43.33% 50% at 50% 50%, #20BD48 0%, #0A4018 99.99%);
85
- border-radius: 300px;
86
- position: relative;
87
- border: 20px solid #5C3A21;
88
- display: flex;
89
- align-items: center;
90
- justify-content: center;
91
- margin: 0;
92
- box-shadow: 0 8px 12px 6px rgba(0, 0, 0, 0.15), 0 4px 4px 0 rgba(0, 0, 0, 0.30);
93
- }
94
- .muck-line {
95
- position: absolute;
96
- width: 780px;
97
- height: 300px;
98
- border: 1px solid #9AA0A6;
99
- border-radius: 240px;
100
- pointer-events: none;
101
- z-index: 1;
102
- display: flex;
103
- align-items: center;
104
- justify-content: center;
105
- }
106
- .players-container {
107
- position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10;
108
- }
109
- .player-container {
110
- position: absolute;
111
- width: 100%;
112
- pointer-events: none;
113
- display: flex;
114
- flex-direction: column;
115
- }
116
- .player-container-0 { top: 0; }
117
- .player-container-1 { bottom: 0; flex-direction: column-reverse; }
118
- .player-card-area {
119
- color: white; text-align: center;
120
- display: flex; justify-content: left; align-items: left;
121
- pointer-events: auto;
122
- flex: 1;
123
- }
124
- .stack-cards-wrapper {
125
- display: flex;
126
- flex-direction: row;
127
- align-items: center;
128
- justify-content: center;
129
- gap: 16px;
130
- margin: 12px;
131
- width: 100%;
132
- }
133
- .player-info-area {
134
- color: white;
135
- width: auto;
136
- min-width: 200px;
137
- pointer-events: auto;
138
- display: flex;
139
- flex-direction: column;
140
- justify-content: center;
141
- align-items: center;
142
- margin: 20px auto;
143
- padding: 20px;
144
- background-color: rgba(32, 33, 36, 0.70);;
145
- border-radius: 16px;
146
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
147
- border: 2px solid transparent;
148
- transition: border-color 0.3s ease, box-shadow 0.3s ease;
149
- }
150
- .player-info-area.active-player {
151
- border-color: #20BEFF;
152
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 20px rgba(32, 190, 255, 0.5);
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
- }
158
- .player-container-0 .player-info-area { flex-direction: column-reverse; }
159
- .player-name-wrapper {
160
- display: flex;
161
- align-items: center;
162
- justify-content: center;
163
- gap: 16px;
164
- margin: 0 60px;
165
- padding: 10px 0;
166
- }
167
- .player-thumbnail {
168
- width: 48px;
169
- height: 48px;
170
- border-radius: 50%;
171
- object-fit: cover;
172
- background-color: #ffffff;
173
- flex-shrink: 0;
174
- padding: 6px;
175
- }
176
- .player-name {
177
- font-size: 24px; font-weight: 600;
178
- white-space: nowrap;
179
- overflow: hidden;
180
- text-overflow: ellipsis;
181
- color: white;
182
- text-align: center;
183
- }
184
- .player-name.winner { color: #FFEB70; }
185
- .player-name.current-turn { color: #20BEFF; }
186
- .player-stack { font-size: 20px; font-weight: 600; color: #ffffff; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; }
187
- .player-cards-container { min-height: 80px; display: flex; justify-content: center; align-items:center;}
188
- .card {
189
- display: flex; flex-direction: column; justify-content: space-between; align-items: center;
190
- width: 44px; height: 70px; border: 2px solid #202124; border-radius: 8px;
191
- background-color: white; color: black; font-weight: bold; text-align: center; overflow: hidden; position: relative;
192
- padding: 6px;
193
- box-shadow: 0 6px 10px 4px rgba(0, 0, 0, 0.15), 0 2px 3px 0 rgba(0, 0, 0, 0.30);
194
- }
195
- .card-rank { font-family: 'Inter' sans-serif; font-size: 32px; line-height: 1; display: block; align-self: flex-start; }
196
- .card-suit { width: 36px; height: 36px; display: block; margin-bottom: 2px; }
197
- .player-cards-container .card { width: 38px; height: 60px; border-radius: 6px; }
198
- .player-cards-container .card:nth-child(2) { transform: rotate(20deg); margin-top: 14px; margin-left: -6px; }
199
- .player-cards-container .card-rank { font-size: 26px; }
200
- .player-cards-container .card-suit { width: 28px; height: 28px; }
201
- .card-suit svg { width: 100%; height: 100%; }
202
- .card-red .card-rank { color: #B3261E; }
203
- .card-red .card-suit svg { fill: #B3261E; }
204
- .card-black .card-rank { color: #000000; }
205
- .card-black .card-suit svg { fill: #000000; }
206
- .card-blue .card-rank { color: #0B57D0; }
207
- .card-blue .card-suit svg { fill: #0B57D0; }
208
- .card-green .card-rank { color: #146C2E; }
209
- .card-green .card-suit svg { fill: #146C2E; }
210
- .card-back {
211
- background-color: #2b6cb0;
212
- background-image: linear-gradient(45deg, rgba(255,255,255,0.1) 25%, transparent 25%, transparent 75%, rgba(255,255,255,0.1) 75%, rgba(255,255,255,0.1)),
213
- linear-gradient(-45deg, rgba(255,255,255,0.1) 25%, transparent 25%, transparent 75%, rgba(255,255,255,0.1) 75%, rgba(255,255,255,0.1));
214
- background-size: 10px 10px; border: 2px solid #63b3ed;
215
- }
216
- .card-back .card-rank, .card-back .card-suit { display: none; }
217
- .card-empty {
218
- background-color: rgba(232, 234, 237, 0.1);
219
- border: 2px solid rgba(154, 160, 166, 0.5);
220
- box-shadow: none
221
- }
222
- .card-empty .card-rank, .card-empty .card-suit { display: none; }
223
- .community-cards-area { text-align: center; z-index: 10; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
224
- .community-cards-container { min-height: 75px; display: flex; justify-content: center; align-items:center; margin-bottom: 0.5rem; gap: 8px; }
225
- .pot-display { font-size: 30px; font-weight: bold; color: #ffffff; margin-bottom: 10px; }
226
- .bet-display {
227
- display: inline-block; padding: 10px 20px; border-radius: 30px;
228
- background-color: #ffffff; color: black;
229
- font-family: 'Inter' sans-serif; font-size: 20px; font-weight: 600;
230
- text-align: center;
231
- height: 20pxrem; line-height: 20px;
232
- width: 150px;
233
- height: 20px;
234
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
235
- }
236
- .blind-indicator { font-size: 0.7rem; color: #a0aec0; margin-top: 3px; }
237
- .dealer-button {
238
- width: 36px; height: 36px; background-color: #f0f0f0; color: #333; border-radius: 50%;
239
- text-align: center; font-weight: bold; font-size: 28px; position: absolute;
240
- padding-left: 1px;
241
- line-height: 33px;
242
- box-shadow: 0 1px 3px rgba(0,0,0,0.3); z-index: 15; pointer-events: auto;
243
- border: 2px solid black;
244
- outline: 2px solid #20BEFF;
245
- left: 320px
246
- }
247
- .dealer-button.dealer-player0 { top: 170px; }
248
- .dealer-button.dealer-player1 { bottom: 170px; }
249
- .step-counter {
250
- position: absolute; top: 12px; right: 12px; z-index: 20;
251
- background-color: rgba(60, 64, 67, 0.9); color: #ffffff;
252
- padding: 6px 12px; border-radius: 6px;
253
- font-size: 14px; font-weight: 600;
254
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
255
- }
256
- .chip-stack {
257
- position: absolute;
258
- display: flex;
259
- flex-direction: row;
260
- align-items: center;
261
- gap: 12px;
262
- z-index: 12;
263
- pointer-events: none;
264
- left: 50%;
265
- transform: translateX(-50%);
266
- }
267
- .chip-stack.chip-stack-player0 {
268
- top: 60px;
269
- }
270
- .chip-stack.chip-stack-player1 {
271
- bottom: 60px;
272
- }
273
- .chip-stack-chips {
274
- display: flex;
275
- flex-direction: row-reverse;
276
- align-items: flex-end;
277
- justify-content: center;
278
- gap: 8px;
279
- position: relative;
280
- }
281
- .chip-denomination-stack {
282
- display: flex;
283
- flex-direction: column-reverse;
284
- align-items: center;
285
- position: relative;
286
- }
287
- .chip {
288
- width: 40px;
289
- height: 40px;
290
- position: relative;
291
- margin-bottom: -34px;
292
- filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
293
- }
294
- .chip:first-child {
295
- margin-bottom: 0;
296
- }
297
- .chip img {
298
- width: 100%;
299
- height: 100%;
300
- display: block;
301
- }
302
- .chip-stack-label {
303
- color: #FFFFFF;
304
- font-size: 18px;
305
- font-weight: bold;
306
- white-space: nowrap;
307
- }
308
- `;
309
-
310
- function _injectStyles(passedOptions) {
311
- if (typeof document === 'undefined' || window.__poker_styles_injected) {
312
- return;
313
- }
314
- const style = document.createElement('style');
315
- style.textContent = css;
316
- const parentForStyles =
317
- passedOptions && passedOptions.parent ? passedOptions.parent.ownerDocument.head : document.head;
318
- if (parentForStyles && !parentForStyles.querySelector('style[data-poker-renderer-styles]')) {
319
- style.setAttribute('data-poker-renderer-styles', 'true');
320
- parentForStyles.appendChild(style);
321
- }
322
- window.__poker_styles_injected = true;
323
- }
324
-
325
- function createCardElement(cardStr, isHidden = false) {
326
- const cardDiv = document.createElement('div');
327
- cardDiv.classList.add('card');
328
- if (isHidden || !cardStr || cardStr === '?' || cardStr === '??') {
329
- cardDiv.classList.add('card-back');
330
- } else {
331
- const { rank, suit } = acpcCardToDisplay(cardStr);
332
- const rankSpan = document.createElement('span');
333
- rankSpan.classList.add('card-rank');
334
- rankSpan.textContent = rank;
335
- cardDiv.appendChild(rankSpan);
336
-
337
- const suitSpan = document.createElement('span');
338
- suitSpan.classList.add('card-suit');
339
-
340
- if (suitSVGs[suit]) {
341
- suitSpan.innerHTML = suitSVGs[suit];
342
- }
343
-
344
- cardDiv.appendChild(suitSpan);
345
-
346
- if (suit === 'hearts') cardDiv.classList.add('card-red');
347
- else if (suit === 'spades') cardDiv.classList.add('card-black');
348
- else if (suit === 'diamonds') cardDiv.classList.add('card-blue');
349
- else if (suit === 'clubs') cardDiv.classList.add('card-green');
350
- }
351
- return cardDiv;
352
- }
353
-
354
- function updateChipStack(chipStackElement, betAmount) {
355
- if (betAmount <= 0) {
356
- chipStackElement.style.display = 'none';
357
- return;
358
- }
359
-
360
- chipStackElement.style.display = 'flex';
361
- const chipsContainer = chipStackElement.querySelector('.chip-stack-chips');
362
- const labelElement = chipStackElement.querySelector('.chip-stack-label');
363
-
364
- chipsContainer.innerHTML = '';
365
- labelElement.textContent = betAmount;
366
-
367
- // Break down bet into denominations (100, 25, 10, 5, 1)
368
- const denominations = [100, 25, 10, 5, 1];
369
- let remaining = betAmount;
370
- const chipCounts = [];
371
-
372
- for (const denom of denominations) {
373
- const count = Math.floor(remaining / denom);
374
- if (count > 0) {
375
- chipCounts.push({ denom, count: Math.min(count, 5) }); // Max 5 of each denomination
376
- remaining -= count * denom;
377
- }
378
- }
379
-
380
- // Render chips separated by denomination (highest to lowest, left to right)
381
- chipCounts.forEach(({ denom, count }) => {
382
- const denomStack = document.createElement('div');
383
- denomStack.className = 'chip-denomination-stack';
384
-
385
- for (let i = 0; i < count; i++) {
386
- const chip = document.createElement('div');
387
- chip.className = 'chip';
388
- const img = document.createElement('img');
389
- img.src = chipImages[denom];
390
- img.alt = `${denom} chip`;
391
- chip.appendChild(img);
392
- denomStack.appendChild(chip);
393
- }
394
-
395
- chipsContainer.appendChild(denomStack);
396
- });
397
- }
398
-
399
- // --- Board Parsing and Rendering ---
400
- function _ensurePokerTableElements(parentElement, passedOptions) {
401
- if (!parentElement) return false;
402
- parentElement.innerHTML = '';
403
- parentElement.classList.add('poker-renderer-host');
404
-
405
- elements.diagnosticHeader = document.createElement('h1');
406
- elements.diagnosticHeader.id = 'poker-renderer-diagnostic-header';
407
- elements.diagnosticHeader.textContent = 'Poker Table Initialized (Live Data)';
408
- elements.diagnosticHeader.style.cssText =
409
- 'color: lime; background-color: black; padding: 5px; font-size: 12px; position: absolute; top: 0px; left: 0px; z-index: 10001; display: none;'; // Hidden by default
410
- parentElement.appendChild(elements.diagnosticHeader);
411
-
412
- elements.gameLayout = document.createElement('div');
413
- elements.gameLayout.className = 'poker-game-layout';
414
- parentElement.appendChild(elements.gameLayout);
415
-
416
- elements.pokerTableContainer = document.createElement('div');
417
- elements.pokerTableContainer.className = 'poker-table-container';
418
- elements.gameLayout.appendChild(elements.pokerTableContainer);
419
-
420
- elements.playersContainer = document.createElement('div');
421
- elements.playersContainer.className = 'players-container';
422
- elements.gameLayout.appendChild(elements.playersContainer);
423
-
424
- elements.pokerTable = document.createElement('div');
425
- elements.pokerTable.className = 'poker-table';
426
- elements.pokerTableContainer.appendChild(elements.pokerTable);
427
-
428
- const muckLine = document.createElement('div');
429
- muckLine.className = 'muck-line';
430
- elements.pokerTable.appendChild(muckLine);
431
-
432
- // Create chip stacks for each player inside the table
433
- elements.chipStacks = [];
434
- for (let i = 0; i < 2; i++) {
435
- const chipStack = document.createElement('div');
436
- chipStack.className = `chip-stack chip-stack-player${i}`;
437
- chipStack.style.display = 'none';
438
- chipStack.innerHTML = `
439
- <div class="chip-stack-chips"></div>
440
- <div class="chip-stack-label">0</div>
441
- `;
442
- elements.pokerTable.appendChild(chipStack);
443
- elements.chipStacks.push(chipStack);
444
- }
445
-
446
- const communityArea = document.createElement('div');
447
- communityArea.className = 'community-cards-area';
448
- elements.pokerTable.appendChild(communityArea);
449
-
450
- elements.potDisplay = document.createElement('div');
451
- elements.potDisplay.className = 'pot-display';
452
- communityArea.appendChild(elements.potDisplay);
453
-
454
- elements.communityCardsContainer = document.createElement('div');
455
- elements.communityCardsContainer.className = 'community-cards-container';
456
- communityArea.appendChild(elements.communityCardsContainer);
457
-
458
- elements.playerContainers = [];
459
- elements.playerCardAreas = [];
460
- elements.playerInfoAreas = [];
461
- elements.playerNames = [];
462
- elements.playerThumbnails = [];
463
-
464
- for (let i = 0; i < 2; i++) {
465
- // Create player container that groups all player elements
466
- const playerContainer = document.createElement('div');
467
- playerContainer.className = `player-container player-container-${i}`;
468
- elements.playersContainer.appendChild(playerContainer);
469
- elements.playerContainers.push(playerContainer);
470
-
471
- // Player name wrapper with thumbnail
472
- const playerNameWrapper = document.createElement('div');
473
- playerNameWrapper.className = `player-name-wrapper`;
474
- playerContainer.appendChild(playerNameWrapper);
475
-
476
- // Player thumbnail
477
- const playerThumbnail = document.createElement('img');
478
- playerThumbnail.className = `player-thumbnail`;
479
- playerThumbnail.style.display = 'none'; // Hidden by default
480
- playerNameWrapper.appendChild(playerThumbnail);
481
- elements.playerThumbnails.push(playerThumbnail);
482
-
483
- // Player name
484
- const playerName = document.createElement('div');
485
- playerName.className = `player-name`;
486
- playerName.textContent = `Player ${i}`;
487
- playerNameWrapper.appendChild(playerName);
488
- elements.playerNames.push(playerName);
489
-
490
- // Info area containing bet, cards, and stack
491
- const playerInfoArea = document.createElement('div');
492
- playerInfoArea.className = `player-info-area`;
493
- playerInfoArea.innerHTML = `
494
- <div class="bet-display">Standby</div>
495
- <div class="stack-cards-wrapper">
496
- <div class="player-card-area">
497
- <div class="player-cards-container"></div>
498
- </div>
499
- <div class="player-stack">
500
- <span class="player-stack-value">0</span>
501
- </div>
502
- </div>
503
- `;
504
- playerContainer.appendChild(playerInfoArea);
505
- elements.playerInfoAreas.push(playerInfoArea);
506
-
507
- // Get reference to card area (already in DOM)
508
- const playerCardArea = playerInfoArea.querySelector('.player-card-area');
509
- elements.playerCardAreas.push(playerCardArea);
510
- }
511
-
512
- elements.dealerButton = document.createElement('div');
513
- elements.dealerButton.className = 'dealer-button';
514
- elements.dealerButton.textContent = 'D';
515
- elements.dealerButton.style.display = 'none';
516
- elements.playersContainer.appendChild(elements.dealerButton);
517
-
518
- elements.stepCounter = document.createElement('div');
519
- elements.stepCounter.className = 'step-counter';
520
- elements.stepCounter.textContent = 'Standby';
521
- elements.gameLayout.appendChild(elements.stepCounter);
522
- return true;
523
- }
524
-
525
- // --- State Parsing ---
526
- function _parseKagglePokerState(options) {
527
- const { environment, step } = options;
528
- const numPlayers = 2;
529
-
530
- // --- Default State ---
531
- const defaultStateUiData = {
532
- players: [],
533
- communityCards: [],
534
- pot: 0,
535
- isTerminal: false,
536
- };
537
-
538
- // --- Step Validation ---
539
- if (!environment || !environment.steps || !environment.steps[step] || !environment.info?.stateHistory) {
540
- return defaultStateUiData;
541
- }
542
-
543
- return getPokerStateForStep(environment, step);
544
- }
545
-
546
- function _applyScale(parentElement) {
547
- if (!parentElement || !elements.gameLayout) return;
548
-
549
- const parentWidth = parentElement.clientWidth;
550
- const parentHeight = parentElement.clientHeight;
551
-
552
- const baseWidth = 1000;
553
- const baseHeight = 1000;
554
-
555
- const scaleX = parentWidth / baseWidth;
556
- const scaleY = parentHeight / baseHeight;
557
- const scale = Math.min(scaleX, scaleY);
558
-
559
- elements.gameLayout.style.transform = `scale(${scale})`;
560
- }
561
-
562
- function _renderPokerTableUI(data, passedOptions) {
563
- if (!elements.pokerTable || !data) return;
564
- const { players, communityCards, pot, isTerminal, step } = data;
565
-
566
- // Update step counter
567
- if (elements.stepCounter && step !== undefined) {
568
- elements.stepCounter.textContent = `Debug Step: ${step}`;
569
- }
570
-
571
- if (elements.diagnosticHeader && data.rawObservation) {
572
- // Optional: Show diagnostics for debugging
573
- // elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${data.rawObservation.current_player} POT:${data.pot}`;
574
- // elements.diagnosticHeader.style.display = 'block';
575
- }
576
-
577
- elements.communityCardsContainer.innerHTML = '';
578
- // Always show 5 slots for the river
579
- // Display cards left to right, with empty slots at the end
580
- const numCommunityCards = 5;
581
- const numCards = communityCards ? communityCards.length : 0;
582
-
583
- // Since the 4th and 5th street cards are appended to the communityCards array, we need to
584
- // reverse it so that the added cards are put at the end of the display area on the board.
585
- if (communityCards) communityCards.reverse();
586
-
587
- // Add actual cards
588
- for (let i = 0; i < numCards; i++) {
589
- elements.communityCardsContainer.appendChild(createCardElement(communityCards[i]));
590
- }
591
-
592
- // Fill remaining slots with empty cards
593
- for (let i = numCards; i < numCommunityCards; i++) {
594
- const emptyCard = document.createElement('div');
595
- emptyCard.classList.add('card', 'card-empty');
596
- elements.communityCardsContainer.appendChild(emptyCard);
597
- }
598
-
599
- elements.potDisplay.textContent = `Total Pot : ${pot}`;
600
-
601
- players.forEach((playerData, index) => {
602
- const playerNameElement = elements.playerNames[index];
603
- if (playerNameElement) {
604
- playerNameElement.textContent = playerData.name;
605
-
606
- // Highlight current player's turn
607
- if (playerData.isTurn && !isTerminal) {
608
- playerNameElement.classList.add('current-turn');
609
- } else {
610
- playerNameElement.classList.remove('current-turn');
611
- }
612
-
613
- // Add winner class if player won
614
- if (playerData.isWinner) {
615
- playerNameElement.classList.add('winner');
616
- } else {
617
- playerNameElement.classList.remove('winner');
618
- }
619
- }
620
-
621
- // Update thumbnail
622
- const playerThumbnailElement = elements.playerThumbnails[index];
623
- if (playerThumbnailElement && playerData.thumbnail) {
624
- playerThumbnailElement.src = playerData.thumbnail;
625
- playerThumbnailElement.style.display = 'block';
626
- } else if (playerThumbnailElement) {
627
- playerThumbnailElement.style.display = 'none';
628
- }
629
-
630
- // Update card area (left side)
631
- const playerCardArea = elements.playerCardAreas[index];
632
- if (playerCardArea) {
633
- const playerCardsContainer = playerCardArea.querySelector('.player-cards-container');
634
- playerCardsContainer.innerHTML = '';
635
-
636
- // In heads-up, we show both hands at the end.
637
- const showCards = isTerminal || (playerData.cards && !playerData.cards.includes(null));
638
-
639
- (playerData.cards || [null, null]).forEach((cardStr) => {
640
- playerCardsContainer.appendChild(createCardElement(cardStr, !showCards && cardStr !== null));
641
- });
642
- }
643
-
644
- // Update chip stacks on the table
645
- if (elements.chipStacks[index]) {
646
- updateChipStack(elements.chipStacks[index], playerData.currentBet);
647
- }
648
-
649
- // Update info area (right side)
650
- const playerInfoArea = elements.playerInfoAreas[index];
651
- if (playerInfoArea) {
652
- // Highlight active player's pod
653
- if (playerData.isTurn && !isTerminal) {
654
- playerInfoArea.classList.add('active-player');
655
- } else {
656
- playerInfoArea.classList.remove('active-player');
657
- }
658
-
659
- // Highlight winner's pod
660
- if (playerData.isWinner) {
661
- playerInfoArea.classList.add('winner-player');
662
- } else {
663
- playerInfoArea.classList.remove('winner-player');
664
- }
665
-
666
- playerInfoArea.querySelector('.player-stack-value').textContent = `${playerData.stack}`;
667
-
668
- const betDisplay = playerInfoArea.querySelector('.bet-display');
669
- if (playerData.currentBet > 0) {
670
- if (playerData.actionDisplayText) {
671
- betDisplay.textContent = playerData.actionDisplayText;
672
- } else {
673
- betDisplay.textContent = '';
674
- }
675
- betDisplay.style.display = 'block';
676
- } else {
677
- betDisplay.style.display = 'none';
678
- }
679
- }
680
- });
681
-
682
- const dealerPlayerIndex = players.findIndex((p) => p.isDealer);
683
- if (elements.dealerButton) {
684
- if (dealerPlayerIndex !== -1) {
685
- elements.dealerButton.style.display = 'block';
686
- // Remove previous dealer class
687
- elements.dealerButton.classList.remove('dealer-player0', 'dealer-player1');
688
- // Add new dealer class based on player index
689
- elements.dealerButton.classList.add(`dealer-player${dealerPlayerIndex}`);
690
- } else {
691
- elements.dealerButton.style.display = 'none';
692
- }
693
- }
694
- }
695
-
696
- // --- MAIN EXECUTION LOGIC ---
697
- const { parent } = options;
698
- if (!parent) {
699
- console.error('Renderer: Parent element not provided.');
700
- return;
701
- }
702
-
703
- _injectStyles(options);
704
-
705
- if (!_ensurePokerTableElements(parent, options)) {
706
- console.error('Renderer: Failed to ensure poker table elements.');
707
- parent.innerHTML = '<p style="color:red;">Error: Could not create poker table structure.</p>';
708
- return;
709
- }
710
-
711
- const uiData = _parseKagglePokerState(options);
712
- _renderPokerTableUI(uiData, options);
713
-
714
- // Apply initial scale
715
- _applyScale(parent);
716
-
717
- // Watch for container size changes and reapply scale
718
- if (typeof ResizeObserver !== 'undefined') {
719
- const resizeObserver = new ResizeObserver(() => {
720
- _applyScale(parent);
721
- });
722
- resizeObserver.observe(parent);
723
- }
724
- }