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.
- kaggle_environments/envs/connectx/visualizer/default/index.html +13 -0
- kaggle_environments/envs/connectx/visualizer/default/package.json +22 -0
- kaggle_environments/envs/connectx/visualizer/default/replays/test-replay.json +1129 -0
- kaggle_environments/envs/connectx/visualizer/default/src/main.ts +12 -0
- kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +396 -0
- kaggle_environments/envs/connectx/visualizer/default/src/style.css +38 -0
- kaggle_environments/envs/connectx/visualizer/default/tsconfig.json +4 -0
- kaggle_environments/envs/connectx/visualizer/default/vite.config.ts +7 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js +163 -88
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/index.html +13 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +23 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json +1 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_first_steps.mjs +202 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_replay.mjs +215 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_steps_with_end_states.mjs +234 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +260 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.ts +61 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/debug_repeated_poker_renderer.ts +49 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_1.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_10.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_100.svg +48 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_25.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_5.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +36 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.ts +573 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/style.css +594 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json +7 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts +6 -0
- kaggle_environments/envs/werewolf/README.md +190 -0
- kaggle_environments/envs/werewolf/harness/__init__.py +0 -0
- kaggle_environments/envs/werewolf/harness/base.py +773 -0
- kaggle_environments/envs/werewolf/harness/litellm_models.yaml +51 -0
- kaggle_environments/envs/werewolf/harness/main.py +54 -0
- kaggle_environments/envs/werewolf/harness/test_base.py +35 -0
- kaggle_environments/envs/werewolf/runner.py +146 -0
- kaggle_environments/envs/werewolf/scripts/__init__.py +0 -0
- kaggle_environments/envs/werewolf/scripts/add_audio.py +425 -0
- kaggle_environments/envs/werewolf/scripts/configs/audio/standard.yaml +24 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/block_basic.yaml +102 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/comprehensive.yaml +100 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_DisableDoctorSelfSave_DisableDoctorConsecutiveSave_large.yaml +104 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_large.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_small.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_DisableDoctorConsecutiveSave.yaml +104 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationNoReveal_DayExileNoReveal.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationRevealTeam_DayExileRevealTeam.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_disable_doctor_self_save.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_no_tie_exile.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_roundbiddiscussion.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/run_config.yaml +58 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/vertex_api_example_config.yaml +115 -0
- kaggle_environments/envs/werewolf/scripts/measure_cost.py +251 -0
- kaggle_environments/envs/werewolf/scripts/plot_existing_trajectories.py +135 -0
- kaggle_environments/envs/werewolf/scripts/rerender_html.py +87 -0
- kaggle_environments/envs/werewolf/scripts/run.py +93 -0
- kaggle_environments/envs/werewolf/scripts/run_block.py +237 -0
- kaggle_environments/envs/werewolf/scripts/run_pairwise_matrix.py +222 -0
- kaggle_environments/envs/werewolf/scripts/self_play.py +196 -0
- kaggle_environments/envs/werewolf/scripts/utils.py +47 -0
- kaggle_environments/envs/werewolf/werewolf.json +1 -1
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/METADATA +1 -1
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/RECORD +68 -7
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/WHEEL +0 -0
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/entry_points.txt +0 -0
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,7 +12,7 @@ function renderer(options) {
|
|
|
12
12
|
playerInfoAreas: [],
|
|
13
13
|
dealerButton: null,
|
|
14
14
|
diagnosticHeader: null,
|
|
15
|
-
|
|
15
|
+
stepCounter: null,
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const css = `
|
|
@@ -43,7 +43,7 @@ function renderer(options) {
|
|
|
43
43
|
|
|
44
44
|
.poker-renderer-host {
|
|
45
45
|
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
|
|
46
|
-
font-family: 'Zeitung Pro', sans-serif; background-color: #
|
|
46
|
+
font-family: 'Zeitung Pro', sans-serif; background-color: #1C1D20; color: #fff;
|
|
47
47
|
overflow: hidden; padding: 1rem; box-sizing: border-box; position: relative;
|
|
48
48
|
}
|
|
49
49
|
.poker-game-layout { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; position: relative; max-width: 750px; max-height: 750px; }
|
|
@@ -135,10 +135,11 @@ function renderer(options) {
|
|
|
135
135
|
.pot-display { font-size: 40px; font-weight: bold; color: #ffffff; margin-bottom: 30px; }
|
|
136
136
|
.bet-display {
|
|
137
137
|
display: inline-block; padding: 10px 20px; border-radius: 12px;
|
|
138
|
-
background-color: #
|
|
138
|
+
background-color: #3C4043; color: #ffff;
|
|
139
139
|
font-family: 'Inter' sans-serif; font-size: 1.75rem; font-weigth: 600;
|
|
140
140
|
text-align: center;
|
|
141
141
|
height: 3rem; line-height: 3rem;
|
|
142
|
+
min-width: 200px;
|
|
142
143
|
}
|
|
143
144
|
.blind-indicator { font-size: 0.7rem; color: #a0aec0; margin-top: 3px; }
|
|
144
145
|
.dealer-button {
|
|
@@ -148,10 +149,16 @@ function renderer(options) {
|
|
|
148
149
|
}
|
|
149
150
|
.dealer-button.dealer-player0 { bottom: 110px; }
|
|
150
151
|
.dealer-button.dealer-player1 { top: 110px; }
|
|
151
|
-
|
|
152
|
+
.step-counter {
|
|
153
|
+
position: absolute; top: 12px; right: 12px; z-index: 20;
|
|
154
|
+
background-color: rgba(60, 64, 67, 0.9); color: #ffffff;
|
|
155
|
+
padding: 6px 12px; border-radius: 6px;
|
|
156
|
+
font-size: 14px; font-weight: 600;
|
|
157
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
158
|
+
}
|
|
152
159
|
|
|
153
160
|
@media (max-width: 768px) {
|
|
154
|
-
.bet-display { font-size: 1.5rem; height: 2.2rem; line-height: 2.2rem; }
|
|
161
|
+
.bet-display { font-size: 1.5rem; height: 2.2rem; line-height: 2.2rem; min-width: 0;}
|
|
155
162
|
.card { width: 60px; height: 85px; } .card-rank { font-size: 35px; } .card-suit { width: 35px; height: 35px; }
|
|
156
163
|
.community-cards-container { gap: 6px; }
|
|
157
164
|
.player-card-area { min-height: 120px; }
|
|
@@ -268,10 +275,6 @@ function renderer(options) {
|
|
|
268
275
|
elements.diagnosticHeader.style.cssText = "color: lime; background-color: black; padding: 5px; font-size: 12px; position: absolute; top: 0px; left: 0px; z-index: 10001; display: none;"; // Hidden by default
|
|
269
276
|
parentElement.appendChild(elements.diagnosticHeader);
|
|
270
277
|
|
|
271
|
-
elements.gameMessageArea = document.createElement('div');
|
|
272
|
-
elements.gameMessageArea.id = 'game-message-area';
|
|
273
|
-
parentElement.appendChild(elements.gameMessageArea);
|
|
274
|
-
|
|
275
278
|
elements.gameLayout = document.createElement('div');
|
|
276
279
|
elements.gameLayout.className = 'poker-game-layout';
|
|
277
280
|
parentElement.appendChild(elements.gameLayout);
|
|
@@ -352,20 +355,93 @@ function renderer(options) {
|
|
|
352
355
|
elements.dealerButton.textContent = 'D';
|
|
353
356
|
elements.dealerButton.style.display = 'none';
|
|
354
357
|
elements.playersContainer.appendChild(elements.dealerButton);
|
|
358
|
+
|
|
359
|
+
elements.stepCounter = document.createElement('div');
|
|
360
|
+
elements.stepCounter.className = 'step-counter';
|
|
361
|
+
elements.stepCounter.textContent = 'Standby';
|
|
362
|
+
elements.gameLayout.appendChild(elements.stepCounter);
|
|
355
363
|
return true;
|
|
356
364
|
}
|
|
357
365
|
|
|
358
|
-
function
|
|
366
|
+
function _getLastMovesACPC(bettingString, currentPlayer) {
|
|
367
|
+
// We will store all human-readable moves here
|
|
368
|
+
const allMoves = [];
|
|
369
|
+
|
|
370
|
+
// Split the action string by street (e.g., ["r5c", "cr11f"])
|
|
371
|
+
const streets = bettingString.split('/');
|
|
372
|
+
|
|
373
|
+
// Process each street's actions
|
|
374
|
+
for (let streetIndex = 0; streetIndex < streets.length; streetIndex++) {
|
|
375
|
+
const streetAction = streets[streetIndex];
|
|
376
|
+
let i = 0;
|
|
377
|
+
|
|
378
|
+
// Preflop (streetIndex 0), action is "open" due to blinds.
|
|
379
|
+
// Postflop (streetIndex > 0), action is "not open" (first player checks or bets).
|
|
380
|
+
let isAggressiveActionOpen = (streetIndex === 0);
|
|
381
|
+
|
|
382
|
+
// 4. Parse the moves within the street
|
|
383
|
+
while (i < streetAction.length) {
|
|
384
|
+
const char = streetAction[i];
|
|
385
|
+
let move = null;
|
|
386
|
+
|
|
387
|
+
if (char === 'c') {
|
|
388
|
+
// 'c' (call/check)
|
|
389
|
+
if (isAggressiveActionOpen) {
|
|
390
|
+
move = 'call';
|
|
391
|
+
} else {
|
|
392
|
+
move = 'check';
|
|
393
|
+
}
|
|
394
|
+
isAggressiveActionOpen = false; // 'c' never leaves action open
|
|
395
|
+
i++;
|
|
396
|
+
} else if (char === 'f') {
|
|
397
|
+
// 'f' (fold)
|
|
398
|
+
move = 'fold';
|
|
399
|
+
isAggressiveActionOpen = false; // 'f' ends the hand
|
|
400
|
+
i++;
|
|
401
|
+
} else if (char === 'r') {
|
|
402
|
+
// 'r' (raise/bet)
|
|
403
|
+
let amount = '';
|
|
404
|
+
i++;
|
|
405
|
+
// Continue to parse all digits of the raise amount
|
|
406
|
+
while (i < streetAction.length && streetAction[i] >= '0' && streetAction[i] <= '9') {
|
|
407
|
+
amount += streetAction[i];
|
|
408
|
+
i++;
|
|
409
|
+
}
|
|
410
|
+
move = `raise ${amount}`;
|
|
411
|
+
isAggressiveActionOpen = true; // 'r' always leaves action open
|
|
412
|
+
} else {
|
|
413
|
+
// Should not happen with valid input, but good to prevent infinite loops
|
|
414
|
+
i++;
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// 5. Store this move in the history
|
|
419
|
+
if (move) {
|
|
420
|
+
allMoves.push(move);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// 6. Get the last two moves from our complete list
|
|
426
|
+
const lastMove = allMoves.length > 0 ? allMoves[allMoves.length - 1] : null;
|
|
427
|
+
const secondLastMove = allMoves.length > 1 ? allMoves[allMoves.length - 2] : null;
|
|
428
|
+
|
|
429
|
+
const lastMoves = currentPlayer === 0 ? [secondLastMove, lastMove] : [lastMove, secondLastMove];
|
|
430
|
+
|
|
431
|
+
return lastMoves;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function _parseStepHistoryData(universalPokerJSON) {
|
|
359
435
|
const result = {
|
|
360
|
-
|
|
361
|
-
p1cards: '',
|
|
436
|
+
cards: [],
|
|
362
437
|
communityCards: '',
|
|
363
|
-
|
|
364
|
-
|
|
438
|
+
bets: [],
|
|
439
|
+
lastMoves: ['', ''],
|
|
440
|
+
winOdds: [0, 0],
|
|
365
441
|
};
|
|
366
442
|
|
|
367
443
|
// Split the string into its main lines
|
|
368
|
-
const lines =
|
|
444
|
+
const lines = universalPokerJSON.acpc_state.trim().split('\n');
|
|
369
445
|
if (lines.length < 2) {
|
|
370
446
|
console.error("Invalid state string format.");
|
|
371
447
|
return result;
|
|
@@ -374,10 +450,29 @@ function renderer(options) {
|
|
|
374
450
|
const stateLine = lines[0]; // example: "STATE:0:r5c/cr11c/:6cKd|AsJc/7hQh6d/2c"
|
|
375
451
|
const spentLine = lines[1]; // example: "Spent: [P0: 11 P1: 11 ]"
|
|
376
452
|
|
|
377
|
-
// ---
|
|
453
|
+
// --- Parse the Spent Line ---
|
|
454
|
+
if (spentLine) {
|
|
455
|
+
const p0BetMatch = spentLine.match(/P0:\s*(\d+)/);
|
|
456
|
+
const p1BetMatch = spentLine.match(/P1:\s*(\d+)/);
|
|
457
|
+
|
|
458
|
+
const bets = [0, 0];
|
|
459
|
+
|
|
460
|
+
if (p0BetMatch) {
|
|
461
|
+
bets[0] = parseInt(p0BetMatch[1], 10);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (p1BetMatch) {
|
|
465
|
+
bets[1] = parseInt(p1BetMatch[1], 10);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
result.bets = bets;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// --- Parse the State Line ---
|
|
378
472
|
if (stateLine) {
|
|
379
473
|
const stateParts = stateLine.split(':');
|
|
380
474
|
|
|
475
|
+
// --- Parse Cards ---
|
|
381
476
|
// The card string is always the last part
|
|
382
477
|
const cardString = stateParts[stateParts.length - 1]; // example: "6cKd|AsJc/7hQh6d/2c"
|
|
383
478
|
|
|
@@ -389,8 +484,7 @@ function renderer(options) {
|
|
|
389
484
|
const playerHands = cardSegments[0].split('|');
|
|
390
485
|
if (playerHands.length >= 2) {
|
|
391
486
|
// example: "6cKd"
|
|
392
|
-
result.
|
|
393
|
-
result.p1cards = playerHands[1];
|
|
487
|
+
result.cards = [playerHands[0], playerHands[1]];
|
|
394
488
|
}
|
|
395
489
|
}
|
|
396
490
|
|
|
@@ -399,22 +493,22 @@ function renderer(options) {
|
|
|
399
493
|
.slice(1) // gets all elements AFTER the player hands
|
|
400
494
|
.filter(Boolean) // removes any empty strings (e.g., from a trailing "/")
|
|
401
495
|
.join(''); // joins the remaining segments into a single string
|
|
402
|
-
}
|
|
403
496
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const
|
|
497
|
+
// --- Parse Betting String --
|
|
498
|
+
// The betting string is everything between the 2nd colon and the last colon.
|
|
499
|
+
// This handles edge cases like "STATE:0:r5c/cr11c/:cards"
|
|
500
|
+
const bettingString = stateParts.slice(2, stateParts.length - 1).join(':');
|
|
408
501
|
|
|
409
|
-
if (
|
|
410
|
-
result.
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (p1BetMatch) {
|
|
414
|
-
result.p1bet = parseInt(p1BetMatch[1], 10);
|
|
502
|
+
if (bettingString) {
|
|
503
|
+
result.lastMoves = _getLastMovesACPC(bettingString, universalPokerJSON.current_player);
|
|
415
504
|
}
|
|
416
505
|
}
|
|
417
506
|
|
|
507
|
+
// Parse win odds
|
|
508
|
+
p0WinOdds = Number(universalPokerJSON.odds[0]).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2 })
|
|
509
|
+
p1WinOdds = Number(universalPokerJSON.odds[1]).toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 2 })
|
|
510
|
+
result.winOdds = [p0WinOdds, p1WinOdds];
|
|
511
|
+
|
|
418
512
|
return result;
|
|
419
513
|
}
|
|
420
514
|
|
|
@@ -433,7 +527,7 @@ function renderer(options) {
|
|
|
433
527
|
const numPlayers = 2;
|
|
434
528
|
|
|
435
529
|
// --- Default State ---
|
|
436
|
-
const
|
|
530
|
+
const stateUIData = {
|
|
437
531
|
players: Array(numPlayers).fill(null).map((_, i) => {
|
|
438
532
|
const agentName = environment?.info?.TeamNames?.[i] ||
|
|
439
533
|
`Player ${i}`;
|
|
@@ -443,23 +537,24 @@ function renderer(options) {
|
|
|
443
537
|
stack: 0,
|
|
444
538
|
cards: [], // Will be filled with nulls or cards
|
|
445
539
|
currentBet: 0,
|
|
446
|
-
position: i === 0 ? "Small Blind" : "Big Blind",
|
|
447
540
|
isDealer: i === 0,
|
|
448
541
|
isTurn: false,
|
|
449
|
-
status: "Waiting...",
|
|
450
542
|
reward: null
|
|
451
543
|
};
|
|
452
544
|
}),
|
|
453
545
|
communityCards: [],
|
|
454
546
|
pot: 0,
|
|
455
547
|
isTerminal: false,
|
|
456
|
-
|
|
548
|
+
blinds: [1, 2],
|
|
549
|
+
lastMoves: [],
|
|
457
550
|
rawObservation: null, // For debugging
|
|
551
|
+
step: step,
|
|
458
552
|
};
|
|
459
553
|
|
|
460
554
|
// --- Step Validation ---
|
|
461
555
|
if (!environment || !environment.steps || !environment.steps[step] || !environment.info) {
|
|
462
|
-
return
|
|
556
|
+
// return default state
|
|
557
|
+
return stateUIData;
|
|
463
558
|
}
|
|
464
559
|
|
|
465
560
|
currentStateHistory = JSON.parse(environment.info.stateHistory[step]);
|
|
@@ -468,45 +563,44 @@ function renderer(options) {
|
|
|
468
563
|
// TODO: Handle the flop phase steps (chance steps)
|
|
469
564
|
|
|
470
565
|
currentUniversalPokerJSON = _getCurrentStepUniversalPokerJSON(options);
|
|
471
|
-
currentStepFromStateHistory =
|
|
566
|
+
currentStepFromStateHistory = _parseStepHistoryData(currentUniversalPokerJSON);
|
|
472
567
|
|
|
473
568
|
const currentStepAgents = environment.steps[step];
|
|
474
569
|
if (!currentStepAgents || currentStepAgents.length < numPlayers) {
|
|
475
|
-
|
|
476
|
-
return defaultUIData;
|
|
570
|
+
return stateUIData;
|
|
477
571
|
}
|
|
478
572
|
|
|
479
|
-
|
|
480
|
-
const
|
|
481
|
-
const player_contributions = [currentStepFromStateHistory.p0bet, currentStepFromStateHistory.p1bet];
|
|
573
|
+
const pot_size = currentStepFromStateHistory.bets.reduce((a, b) => a + b, 0);
|
|
574
|
+
const player_contributions = currentStepFromStateHistory.bets;
|
|
482
575
|
const starting_stacks = currentUniversalPokerJSON.starting_stacks;
|
|
483
576
|
const player_hands = [
|
|
484
|
-
currentStepFromStateHistory.
|
|
485
|
-
currentStepFromStateHistory.
|
|
577
|
+
currentStepFromStateHistory.cards[0]?.match(/.{1,2}/g) || [],
|
|
578
|
+
currentStepFromStateHistory.cards[1]?.match(/.{1,2}/g) || []
|
|
486
579
|
];
|
|
487
580
|
const board_cards = currentStepFromStateHistory.communityCards ? currentStepFromStateHistory.communityCards.match(/.{1,2}/g).reverse() : [];
|
|
488
|
-
const current_player = currentStepFromStateHistory.current_player;
|
|
489
|
-
const betting_history = currentStepFromStateHistory.betting_history;
|
|
490
581
|
|
|
491
582
|
// TODO: Add odds, best_five_card_hands best_hand_rank_types
|
|
492
583
|
|
|
493
|
-
|
|
494
|
-
defaultUIData.isTerminal = isTerminal;
|
|
495
|
-
defaultUIData.pot = pot_size || 0;
|
|
496
|
-
defaultUIData.communityCards = board_cards || [];
|
|
584
|
+
// TODO: Add current player
|
|
497
585
|
|
|
586
|
+
const isTerminal = false // TODO: read isTerminal from observation
|
|
587
|
+
stateUIData.isTerminal = isTerminal;
|
|
588
|
+
stateUIData.pot = pot_size || 0;
|
|
589
|
+
stateUIData.communityCards = board_cards || [];
|
|
590
|
+
stateUIData.lastMoves = currentStepFromStateHistory.lastMoves;
|
|
591
|
+
stateUIData.blinds = currentUniversalPokerState.blinds;
|
|
498
592
|
|
|
499
|
-
// --- Update
|
|
593
|
+
// --- Update Players ---
|
|
500
594
|
for (let i = 0; i < numPlayers; i++) {
|
|
501
|
-
const pData =
|
|
595
|
+
const pData = stateUIData.players[i];
|
|
502
596
|
const contribution = player_contributions ? player_contributions[i] : 0;
|
|
503
597
|
const startStack = starting_stacks ? starting_stacks[i] : 0;
|
|
504
598
|
|
|
505
599
|
pData.currentBet = contribution;
|
|
506
600
|
pData.stack = startStack - contribution;
|
|
507
601
|
pData.cards = (player_hands[i] || []).map(c => c === "??" ? null : c);
|
|
508
|
-
pData.isTurn =
|
|
509
|
-
pData.
|
|
602
|
+
pData.isTurn = currentUniversalPokerState.current_player === i;
|
|
603
|
+
pData.isDealer = currentUniversalPokerState.blinds[i] === 1; // infer dealer from small blind
|
|
510
604
|
|
|
511
605
|
if (isTerminal) {
|
|
512
606
|
const reward = environment.rewards ? environment.rewards[i] : null;
|
|
@@ -523,52 +617,24 @@ function renderer(options) {
|
|
|
523
617
|
}
|
|
524
618
|
}
|
|
525
619
|
|
|
526
|
-
|
|
527
|
-
if (!isTerminal && betting_history && betting_history.includes('f')) {
|
|
528
|
-
// A simple fold check: the player who didn't make the last action and isn't the current player might have folded.
|
|
529
|
-
// This is a simplification. A more robust parser would track the betting sequence.
|
|
530
|
-
const lastAction = betting_history.slice(-1);
|
|
531
|
-
if (lastAction === 'f') {
|
|
532
|
-
// Find who is NOT the current player
|
|
533
|
-
const nonCurrentPlayerIndex = current_player === '0' ? 1 : 0;
|
|
534
|
-
// If they are not all-in, they folded.
|
|
535
|
-
if (defaultUIData.players[nonCurrentPlayerIndex].status !== 'All-in') {
|
|
536
|
-
defaultUIData.players[nonCurrentPlayerIndex].status = "Folded";
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
// --- Set Game Message ---
|
|
543
|
-
if (isTerminal) {
|
|
544
|
-
const winnerIndex = environment.rewards ? environment.rewards.findIndex(r => r > 0) : -1;
|
|
545
|
-
if (winnerIndex !== -1) {
|
|
546
|
-
defaultUIData.gameMessage = `Player ${winnerIndex} wins!`;
|
|
547
|
-
} else {
|
|
548
|
-
defaultUIData.gameMessage = "Game Over.";
|
|
549
|
-
}
|
|
550
|
-
} else if (current_player === "chance") {
|
|
551
|
-
defaultUIData.gameMessage = `Dealing...`;
|
|
552
|
-
} else {
|
|
553
|
-
defaultUIData.gameMessage = `Player ${current_player}'s turn.`;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
return defaultUIData;
|
|
620
|
+
return stateUIData;
|
|
557
621
|
}
|
|
558
622
|
|
|
559
623
|
|
|
560
624
|
function _renderPokerTableUI(data, passedOptions) {
|
|
561
625
|
if (!elements.pokerTable || !data) return;
|
|
562
|
-
const { players, communityCards, pot, isTerminal,
|
|
626
|
+
const { players, communityCards, pot, isTerminal, step } = data;
|
|
627
|
+
|
|
628
|
+
// Update step counter
|
|
629
|
+
if (elements.stepCounter && step !== undefined) {
|
|
630
|
+
elements.stepCounter.textContent = `Step: ${step}`;
|
|
631
|
+
}
|
|
563
632
|
|
|
564
633
|
if (elements.diagnosticHeader && data.rawObservation) {
|
|
565
634
|
// Optional: Show diagnostics for debugging
|
|
566
635
|
// elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${data.rawObservation.current_player} POT:${data.pot}`;
|
|
567
636
|
// elements.diagnosticHeader.style.display = 'block';
|
|
568
637
|
}
|
|
569
|
-
if (elements.gameMessageArea) {
|
|
570
|
-
elements.gameMessageArea.textContent = gameMessage;
|
|
571
|
-
}
|
|
572
638
|
|
|
573
639
|
elements.communityCardsContainer.innerHTML = '';
|
|
574
640
|
// Always show 5 slots for the river
|
|
@@ -630,7 +696,16 @@ function renderer(options) {
|
|
|
630
696
|
|
|
631
697
|
const betDisplay = playerInfoArea.querySelector('.bet-display');
|
|
632
698
|
if (playerData.currentBet > 0) {
|
|
633
|
-
|
|
699
|
+
if (data.lastMoves[index]) {
|
|
700
|
+
betDisplay.textContent = data.lastMoves[index];
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
if (playerData.isDealer) {
|
|
704
|
+
betDisplay.textContent = 'Small Blind';
|
|
705
|
+
} else {
|
|
706
|
+
betDisplay.textContent = 'Big Blind';
|
|
707
|
+
}
|
|
708
|
+
}
|
|
634
709
|
betDisplay.style.display = 'block';
|
|
635
710
|
} else {
|
|
636
711
|
betDisplay.style.display = 'none';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Repeated Poker Visualizer</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kaggle-environments/repeated-poker-visualizer",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"dev-with-replay": "cross-env VITE_REPLAY_FILE=./replays/test-replay.json vite",
|
|
9
|
+
"build": "tsc && vite build",
|
|
10
|
+
"preview": "vite preview"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"cross-env": "^10.1.0",
|
|
14
|
+
"typescript": "^5.0.0",
|
|
15
|
+
"vite": "^5.0.0"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@kaggle-environments/core": "workspace:*",
|
|
19
|
+
"htm": "^3.1.1",
|
|
20
|
+
"json-formatter-js": "^2.5.23",
|
|
21
|
+
"preact": "^10.13.2"
|
|
22
|
+
}
|
|
23
|
+
}
|