kaggle-environments 0.2.1__py3-none-any.whl → 1.20.1__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/__init__.py +49 -13
- kaggle_environments/agent.py +177 -124
- kaggle_environments/api.py +31 -0
- kaggle_environments/core.py +295 -170
- kaggle_environments/envs/cabt/cabt.js +164 -0
- kaggle_environments/envs/cabt/cabt.json +28 -0
- kaggle_environments/envs/cabt/cabt.py +186 -0
- kaggle_environments/envs/cabt/cg/__init__.py +0 -0
- kaggle_environments/envs/cabt/cg/cg.dll +0 -0
- kaggle_environments/envs/cabt/cg/game.py +75 -0
- kaggle_environments/envs/cabt/cg/libcg.so +0 -0
- kaggle_environments/envs/cabt/cg/sim.py +48 -0
- kaggle_environments/envs/cabt/test_cabt.py +120 -0
- kaggle_environments/envs/chess/chess.js +4289 -0
- kaggle_environments/envs/chess/chess.json +60 -0
- kaggle_environments/envs/chess/chess.py +4241 -0
- kaggle_environments/envs/chess/test_chess.py +60 -0
- kaggle_environments/envs/connectx/connectx.ipynb +3186 -0
- kaggle_environments/envs/connectx/connectx.js +1 -1
- kaggle_environments/envs/connectx/connectx.json +15 -1
- kaggle_environments/envs/connectx/connectx.py +6 -23
- kaggle_environments/envs/connectx/test_connectx.py +70 -24
- kaggle_environments/envs/football/football.ipynb +75 -0
- kaggle_environments/envs/football/football.json +91 -0
- kaggle_environments/envs/football/football.py +277 -0
- kaggle_environments/envs/football/helpers.py +95 -0
- kaggle_environments/envs/football/test_football.py +360 -0
- kaggle_environments/envs/halite/__init__.py +0 -0
- kaggle_environments/envs/halite/halite.ipynb +44741 -0
- kaggle_environments/envs/halite/halite.js +199 -83
- kaggle_environments/envs/halite/halite.json +31 -18
- kaggle_environments/envs/halite/halite.py +164 -303
- kaggle_environments/envs/halite/helpers.py +720 -0
- kaggle_environments/envs/halite/test_halite.py +190 -0
- kaggle_environments/envs/hungry_geese/__init__.py +0 -0
- kaggle_environments/envs/{battlegeese/battlegeese.js → hungry_geese/hungry_geese.js} +38 -22
- kaggle_environments/envs/{battlegeese/battlegeese.json → hungry_geese/hungry_geese.json} +21 -14
- kaggle_environments/envs/hungry_geese/hungry_geese.py +316 -0
- kaggle_environments/envs/hungry_geese/test_hungry_geese.py +0 -0
- kaggle_environments/envs/identity/identity.json +6 -5
- kaggle_environments/envs/identity/identity.py +15 -2
- kaggle_environments/envs/kore_fleets/__init__.py +0 -0
- kaggle_environments/envs/kore_fleets/helpers.py +1005 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.ipynb +114 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.js +658 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.json +164 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.py +555 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/Bot.java +54 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/README.md +26 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/jars/hamcrest-core-1.3.jar +0 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/jars/junit-4.13.2.jar +0 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Board.java +518 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Cell.java +61 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Configuration.java +24 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Direction.java +166 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Fleet.java +72 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/KoreJson.java +97 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Observation.java +72 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Pair.java +13 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Player.java +68 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Point.java +65 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Shipyard.java +70 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/ShipyardAction.java +59 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/main.py +73 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/BoardTest.java +567 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/ConfigurationTest.java +25 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/KoreJsonTest.java +62 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/ObservationTest.java +46 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/PointTest.java +21 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/ShipyardTest.java +22 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/configuration.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/fullob.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/observation.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/python/__init__.py +0 -0
- kaggle_environments/envs/kore_fleets/starter_bots/python/main.py +27 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/Bot.ts +34 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/DoNothingBot.ts +12 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/MinerBot.ts +62 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/README.md +55 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/interpreter.ts +402 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Board.ts +514 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Cell.ts +63 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Configuration.ts +25 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Direction.ts +169 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Fleet.ts +76 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/KoreIO.ts +70 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Observation.ts +45 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Pair.ts +11 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Player.ts +68 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Point.ts +65 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Shipyard.ts +72 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/ShipyardAction.ts +58 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/main.py +73 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/miner.py +73 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/package.json +23 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/BoardTest.ts +551 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ConfigurationTest.ts +16 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ObservationTest.ts +33 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/PointTest.ts +17 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ShipyardTest.ts +18 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/configuration.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/fullob.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/observation.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/tsconfig.json +22 -0
- kaggle_environments/envs/kore_fleets/test_kore_fleets.py +331 -0
- kaggle_environments/envs/lux_ai_2021/README.md +3 -0
- kaggle_environments/envs/lux_ai_2021/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_2021/agents.py +11 -0
- kaggle_environments/envs/lux_ai_2021/dimensions/754.js +2 -0
- kaggle_environments/envs/lux_ai_2021/dimensions/754.js.LICENSE.txt +296 -0
- kaggle_environments/envs/lux_ai_2021/dimensions/main.js +1 -0
- kaggle_environments/envs/lux_ai_2021/index.html +43 -0
- kaggle_environments/envs/lux_ai_2021/lux_ai_2021.json +100 -0
- kaggle_environments/envs/lux_ai_2021/lux_ai_2021.py +231 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.js +6 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.json +59 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_objects.js +145 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/io.js +14 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/kit.js +209 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/map.js +107 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/parser.js +79 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.js +88 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.py +75 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/simple.tar.gz +0 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/annotate.py +20 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/constants.py +25 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game.py +86 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.json +59 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.py +7 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_map.py +106 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_objects.py +154 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/random_agent.py +38 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/simple_agent.py +82 -0
- kaggle_environments/envs/lux_ai_2021/test_lux.py +19 -0
- kaggle_environments/envs/lux_ai_2021/testing.md +23 -0
- kaggle_environments/envs/lux_ai_2021/todo.md.og +18 -0
- kaggle_environments/envs/lux_ai_s3/README.md +21 -0
- kaggle_environments/envs/lux_ai_s3/agents.py +5 -0
- kaggle_environments/envs/lux_ai_s3/index.html +42 -0
- kaggle_environments/envs/lux_ai_s3/lux_ai_s3.json +47 -0
- kaggle_environments/envs/lux_ai_s3/lux_ai_s3.py +178 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/__init__.py +1 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/env.py +819 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/globals.py +9 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/params.py +101 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/profiler.py +141 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/pygame_render.py +222 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/spaces.py +27 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/state.py +464 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/utils.py +12 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/wrappers.py +156 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/agent.py +78 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/kit.py +31 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/utils.py +17 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/main.py +66 -0
- kaggle_environments/envs/lux_ai_s3/test_lux.py +9 -0
- kaggle_environments/envs/mab/__init__.py +0 -0
- kaggle_environments/envs/mab/agents.py +12 -0
- kaggle_environments/envs/mab/mab.js +100 -0
- kaggle_environments/envs/mab/mab.json +74 -0
- kaggle_environments/envs/mab/mab.py +146 -0
- kaggle_environments/envs/open_spiel/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/chess/chess.js +441 -0
- kaggle_environments/envs/open_spiel/games/chess/image_config.jsonl +20 -0
- kaggle_environments/envs/open_spiel/games/chess/openings.jsonl +20 -0
- kaggle_environments/envs/open_spiel/games/connect_four/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/connect_four/connect_four.js +284 -0
- kaggle_environments/envs/open_spiel/games/connect_four/connect_four_proxy.py +86 -0
- kaggle_environments/envs/open_spiel/games/go/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/go/go.js +481 -0
- kaggle_environments/envs/open_spiel/games/go/go_proxy.py +99 -0
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe.js +345 -0
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe_proxy.py +98 -0
- kaggle_environments/envs/open_spiel/games/universal_poker/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker.js +431 -0
- kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker_proxy.py +159 -0
- kaggle_environments/envs/open_spiel/html_playthrough_generator.py +31 -0
- kaggle_environments/envs/open_spiel/observation.py +128 -0
- kaggle_environments/envs/open_spiel/open_spiel.py +565 -0
- kaggle_environments/envs/open_spiel/proxy.py +138 -0
- kaggle_environments/envs/open_spiel/test_open_spiel.py +191 -0
- kaggle_environments/envs/rps/__init__.py +0 -0
- kaggle_environments/envs/rps/agents.py +84 -0
- kaggle_environments/envs/rps/helpers.py +25 -0
- kaggle_environments/envs/rps/rps.js +117 -0
- kaggle_environments/envs/rps/rps.json +63 -0
- kaggle_environments/envs/rps/rps.py +90 -0
- kaggle_environments/envs/rps/test_rps.py +110 -0
- kaggle_environments/envs/rps/utils.py +7 -0
- kaggle_environments/envs/tictactoe/test_tictactoe.py +43 -77
- kaggle_environments/envs/tictactoe/tictactoe.ipynb +1397 -0
- kaggle_environments/envs/tictactoe/tictactoe.json +10 -2
- kaggle_environments/envs/tictactoe/tictactoe.py +1 -1
- kaggle_environments/errors.py +2 -4
- kaggle_environments/helpers.py +377 -0
- kaggle_environments/main.py +340 -0
- kaggle_environments/schemas.json +23 -18
- kaggle_environments/static/player.html +206 -74
- kaggle_environments/utils.py +46 -73
- {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.1.dist-info}/METADATA +36 -114
- kaggle_environments-1.20.1.dist-info/RECORD +211 -0
- {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.1.dist-info}/WHEEL +1 -2
- kaggle_environments-1.20.1.dist-info/entry_points.txt +3 -0
- kaggle_environments/envs/battlegeese/battlegeese.py +0 -223
- kaggle_environments/temp.py +0 -14
- kaggle_environments-0.2.1.dist-info/RECORD +0 -32
- kaggle_environments-0.2.1.dist-info/entry_points.txt +0 -3
- kaggle_environments-0.2.1.dist-info/top_level.txt +0 -1
- {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
function renderer(options) {
|
|
2
|
+
// --- Existing Elements and Style Injection (Unchanged) ---
|
|
3
|
+
const elements = {
|
|
4
|
+
pokerTableContainer: null,
|
|
5
|
+
pokerTable: null,
|
|
6
|
+
communityCardsContainer: null,
|
|
7
|
+
potDisplay: null,
|
|
8
|
+
playerPods: [],
|
|
9
|
+
dealerButton: null,
|
|
10
|
+
diagnosticHeader: null,
|
|
11
|
+
gameMessageArea: null,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function _injectStyles(passedOptions) {
|
|
15
|
+
if (typeof document === 'undefined' || window.__poker_styles_injected) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const style = document.createElement('style');
|
|
19
|
+
style.textContent = `
|
|
20
|
+
.poker-renderer-host {
|
|
21
|
+
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
|
|
22
|
+
font-family: 'Inter', sans-serif; background-color: #2d3748; color: #fff;
|
|
23
|
+
overflow: hidden; padding: 1rem; box-sizing: border-box;
|
|
24
|
+
}
|
|
25
|
+
.poker-table-container { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
|
|
26
|
+
.poker-table {
|
|
27
|
+
width: clamp(400px, 85vw, 850px); height: clamp(220px, 48vw, 450px);
|
|
28
|
+
background-color: #006400; border-radius: 225px; position: relative;
|
|
29
|
+
border: 12px solid #5c3a21; box-shadow: 0 0 25px rgba(0,0,0,0.6);
|
|
30
|
+
display: flex; align-items: center; justify-content: center;
|
|
31
|
+
}
|
|
32
|
+
.player-pod {
|
|
33
|
+
background-color: rgba(0, 0, 0, 0.75); border: 1px solid #4a5568; border-radius: 0.75rem;
|
|
34
|
+
padding: 0.6rem 0.8rem; color: white; text-align: center; position: absolute;
|
|
35
|
+
min-width: 120px; max-width: 160px; box-shadow: 0 3px 12px rgba(0,0,0,0.35);
|
|
36
|
+
transform: translateX(-50%); display: flex; flex-direction: column; justify-content: space-between;
|
|
37
|
+
min-height: 130px;
|
|
38
|
+
}
|
|
39
|
+
.player-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; margin-bottom: 0.25rem; font-size: 0.9rem;}
|
|
40
|
+
.player-stack { font-size: 0.8rem; color: #facc15; margin-bottom: 0.25rem; }
|
|
41
|
+
.player-cards-container { margin: 0.25rem 0; min-height: 70px; display: flex; justify-content: center; align-items:center;}
|
|
42
|
+
.player-status { font-size: 0.75rem; color: #9ca3af; min-height: 1.1em; margin-top: 0.25rem; }
|
|
43
|
+
.card {
|
|
44
|
+
display: inline-flex; flex-direction: column; justify-content: center; align-items: center;
|
|
45
|
+
width: 48px; height: 68px; border: 1px solid #999; border-radius: 0.375rem; margin: 0 3px;
|
|
46
|
+
background-color: white; color: black; font-weight: bold; text-align: center; overflow: hidden; position: relative;
|
|
47
|
+
}
|
|
48
|
+
.card-rank { font-size: 1.8rem; line-height: 1; display: block; margin-top: 2px; }
|
|
49
|
+
.card-suit { font-size: 1.5rem; line-height: 1; display: block; }
|
|
50
|
+
.card-red .card-suit { color: #c0392b; } .card-black .card-suit { color: #1a202c; }
|
|
51
|
+
.card-back {
|
|
52
|
+
background-color: #2b6cb0;
|
|
53
|
+
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)),
|
|
54
|
+
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));
|
|
55
|
+
background-size: 10px 10px; border: 2px solid #63b3ed;
|
|
56
|
+
}
|
|
57
|
+
.card-back .card-rank, .card-back .card-suit { display: none; }
|
|
58
|
+
.community-cards-area { text-align: center; z-index: 10; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
|
|
59
|
+
.community-cards-container { min-height: 75px; display: flex; justify-content: center; align-items:center; margin-bottom: 0.5rem; }
|
|
60
|
+
.community-cards-container .card { width: 52px; height: 72px; }
|
|
61
|
+
.community-cards-container .card-rank { font-size: 2rem; } .community-cards-container .card-suit { font-size: 1.7rem; }
|
|
62
|
+
.pot-display { font-size: 1.1rem; font-weight: bold; color: #facc15; }
|
|
63
|
+
.bet-display {
|
|
64
|
+
display: inline-block; min-width: 55px; padding: 4px 8px; border-radius: 12px;
|
|
65
|
+
background-color: #1a202c; color: #f1c40f; font-size: 0.8rem; line-height: 1.4;
|
|
66
|
+
text-align: center; margin-top: 4px; border: 1.5px solid #f1c40f; box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
67
|
+
}
|
|
68
|
+
.blind-indicator { font-size: 0.7rem; color: #a0aec0; margin-top: 3px; }
|
|
69
|
+
.dealer-button {
|
|
70
|
+
width: 36px; height: 36px; background-color: #f0f0f0; color: #333; border-radius: 50%;
|
|
71
|
+
text-align: center; line-height: 36px; font-weight: bold; font-size: 1rem; position: absolute;
|
|
72
|
+
border: 2px solid #888; box-shadow: 0 1px 3px rgba(0,0,0,0.3); z-index: 5;
|
|
73
|
+
}
|
|
74
|
+
.pos-player0-sb { bottom: -55px; left: 50%; }
|
|
75
|
+
.pos-player1-bb { top: -55px; left: 50%; }
|
|
76
|
+
.dealer-sb { bottom: -15px; left: calc(50% + 95px); transform: translateX(-50%); }
|
|
77
|
+
.current-player-turn-highlight { border: 2px solid #f1c40f !important; box-shadow: 0 0 15px #f1c40f, 0 3px 12px rgba(0,0,0,0.35) !important; }
|
|
78
|
+
#game-message-area { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); background-color: rgba(0,0,0,0.6); padding: 5px 10px; border-radius: 5px; font-size: 0.9rem; z-index: 20;}
|
|
79
|
+
|
|
80
|
+
@media (max-width: 768px) {
|
|
81
|
+
.poker-table { width: clamp(350px, 90vw, 700px); height: clamp(180px, 48vw, 350px); border-radius: 175px; }
|
|
82
|
+
.pos-player0-sb { bottom: -50px; } .pos-player1-bb { top: -50px; }
|
|
83
|
+
.dealer-sb { left: calc(50% + 85px); bottom: -12px; }
|
|
84
|
+
.player-pod { min-width: 110px; max-width: 150px; padding: 0.5rem 0.7rem; min-height: 120px; }
|
|
85
|
+
.card { width: 44px; height: 62px; } .card-rank { font-size: 1.6rem; } .card-suit { font-size: 1.3rem; }
|
|
86
|
+
.community-cards-container .card { width: 48px; height: 68px; }
|
|
87
|
+
.community-cards-container .card-rank { font-size: 1.8rem;} .community-cards-container .card-suit { font-size: 1.5rem;}
|
|
88
|
+
}
|
|
89
|
+
@media (max-width: 600px) {
|
|
90
|
+
.poker-table { width: clamp(300px, 90vw, 500px); height: clamp(160px, 50vw, 250px); border-radius: 125px; }
|
|
91
|
+
.player-pod { min-width: 100px; max-width: 140px; padding: 0.4rem 0.5rem; font-size: 0.85rem; min-height: 110px;}
|
|
92
|
+
.player-name { font-size: 0.85rem;} .player-stack { font-size: 0.75rem; }
|
|
93
|
+
.card { width: 40px; height: 58px; margin: 0 2px; } .card-rank { font-size: 1.4rem; } .card-suit { font-size: 1.2rem; }
|
|
94
|
+
.community-cards-container .card { width: 42px; height: 60px; }
|
|
95
|
+
.community-cards-container .card-rank { font-size: 1.5rem;} .community-cards-container .card-suit { font-size: 1.3rem;}
|
|
96
|
+
.bet-display { font-size: 0.75rem; } .pos-player0-sb { bottom: -45px; } .pos-player1-bb { top: -45px; }
|
|
97
|
+
.dealer-button { width: 32px; height: 32px; line-height: 32px; font-size: 0.9rem;}
|
|
98
|
+
.dealer-sb { bottom: -8px; left: calc(50% + 75px); }
|
|
99
|
+
}
|
|
100
|
+
@media (max-width: 400px) {
|
|
101
|
+
.poker-table { width: clamp(280px, 95vw, 380px); height: clamp(150px, 55vw, 200px); border-radius: 100px; border-width: 8px; }
|
|
102
|
+
.player-pod { min-width: 90px; max-width: 120px; padding: 0.3rem 0.4rem; min-height: 100px;}
|
|
103
|
+
.player-name { font-size: 0.8rem;} .player-stack { font-size: 0.7rem; }
|
|
104
|
+
.card { width: 36px; height: 52px; margin: 0 1px; } .card-rank { font-size: 1.2rem; } .card-suit { font-size: 1rem; }
|
|
105
|
+
.community-cards-container .card { width: 38px; height: 55px; }
|
|
106
|
+
.community-cards-container .card-rank { font-size: 1.3rem;} .community-cards-container .card-suit { font-size: 1.1rem;}
|
|
107
|
+
.dealer-button { width: 28px; height: 28px; line-height: 28px; font-size: 0.8rem;}
|
|
108
|
+
.pos-player0-sb { bottom: -40px; } .pos-player1-bb { top: -40px; }
|
|
109
|
+
.dealer-sb { bottom: -5px; left: calc(50% + 65px); }
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
112
|
+
const parentForStyles = passedOptions && passedOptions.parent ? passedOptions.parent.ownerDocument.head : document.head;
|
|
113
|
+
if (parentForStyles && !parentForStyles.querySelector('style[data-poker-renderer-styles]')) {
|
|
114
|
+
style.setAttribute('data-poker-renderer-styles', 'true');
|
|
115
|
+
parentForStyles.appendChild(style);
|
|
116
|
+
}
|
|
117
|
+
window.__poker_styles_injected = true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function acpcCardToDisplay(acpcCard) {
|
|
121
|
+
if (!acpcCard || acpcCard.length < 2) return { rank: '?', suitSymbol: '', original: acpcCard };
|
|
122
|
+
const rankChar = acpcCard[0].toUpperCase();
|
|
123
|
+
const suitChar = acpcCard[1].toLowerCase();
|
|
124
|
+
const rankMap = { 'T': '10', 'J': 'J', 'Q': 'Q', 'K': 'K', 'A': 'A' };
|
|
125
|
+
const suitMap = { 's': '♠', 'h': '♥', 'd': '♦', 'c': '♣' };
|
|
126
|
+
const rank = rankMap[rankChar] || rankChar;
|
|
127
|
+
const suitSymbol = suitMap[suitChar] || '';
|
|
128
|
+
return { rank, suitSymbol, original: acpcCard };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function createCardElement(cardStr, isHidden = false) {
|
|
132
|
+
const cardDiv = document.createElement('div');
|
|
133
|
+
cardDiv.classList.add('card');
|
|
134
|
+
if (isHidden || !cardStr || cardStr === '?' || cardStr === "??") {
|
|
135
|
+
cardDiv.classList.add('card-back');
|
|
136
|
+
} else {
|
|
137
|
+
const { rank, suitSymbol } = acpcCardToDisplay(cardStr);
|
|
138
|
+
const rankSpan = document.createElement('span');
|
|
139
|
+
rankSpan.classList.add('card-rank');
|
|
140
|
+
rankSpan.textContent = rank;
|
|
141
|
+
cardDiv.appendChild(rankSpan);
|
|
142
|
+
const suitSpan = document.createElement('span');
|
|
143
|
+
suitSpan.classList.add('card-suit');
|
|
144
|
+
suitSpan.textContent = suitSymbol;
|
|
145
|
+
cardDiv.appendChild(suitSpan);
|
|
146
|
+
if (suitSymbol === '♥' || suitSymbol === '♦') cardDiv.classList.add('card-red');
|
|
147
|
+
else if (suitSymbol === '♠' || suitSymbol === '♣') cardDiv.classList.add('card-black');
|
|
148
|
+
}
|
|
149
|
+
return cardDiv;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function _ensurePokerTableElements(parentElement, passedOptions) {
|
|
153
|
+
if (!parentElement) return false;
|
|
154
|
+
parentElement.innerHTML = '';
|
|
155
|
+
parentElement.classList.add('poker-renderer-host');
|
|
156
|
+
|
|
157
|
+
elements.diagnosticHeader = document.createElement('h1');
|
|
158
|
+
elements.diagnosticHeader.id = 'poker-renderer-diagnostic-header';
|
|
159
|
+
elements.diagnosticHeader.textContent = "Poker Table Initialized (Live Data)";
|
|
160
|
+
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
|
|
161
|
+
parentElement.appendChild(elements.diagnosticHeader);
|
|
162
|
+
|
|
163
|
+
elements.gameMessageArea = document.createElement('div');
|
|
164
|
+
elements.gameMessageArea.id = 'game-message-area';
|
|
165
|
+
parentElement.appendChild(elements.gameMessageArea);
|
|
166
|
+
|
|
167
|
+
elements.pokerTableContainer = document.createElement('div');
|
|
168
|
+
elements.pokerTableContainer.className = 'poker-table-container';
|
|
169
|
+
parentElement.appendChild(elements.pokerTableContainer);
|
|
170
|
+
|
|
171
|
+
elements.pokerTable = document.createElement('div');
|
|
172
|
+
elements.pokerTable.className = 'poker-table';
|
|
173
|
+
elements.pokerTableContainer.appendChild(elements.pokerTable);
|
|
174
|
+
|
|
175
|
+
const communityArea = document.createElement('div');
|
|
176
|
+
communityArea.className = 'community-cards-area';
|
|
177
|
+
elements.pokerTable.appendChild(communityArea);
|
|
178
|
+
|
|
179
|
+
elements.communityCardsContainer = document.createElement('div');
|
|
180
|
+
elements.communityCardsContainer.className = 'community-cards-container';
|
|
181
|
+
communityArea.appendChild(elements.communityCardsContainer);
|
|
182
|
+
|
|
183
|
+
elements.potDisplay = document.createElement('div');
|
|
184
|
+
elements.potDisplay.className = 'pot-display';
|
|
185
|
+
communityArea.appendChild(elements.potDisplay);
|
|
186
|
+
|
|
187
|
+
elements.playerPods = [];
|
|
188
|
+
for (let i = 0; i < 2; i++) {
|
|
189
|
+
const playerPod = document.createElement('div');
|
|
190
|
+
playerPod.className = `player-pod ${i === 0 ? 'pos-player0-sb' : 'pos-player1-bb'}`;
|
|
191
|
+
playerPod.innerHTML = `
|
|
192
|
+
<div class="player-name">Player ${i}</div>
|
|
193
|
+
<div class="player-stack">$0.00</div>
|
|
194
|
+
<div class="player-cards-container"></div>
|
|
195
|
+
<div class="bet-display" style="display:none;">$0.00</div>
|
|
196
|
+
<div class="player-status">(${i === 0 ? 'SB' : 'BB'})</div>
|
|
197
|
+
`;
|
|
198
|
+
elements.pokerTable.appendChild(playerPod);
|
|
199
|
+
elements.playerPods.push(playerPod);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
elements.dealerButton = document.createElement('div');
|
|
203
|
+
elements.dealerButton.className = 'dealer-button dealer-sb';
|
|
204
|
+
elements.dealerButton.textContent = 'D';
|
|
205
|
+
elements.dealerButton.style.display = 'none';
|
|
206
|
+
elements.pokerTable.appendChild(elements.dealerButton);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
// --- REVISED PARSING LOGIC ---
|
|
212
|
+
function _parseKagglePokerState(options) {
|
|
213
|
+
const { environment, step } = options;
|
|
214
|
+
const numPlayers = 2; // Assuming 2 players based on logs
|
|
215
|
+
|
|
216
|
+
// --- Default State ---
|
|
217
|
+
const defaultUIData = {
|
|
218
|
+
players: Array(numPlayers).fill(null).map((_, i) => ({
|
|
219
|
+
id: `player${i}`,
|
|
220
|
+
name: `Player ${i}`,
|
|
221
|
+
stack: 0,
|
|
222
|
+
cards: [], // Will be filled with nulls or cards
|
|
223
|
+
currentBet: 0,
|
|
224
|
+
position: i === 0 ? "SB" : "BB",
|
|
225
|
+
isDealer: i === 0,
|
|
226
|
+
isTurn: false,
|
|
227
|
+
status: "Waiting...",
|
|
228
|
+
reward: null
|
|
229
|
+
})),
|
|
230
|
+
communityCards: [],
|
|
231
|
+
pot: 0,
|
|
232
|
+
isTerminal: false,
|
|
233
|
+
gameMessage: "Initializing...",
|
|
234
|
+
rawObservation: null, // For debugging
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// --- Step Validation ---
|
|
238
|
+
if (!environment || !environment.steps || !environment.steps[step]) {
|
|
239
|
+
return defaultUIData;
|
|
240
|
+
}
|
|
241
|
+
const currentStepAgents = environment.steps[step];
|
|
242
|
+
if (!currentStepAgents || currentStepAgents.length < numPlayers) {
|
|
243
|
+
defaultUIData.gameMessage = "Waiting for agent data...";
|
|
244
|
+
return defaultUIData;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// --- Observation Extraction & Merging ---
|
|
248
|
+
let obsP0 = null, obsP1 = null;
|
|
249
|
+
try {
|
|
250
|
+
obsP0 = JSON.parse(currentStepAgents[0].observation.observationString);
|
|
251
|
+
obsP1 = JSON.parse(currentStepAgents[1].observation.observationString);
|
|
252
|
+
} catch (e) {
|
|
253
|
+
defaultUIData.gameMessage = "Error parsing observation JSON.";
|
|
254
|
+
return defaultUIData;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!obsP0) {
|
|
258
|
+
defaultUIData.gameMessage = "Waiting for valid game state...";
|
|
259
|
+
return defaultUIData;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// --- Combine observations into a single, reliable state object ---
|
|
263
|
+
const combinedState = { ...obsP0 }; // Start with Player 0's data
|
|
264
|
+
// Player hands are split across observations. We need to merge them.
|
|
265
|
+
combinedState.player_hands = [
|
|
266
|
+
// Take the real hand from P0's obs
|
|
267
|
+
obsP0.player_hands[0].length > 0 ? obsP0.player_hands[0] : [],
|
|
268
|
+
// Take the real hand from P1's obs
|
|
269
|
+
obsP1.player_hands[1].length > 0 ? obsP1.player_hands[1] : []
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
defaultUIData.rawObservation = combinedState;
|
|
273
|
+
|
|
274
|
+
// --- Populate UI Data from Combined State ---
|
|
275
|
+
const {
|
|
276
|
+
pot_size,
|
|
277
|
+
player_contributions,
|
|
278
|
+
starting_stacks,
|
|
279
|
+
player_hands,
|
|
280
|
+
board_cards,
|
|
281
|
+
current_player,
|
|
282
|
+
betting_history,
|
|
283
|
+
} = combinedState;
|
|
284
|
+
|
|
285
|
+
const isTerminal = current_player === "terminal";
|
|
286
|
+
defaultUIData.isTerminal = isTerminal;
|
|
287
|
+
defaultUIData.pot = pot_size || 0;
|
|
288
|
+
defaultUIData.communityCards = board_cards || [];
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
// --- Update Player Pods ---
|
|
292
|
+
for (let i = 0; i < numPlayers; i++) {
|
|
293
|
+
const pData = defaultUIData.players[i];
|
|
294
|
+
const contribution = player_contributions ? player_contributions[i] : 0;
|
|
295
|
+
const startStack = starting_stacks ? starting_stacks[i] : 0;
|
|
296
|
+
|
|
297
|
+
pData.currentBet = contribution;
|
|
298
|
+
pData.stack = startStack - contribution;
|
|
299
|
+
pData.cards = (player_hands[i] || []).map(c => c === "??" ? null : c);
|
|
300
|
+
pData.isTurn = String(i) === String(current_player);
|
|
301
|
+
pData.status = pData.position; // Default status
|
|
302
|
+
|
|
303
|
+
if (isTerminal) {
|
|
304
|
+
const reward = environment.rewards ? environment.rewards[i] : null;
|
|
305
|
+
pData.reward = reward;
|
|
306
|
+
if (reward > 0) pData.status = "Winner!";
|
|
307
|
+
else if (reward < 0) pData.status = "Loser";
|
|
308
|
+
else pData.status = "Game Over";
|
|
309
|
+
} else if (pData.isTurn) {
|
|
310
|
+
pData.status = "Thinking...";
|
|
311
|
+
} else if (pData.stack === 0 && pData.currentBet > 0) {
|
|
312
|
+
pData.status = "All-in";
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Handle folded player status
|
|
317
|
+
if (!isTerminal && betting_history && betting_history.includes('f')) {
|
|
318
|
+
// A simple fold check: the player who didn't make the last action and isn't the current player might have folded.
|
|
319
|
+
// This is a simplification. A more robust parser would track the betting sequence.
|
|
320
|
+
const lastAction = betting_history.slice(-1);
|
|
321
|
+
if (lastAction === 'f') {
|
|
322
|
+
// Find who is NOT the current player
|
|
323
|
+
const nonCurrentPlayerIndex = current_player === '0' ? 1 : 0;
|
|
324
|
+
// If they are not all-in, they folded.
|
|
325
|
+
if (defaultUIData.players[nonCurrentPlayerIndex].status !== 'All-in') {
|
|
326
|
+
defaultUIData.players[nonCurrentPlayerIndex].status = "Folded";
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
// --- Set Game Message ---
|
|
333
|
+
if (isTerminal) {
|
|
334
|
+
const winnerIndex = environment.rewards ? environment.rewards.findIndex(r => r > 0) : -1;
|
|
335
|
+
if (winnerIndex !== -1) {
|
|
336
|
+
defaultUIData.gameMessage = `Player ${winnerIndex} wins!`;
|
|
337
|
+
} else {
|
|
338
|
+
defaultUIData.gameMessage = "Game Over.";
|
|
339
|
+
}
|
|
340
|
+
} else if (current_player === "chance") {
|
|
341
|
+
defaultUIData.gameMessage = `Dealing...`;
|
|
342
|
+
} else {
|
|
343
|
+
defaultUIData.gameMessage = `Player ${current_player}'s turn.`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return defaultUIData;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
// --- RENDERER UI LOGIC (Unchanged) ---
|
|
351
|
+
function _renderPokerTableUI(data, passedOptions) {
|
|
352
|
+
if (!elements.pokerTable || !data) return;
|
|
353
|
+
const { players, communityCards, pot, isTerminal, gameMessage } = data;
|
|
354
|
+
|
|
355
|
+
if (elements.diagnosticHeader && data.rawObservation) {
|
|
356
|
+
// Optional: Show diagnostics for debugging
|
|
357
|
+
// elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${data.rawObservation.current_player} POT:${data.pot}`;
|
|
358
|
+
// elements.diagnosticHeader.style.display = 'block';
|
|
359
|
+
}
|
|
360
|
+
if (elements.gameMessageArea) {
|
|
361
|
+
elements.gameMessageArea.textContent = gameMessage;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
elements.communityCardsContainer.innerHTML = '';
|
|
365
|
+
if (communityCards && communityCards.length > 0) {
|
|
366
|
+
communityCards.forEach(cardStr => {
|
|
367
|
+
elements.communityCardsContainer.appendChild(createCardElement(cardStr));
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
elements.potDisplay.textContent = `Pot: $${pot}`;
|
|
372
|
+
|
|
373
|
+
players.forEach((playerData, index) => {
|
|
374
|
+
const playerPod = elements.playerPods[index];
|
|
375
|
+
if (!playerPod) return;
|
|
376
|
+
|
|
377
|
+
playerPod.querySelector('.player-name').textContent = playerData.name;
|
|
378
|
+
playerPod.querySelector('.player-stack').textContent = `$${playerData.stack}`;
|
|
379
|
+
|
|
380
|
+
const playerCardsContainer = playerPod.querySelector('.player-cards-container');
|
|
381
|
+
playerCardsContainer.innerHTML = '';
|
|
382
|
+
|
|
383
|
+
// In heads-up, we show both hands at the end.
|
|
384
|
+
const showCards = isTerminal || (playerData.cards && !playerData.cards.includes(null));
|
|
385
|
+
|
|
386
|
+
(playerData.cards || [null, null]).forEach(cardStr => {
|
|
387
|
+
playerCardsContainer.appendChild(createCardElement(cardStr, !showCards && cardStr !== null));
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
const betDisplay = playerPod.querySelector('.bet-display');
|
|
391
|
+
if (playerData.currentBet > 0) {
|
|
392
|
+
betDisplay.textContent = `$${playerData.currentBet}`;
|
|
393
|
+
betDisplay.style.display = 'inline-block';
|
|
394
|
+
} else {
|
|
395
|
+
betDisplay.style.display = 'none';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
playerPod.querySelector('.player-status').textContent = playerData.status;
|
|
399
|
+
|
|
400
|
+
if (playerData.isTurn && !isTerminal) {
|
|
401
|
+
playerPod.classList.add('current-player-turn-highlight');
|
|
402
|
+
} else {
|
|
403
|
+
playerPod.classList.remove('current-player-turn-highlight');
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
const dealerPlayer = players.find(p => p.isDealer);
|
|
408
|
+
if (elements.dealerButton) {
|
|
409
|
+
elements.dealerButton.style.display = dealerPlayer ? 'block' : 'none';
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// --- MAIN EXECUTION LOGIC ---
|
|
414
|
+
const { parent } = options;
|
|
415
|
+
if (!parent) {
|
|
416
|
+
console.error("Renderer: Parent element not provided.");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
_injectStyles(options);
|
|
421
|
+
|
|
422
|
+
if (!_ensurePokerTableElements(parent, options)) {
|
|
423
|
+
console.error("Renderer: Failed to ensure poker table elements.");
|
|
424
|
+
parent.innerHTML = '<p style="color:red;">Error: Could not create poker table structure.</p>';
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Use the revised parsing logic
|
|
429
|
+
const uiData = _parseKagglePokerState(options);
|
|
430
|
+
_renderPokerTableUI(uiData, options);
|
|
431
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Change Universal Poker state and action string representations."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import pyspiel
|
|
8
|
+
|
|
9
|
+
from ... import proxy
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UniversalPokerState(proxy.State):
|
|
13
|
+
"""Universal Poker state proxy."""
|
|
14
|
+
|
|
15
|
+
def _player_string(self, player: int) -> str:
|
|
16
|
+
if player == pyspiel.PlayerId.CHANCE:
|
|
17
|
+
return "chance"
|
|
18
|
+
elif player == pyspiel.PlayerId.TERMINAL:
|
|
19
|
+
return "terminal"
|
|
20
|
+
if player < 0:
|
|
21
|
+
return pyspiel.PlayerId(player).name.lower()
|
|
22
|
+
else:
|
|
23
|
+
return str(player)
|
|
24
|
+
|
|
25
|
+
def _state_dict(self) -> dict[str, Any]:
|
|
26
|
+
params = self.get_game().get_parameters()
|
|
27
|
+
blinds = params["blind"].strip().split()
|
|
28
|
+
blinds = [int(blind) for blind in blinds]
|
|
29
|
+
assert len(blinds) == self.num_players()
|
|
30
|
+
starting_stacks = params["stack"].strip().split()
|
|
31
|
+
starting_stacks = [int(stack) for stack in starting_stacks]
|
|
32
|
+
assert len(starting_stacks) == self.num_players()
|
|
33
|
+
state_str = self.to_string()
|
|
34
|
+
state_lines = state_str.split("\n")
|
|
35
|
+
player_hands = []
|
|
36
|
+
for i in range(self.num_players()):
|
|
37
|
+
for line in state_lines:
|
|
38
|
+
if line.startswith(f"P{i} Cards:"):
|
|
39
|
+
hand = line.split(":")[1].strip()
|
|
40
|
+
player_hands.append([hand[i : i + 2] for i in range(0, len(hand), 2)])
|
|
41
|
+
assert len(player_hands) == self.num_players()
|
|
42
|
+
board_cards = None
|
|
43
|
+
for line in state_lines:
|
|
44
|
+
if line.startswith("BoardCards"):
|
|
45
|
+
board_cards_str = line.removeprefix("BoardCards").strip()
|
|
46
|
+
board_cards = [board_cards_str[i : i + 2] for i in range(0, len(board_cards_str), 2)]
|
|
47
|
+
assert board_cards is not None
|
|
48
|
+
pattern = r"P\d+:\s*(\d+)"
|
|
49
|
+
player_contributions = []
|
|
50
|
+
for line in state_lines:
|
|
51
|
+
if line.startswith("Spent:"):
|
|
52
|
+
matches = re.findall(pattern, line)
|
|
53
|
+
player_contributions = [int(match) for match in matches]
|
|
54
|
+
assert len(player_contributions) == self.num_players()
|
|
55
|
+
acpc_state = None
|
|
56
|
+
betting_history = None
|
|
57
|
+
for line in state_lines:
|
|
58
|
+
if line.startswith("ACPC State:"):
|
|
59
|
+
acpc_state = line.split("ACPC State:")[1].strip()
|
|
60
|
+
betting_history = acpc_state.split(":")[2]
|
|
61
|
+
assert acpc_state is not None
|
|
62
|
+
assert betting_history is not None
|
|
63
|
+
|
|
64
|
+
state_dict = {}
|
|
65
|
+
state_dict["acpc_state"] = acpc_state
|
|
66
|
+
state_dict["current_player"] = self._player_string(self.current_player())
|
|
67
|
+
state_dict["blinds"] = blinds
|
|
68
|
+
state_dict["betting_history"] = betting_history
|
|
69
|
+
state_dict["player_contributions"] = player_contributions
|
|
70
|
+
state_dict["pot_size"] = sum(player_contributions)
|
|
71
|
+
state_dict["starting_stacks"] = starting_stacks
|
|
72
|
+
state_dict["player_hands"] = player_hands
|
|
73
|
+
state_dict["board_cards"] = board_cards
|
|
74
|
+
return state_dict
|
|
75
|
+
|
|
76
|
+
def to_json(self) -> str:
|
|
77
|
+
return json.dumps(self._state_dict())
|
|
78
|
+
|
|
79
|
+
def _action_to_string(self, player: int, action: int) -> str:
|
|
80
|
+
if player == pyspiel.PlayerId.CHANCE:
|
|
81
|
+
return f"deal {action}" # TODO(jhtschultz): Add card.
|
|
82
|
+
if action == 0:
|
|
83
|
+
return "fold"
|
|
84
|
+
elif action == 1:
|
|
85
|
+
if 0 in self.legal_actions():
|
|
86
|
+
return "call"
|
|
87
|
+
else:
|
|
88
|
+
return "check"
|
|
89
|
+
else:
|
|
90
|
+
return f"raise{action}"
|
|
91
|
+
|
|
92
|
+
def action_to_json(self, action: int) -> str:
|
|
93
|
+
action_str = self._action_to_string(self.current_player(), action)
|
|
94
|
+
return json.dumps({"action": action_str})
|
|
95
|
+
|
|
96
|
+
def observation_dict(self, player: int) -> dict[str, Any]:
|
|
97
|
+
state_dict = self._state_dict()
|
|
98
|
+
for i in range(self.num_players()):
|
|
99
|
+
if i == player:
|
|
100
|
+
continue
|
|
101
|
+
state_dict["player_hands"][i] = ["??", "??"]
|
|
102
|
+
del state_dict["acpc_state"]
|
|
103
|
+
return state_dict
|
|
104
|
+
|
|
105
|
+
def observation_json(self, player: int) -> str:
|
|
106
|
+
return json.dumps(self.observation_dict(player))
|
|
107
|
+
|
|
108
|
+
def observation_string(self, player: int) -> str:
|
|
109
|
+
return self.observation_json(player)
|
|
110
|
+
|
|
111
|
+
def __str__(self):
|
|
112
|
+
return self.to_json()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _strip_empty_kwargs(input_string):
|
|
116
|
+
try:
|
|
117
|
+
open_paren_index = input_string.index("(")
|
|
118
|
+
close_paren_index = input_string.rindex(")")
|
|
119
|
+
except ValueError:
|
|
120
|
+
return input_string
|
|
121
|
+
|
|
122
|
+
function_name = input_string[:open_paren_index]
|
|
123
|
+
args_string = input_string[open_paren_index + 1 : close_paren_index]
|
|
124
|
+
args_list = args_string.split(",")
|
|
125
|
+
non_empty_args = []
|
|
126
|
+
for arg in args_list:
|
|
127
|
+
parts = arg.split("=", 1)
|
|
128
|
+
if len(parts) > 1 and parts[1]:
|
|
129
|
+
non_empty_args.append(arg)
|
|
130
|
+
elif len(parts) == 1 and parts[0]:
|
|
131
|
+
non_empty_args.append(arg)
|
|
132
|
+
new_args_string = ",".join(non_empty_args)
|
|
133
|
+
return f"{function_name}({new_args_string})"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class UniversalPokerGame(proxy.Game):
|
|
137
|
+
"""Universal Poker game proxy."""
|
|
138
|
+
|
|
139
|
+
def __init__(self, params: Any | None = None):
|
|
140
|
+
params = params or {}
|
|
141
|
+
wrapped = pyspiel.load_game("universal_poker", params)
|
|
142
|
+
super().__init__(
|
|
143
|
+
wrapped,
|
|
144
|
+
short_name="universal_poker_proxy",
|
|
145
|
+
long_name="Universal Poker (proxy)",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def __str__(self):
|
|
149
|
+
s = _strip_empty_kwargs(self.__wrapped__.__str__())
|
|
150
|
+
return s.split("(")[0] + "_proxy(" + s.split("(")[1]
|
|
151
|
+
|
|
152
|
+
def new_initial_state(self, *args) -> UniversalPokerState:
|
|
153
|
+
return UniversalPokerState(
|
|
154
|
+
self.__wrapped__.new_initial_state(*args),
|
|
155
|
+
game=self,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
pyspiel.register_game(UniversalPokerGame().get_type(), UniversalPokerGame)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import pyspiel
|
|
4
|
+
|
|
5
|
+
from kaggle_environments import make
|
|
6
|
+
|
|
7
|
+
open_spiel_game_name = "connect_four"
|
|
8
|
+
game = pyspiel.load_game(open_spiel_game_name)
|
|
9
|
+
game_type = game.get_type()
|
|
10
|
+
environment_name = f"open_spiel_{game_type.short_name}"
|
|
11
|
+
agents_to_run = ["random"] * game.num_players()
|
|
12
|
+
replay_width = 500
|
|
13
|
+
replay_height = 450
|
|
14
|
+
debug_mode = True
|
|
15
|
+
env = make(environment_name, debug=debug_mode)
|
|
16
|
+
|
|
17
|
+
print(f"Running game with agents: {agents_to_run}...")
|
|
18
|
+
env.run(agents_to_run)
|
|
19
|
+
print("Game finished.")
|
|
20
|
+
|
|
21
|
+
print("Generating HTML replay...")
|
|
22
|
+
html_replay = env.render(mode="html", width=replay_width, height=replay_height)
|
|
23
|
+
|
|
24
|
+
output_html_file = f"kaggle_environments/envs/open_spiel/{environment_name}_game_replay.html"
|
|
25
|
+
print(f"Saving replay to: '{output_html_file}'")
|
|
26
|
+
with open(output_html_file, "w", encoding="utf-8") as f:
|
|
27
|
+
f.write(html_replay)
|
|
28
|
+
|
|
29
|
+
print("-" * 20)
|
|
30
|
+
print(f"Successfully generated replay: {os.path.abspath(output_html_file)}")
|
|
31
|
+
print("-" * 20)
|