kaggle-environments 0.2.1__py3-none-any.whl → 1.20.0__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 (215) hide show
  1. kaggle_environments/__init__.py +49 -13
  2. kaggle_environments/agent.py +177 -124
  3. kaggle_environments/api.py +31 -0
  4. kaggle_environments/core.py +295 -170
  5. kaggle_environments/envs/cabt/cabt.js +164 -0
  6. kaggle_environments/envs/cabt/cabt.json +28 -0
  7. kaggle_environments/envs/cabt/cabt.py +186 -0
  8. kaggle_environments/envs/cabt/cg/__init__.py +0 -0
  9. kaggle_environments/envs/cabt/cg/cg.dll +0 -0
  10. kaggle_environments/envs/cabt/cg/game.py +75 -0
  11. kaggle_environments/envs/cabt/cg/libcg.so +0 -0
  12. kaggle_environments/envs/cabt/cg/sim.py +48 -0
  13. kaggle_environments/envs/cabt/test_cabt.py +120 -0
  14. kaggle_environments/envs/chess/chess.js +4289 -0
  15. kaggle_environments/envs/chess/chess.json +60 -0
  16. kaggle_environments/envs/chess/chess.py +4241 -0
  17. kaggle_environments/envs/chess/test_chess.py +60 -0
  18. kaggle_environments/envs/connectx/connectx.ipynb +3186 -0
  19. kaggle_environments/envs/connectx/connectx.js +1 -1
  20. kaggle_environments/envs/connectx/connectx.json +15 -1
  21. kaggle_environments/envs/connectx/connectx.py +6 -23
  22. kaggle_environments/envs/connectx/test_connectx.py +70 -24
  23. kaggle_environments/envs/football/football.ipynb +75 -0
  24. kaggle_environments/envs/football/football.json +91 -0
  25. kaggle_environments/envs/football/football.py +277 -0
  26. kaggle_environments/envs/football/helpers.py +95 -0
  27. kaggle_environments/envs/football/test_football.py +360 -0
  28. kaggle_environments/envs/halite/__init__.py +0 -0
  29. kaggle_environments/envs/halite/halite.ipynb +44741 -0
  30. kaggle_environments/envs/halite/halite.js +199 -83
  31. kaggle_environments/envs/halite/halite.json +31 -18
  32. kaggle_environments/envs/halite/halite.py +164 -303
  33. kaggle_environments/envs/halite/helpers.py +720 -0
  34. kaggle_environments/envs/halite/test_halite.py +190 -0
  35. kaggle_environments/envs/hungry_geese/__init__.py +0 -0
  36. kaggle_environments/envs/{battlegeese/battlegeese.js → hungry_geese/hungry_geese.js} +38 -22
  37. kaggle_environments/envs/{battlegeese/battlegeese.json → hungry_geese/hungry_geese.json} +21 -14
  38. kaggle_environments/envs/hungry_geese/hungry_geese.py +316 -0
  39. kaggle_environments/envs/hungry_geese/test_hungry_geese.py +0 -0
  40. kaggle_environments/envs/identity/identity.json +6 -5
  41. kaggle_environments/envs/identity/identity.py +15 -2
  42. kaggle_environments/envs/kore_fleets/__init__.py +0 -0
  43. kaggle_environments/envs/kore_fleets/helpers.py +1005 -0
  44. kaggle_environments/envs/kore_fleets/kore_fleets.ipynb +114 -0
  45. kaggle_environments/envs/kore_fleets/kore_fleets.js +658 -0
  46. kaggle_environments/envs/kore_fleets/kore_fleets.json +164 -0
  47. kaggle_environments/envs/kore_fleets/kore_fleets.py +555 -0
  48. kaggle_environments/envs/kore_fleets/starter_bots/java/Bot.java +54 -0
  49. kaggle_environments/envs/kore_fleets/starter_bots/java/README.md +26 -0
  50. kaggle_environments/envs/kore_fleets/starter_bots/java/jars/hamcrest-core-1.3.jar +0 -0
  51. kaggle_environments/envs/kore_fleets/starter_bots/java/jars/junit-4.13.2.jar +0 -0
  52. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Board.java +518 -0
  53. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Cell.java +61 -0
  54. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Configuration.java +24 -0
  55. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Direction.java +166 -0
  56. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Fleet.java +72 -0
  57. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/KoreJson.java +97 -0
  58. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Observation.java +72 -0
  59. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Pair.java +13 -0
  60. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Player.java +68 -0
  61. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Point.java +65 -0
  62. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Shipyard.java +70 -0
  63. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/ShipyardAction.java +59 -0
  64. kaggle_environments/envs/kore_fleets/starter_bots/java/main.py +73 -0
  65. kaggle_environments/envs/kore_fleets/starter_bots/java/test/BoardTest.java +567 -0
  66. kaggle_environments/envs/kore_fleets/starter_bots/java/test/ConfigurationTest.java +25 -0
  67. kaggle_environments/envs/kore_fleets/starter_bots/java/test/KoreJsonTest.java +62 -0
  68. kaggle_environments/envs/kore_fleets/starter_bots/java/test/ObservationTest.java +46 -0
  69. kaggle_environments/envs/kore_fleets/starter_bots/java/test/PointTest.java +21 -0
  70. kaggle_environments/envs/kore_fleets/starter_bots/java/test/ShipyardTest.java +22 -0
  71. kaggle_environments/envs/kore_fleets/starter_bots/java/test/configuration.json +1 -0
  72. kaggle_environments/envs/kore_fleets/starter_bots/java/test/fullob.json +1 -0
  73. kaggle_environments/envs/kore_fleets/starter_bots/java/test/observation.json +1 -0
  74. kaggle_environments/envs/kore_fleets/starter_bots/python/__init__.py +0 -0
  75. kaggle_environments/envs/kore_fleets/starter_bots/python/main.py +27 -0
  76. kaggle_environments/envs/kore_fleets/starter_bots/ts/Bot.ts +34 -0
  77. kaggle_environments/envs/kore_fleets/starter_bots/ts/DoNothingBot.ts +12 -0
  78. kaggle_environments/envs/kore_fleets/starter_bots/ts/MinerBot.ts +62 -0
  79. kaggle_environments/envs/kore_fleets/starter_bots/ts/README.md +55 -0
  80. kaggle_environments/envs/kore_fleets/starter_bots/ts/interpreter.ts +402 -0
  81. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Board.ts +514 -0
  82. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Cell.ts +63 -0
  83. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Configuration.ts +25 -0
  84. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Direction.ts +169 -0
  85. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Fleet.ts +76 -0
  86. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/KoreIO.ts +70 -0
  87. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Observation.ts +45 -0
  88. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Pair.ts +11 -0
  89. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Player.ts +68 -0
  90. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Point.ts +65 -0
  91. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Shipyard.ts +72 -0
  92. kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/ShipyardAction.ts +58 -0
  93. kaggle_environments/envs/kore_fleets/starter_bots/ts/main.py +73 -0
  94. kaggle_environments/envs/kore_fleets/starter_bots/ts/miner.py +73 -0
  95. kaggle_environments/envs/kore_fleets/starter_bots/ts/package.json +23 -0
  96. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/BoardTest.ts +551 -0
  97. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ConfigurationTest.ts +16 -0
  98. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ObservationTest.ts +33 -0
  99. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/PointTest.ts +17 -0
  100. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ShipyardTest.ts +18 -0
  101. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/configuration.json +1 -0
  102. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/fullob.json +1 -0
  103. kaggle_environments/envs/kore_fleets/starter_bots/ts/test/observation.json +1 -0
  104. kaggle_environments/envs/kore_fleets/starter_bots/ts/tsconfig.json +22 -0
  105. kaggle_environments/envs/kore_fleets/test_kore_fleets.py +331 -0
  106. kaggle_environments/envs/lux_ai_2021/README.md +3 -0
  107. kaggle_environments/envs/lux_ai_2021/__init__.py +0 -0
  108. kaggle_environments/envs/lux_ai_2021/agents.py +11 -0
  109. kaggle_environments/envs/lux_ai_2021/dimensions/754.js +2 -0
  110. kaggle_environments/envs/lux_ai_2021/dimensions/754.js.LICENSE.txt +296 -0
  111. kaggle_environments/envs/lux_ai_2021/dimensions/main.js +1 -0
  112. kaggle_environments/envs/lux_ai_2021/index.html +43 -0
  113. kaggle_environments/envs/lux_ai_2021/lux_ai_2021.json +100 -0
  114. kaggle_environments/envs/lux_ai_2021/lux_ai_2021.py +231 -0
  115. kaggle_environments/envs/lux_ai_2021/test_agents/__init__.py +0 -0
  116. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.js +6 -0
  117. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.json +59 -0
  118. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_objects.js +145 -0
  119. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/io.js +14 -0
  120. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/kit.js +209 -0
  121. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/map.js +107 -0
  122. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/parser.js +79 -0
  123. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.js +88 -0
  124. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.py +75 -0
  125. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/simple.tar.gz +0 -0
  126. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/__init__.py +0 -0
  127. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/annotate.py +20 -0
  128. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/constants.py +25 -0
  129. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game.py +86 -0
  130. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.json +59 -0
  131. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.py +7 -0
  132. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_map.py +106 -0
  133. kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_objects.py +154 -0
  134. kaggle_environments/envs/lux_ai_2021/test_agents/python/random_agent.py +38 -0
  135. kaggle_environments/envs/lux_ai_2021/test_agents/python/simple_agent.py +82 -0
  136. kaggle_environments/envs/lux_ai_2021/test_lux.py +19 -0
  137. kaggle_environments/envs/lux_ai_2021/testing.md +23 -0
  138. kaggle_environments/envs/lux_ai_2021/todo.md.og +18 -0
  139. kaggle_environments/envs/lux_ai_s3/README.md +21 -0
  140. kaggle_environments/envs/lux_ai_s3/agents.py +5 -0
  141. kaggle_environments/envs/lux_ai_s3/index.html +42 -0
  142. kaggle_environments/envs/lux_ai_s3/lux_ai_s3.json +47 -0
  143. kaggle_environments/envs/lux_ai_s3/lux_ai_s3.py +178 -0
  144. kaggle_environments/envs/lux_ai_s3/luxai_s3/__init__.py +1 -0
  145. kaggle_environments/envs/lux_ai_s3/luxai_s3/env.py +819 -0
  146. kaggle_environments/envs/lux_ai_s3/luxai_s3/globals.py +9 -0
  147. kaggle_environments/envs/lux_ai_s3/luxai_s3/params.py +101 -0
  148. kaggle_environments/envs/lux_ai_s3/luxai_s3/profiler.py +141 -0
  149. kaggle_environments/envs/lux_ai_s3/luxai_s3/pygame_render.py +222 -0
  150. kaggle_environments/envs/lux_ai_s3/luxai_s3/spaces.py +27 -0
  151. kaggle_environments/envs/lux_ai_s3/luxai_s3/state.py +464 -0
  152. kaggle_environments/envs/lux_ai_s3/luxai_s3/utils.py +12 -0
  153. kaggle_environments/envs/lux_ai_s3/luxai_s3/wrappers.py +156 -0
  154. kaggle_environments/envs/lux_ai_s3/test_agents/python/agent.py +78 -0
  155. kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/__init__.py +0 -0
  156. kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/kit.py +31 -0
  157. kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/utils.py +17 -0
  158. kaggle_environments/envs/lux_ai_s3/test_agents/python/main.py +66 -0
  159. kaggle_environments/envs/lux_ai_s3/test_lux.py +9 -0
  160. kaggle_environments/envs/mab/__init__.py +0 -0
  161. kaggle_environments/envs/mab/agents.py +12 -0
  162. kaggle_environments/envs/mab/mab.js +100 -0
  163. kaggle_environments/envs/mab/mab.json +74 -0
  164. kaggle_environments/envs/mab/mab.py +146 -0
  165. kaggle_environments/envs/open_spiel/__init__.py +0 -0
  166. kaggle_environments/envs/open_spiel/games/__init__.py +0 -0
  167. kaggle_environments/envs/open_spiel/games/chess/chess.js +441 -0
  168. kaggle_environments/envs/open_spiel/games/chess/image_config.jsonl +20 -0
  169. kaggle_environments/envs/open_spiel/games/chess/openings.jsonl +20 -0
  170. kaggle_environments/envs/open_spiel/games/connect_four/__init__.py +0 -0
  171. kaggle_environments/envs/open_spiel/games/connect_four/connect_four.js +284 -0
  172. kaggle_environments/envs/open_spiel/games/connect_four/connect_four_proxy.py +86 -0
  173. kaggle_environments/envs/open_spiel/games/go/__init__.py +0 -0
  174. kaggle_environments/envs/open_spiel/games/go/go.js +481 -0
  175. kaggle_environments/envs/open_spiel/games/go/go_proxy.py +99 -0
  176. kaggle_environments/envs/open_spiel/games/tic_tac_toe/__init__.py +0 -0
  177. kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe.js +345 -0
  178. kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe_proxy.py +98 -0
  179. kaggle_environments/envs/open_spiel/games/universal_poker/__init__.py +0 -0
  180. kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker.js +431 -0
  181. kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker_proxy.py +159 -0
  182. kaggle_environments/envs/open_spiel/html_playthrough_generator.py +31 -0
  183. kaggle_environments/envs/open_spiel/observation.py +128 -0
  184. kaggle_environments/envs/open_spiel/open_spiel.py +565 -0
  185. kaggle_environments/envs/open_spiel/proxy.py +138 -0
  186. kaggle_environments/envs/open_spiel/test_open_spiel.py +191 -0
  187. kaggle_environments/envs/rps/__init__.py +0 -0
  188. kaggle_environments/envs/rps/agents.py +84 -0
  189. kaggle_environments/envs/rps/helpers.py +25 -0
  190. kaggle_environments/envs/rps/rps.js +117 -0
  191. kaggle_environments/envs/rps/rps.json +63 -0
  192. kaggle_environments/envs/rps/rps.py +90 -0
  193. kaggle_environments/envs/rps/test_rps.py +110 -0
  194. kaggle_environments/envs/rps/utils.py +7 -0
  195. kaggle_environments/envs/tictactoe/test_tictactoe.py +43 -77
  196. kaggle_environments/envs/tictactoe/tictactoe.ipynb +1397 -0
  197. kaggle_environments/envs/tictactoe/tictactoe.json +10 -2
  198. kaggle_environments/envs/tictactoe/tictactoe.py +1 -1
  199. kaggle_environments/errors.py +2 -4
  200. kaggle_environments/helpers.py +377 -0
  201. kaggle_environments/main.py +340 -0
  202. kaggle_environments/schemas.json +23 -18
  203. kaggle_environments/static/player.html +206 -74
  204. kaggle_environments/utils.py +46 -73
  205. kaggle_environments-1.20.0.dist-info/METADATA +25 -0
  206. kaggle_environments-1.20.0.dist-info/RECORD +211 -0
  207. {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.0.dist-info}/WHEEL +1 -2
  208. kaggle_environments-1.20.0.dist-info/entry_points.txt +3 -0
  209. kaggle_environments/envs/battlegeese/battlegeese.py +0 -223
  210. kaggle_environments/temp.py +0 -14
  211. kaggle_environments-0.2.1.dist-info/METADATA +0 -393
  212. kaggle_environments-0.2.1.dist-info/RECORD +0 -32
  213. kaggle_environments-0.2.1.dist-info/entry_points.txt +0 -3
  214. kaggle_environments-0.2.1.dist-info/top_level.txt +0 -1
  215. {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.0.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)