kaggle-environments 0.2.0__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.
- kaggle_environments/__init__.py +49 -13
- kaggle_environments/agent.py +177 -124
- kaggle_environments/api.py +31 -0
- kaggle_environments/core.py +298 -173
- 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} +22 -15
- 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 +214 -50
- kaggle_environments/schemas.json +23 -18
- kaggle_environments/static/player.html +206 -74
- kaggle_environments/utils.py +46 -73
- kaggle_environments-1.20.0.dist-info/METADATA +25 -0
- kaggle_environments-1.20.0.dist-info/RECORD +211 -0
- {kaggle_environments-0.2.0.dist-info → kaggle_environments-1.20.0.dist-info}/WHEEL +1 -2
- kaggle_environments-1.20.0.dist-info/entry_points.txt +3 -0
- kaggle_environments/envs/battlegeese/battlegeese.py +0 -219
- kaggle_environments/temp.py +0 -14
- kaggle_environments-0.2.0.dist-info/METADATA +0 -393
- kaggle_environments-0.2.0.dist-info/RECORD +0 -33
- kaggle_environments-0.2.0.dist-info/entry_points.txt +0 -3
- kaggle_environments-0.2.0.dist-info/top_level.txt +0 -1
- {kaggle_environments-0.2.0.dist-info → kaggle_environments-1.20.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
// Go Board Renderer for OpenSpiel
|
|
2
|
+
function renderer(options) {
|
|
3
|
+
const { environment, step, parent, interactive, isInteractive, maxBoardSize = 800 } = options;
|
|
4
|
+
|
|
5
|
+
// --- Constants ---
|
|
6
|
+
const DEFAULT_BOARD_SIZE = 19;
|
|
7
|
+
const STONE_COLORS = {
|
|
8
|
+
'B': '#2d3748', // Black stone
|
|
9
|
+
'W': '#f7fafc', // White stone with slight gray tint
|
|
10
|
+
'.': 'transparent' // Empty intersection
|
|
11
|
+
};
|
|
12
|
+
const BOARD_COLOR = '#dcb871'; // Traditional Go board wood color
|
|
13
|
+
const LINE_COLOR = '#8b4513'; // Dark brown for grid lines
|
|
14
|
+
const STAR_POINT_COLOR = '#654321'; // Darker brown for star points
|
|
15
|
+
const LABEL_COLOR = '#2d3748';
|
|
16
|
+
|
|
17
|
+
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
18
|
+
|
|
19
|
+
// Dynamic sizing based on board size
|
|
20
|
+
function getBoardConfig(boardSize) {
|
|
21
|
+
let intersectionSize, margin, fontSize;
|
|
22
|
+
|
|
23
|
+
if (boardSize <= 9) {
|
|
24
|
+
intersectionSize = 35;
|
|
25
|
+
margin = 45;
|
|
26
|
+
fontSize = 14;
|
|
27
|
+
} else if (boardSize <= 13) {
|
|
28
|
+
intersectionSize = 30;
|
|
29
|
+
margin = 40;
|
|
30
|
+
fontSize = 13;
|
|
31
|
+
} else {
|
|
32
|
+
intersectionSize = 25;
|
|
33
|
+
margin = 35;
|
|
34
|
+
fontSize = 12;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { intersectionSize, margin, fontSize };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Go column labels (A-T, omitting I)
|
|
41
|
+
const COLUMN_LABELS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'];
|
|
42
|
+
|
|
43
|
+
let currentBoardSvgElement = null;
|
|
44
|
+
let currentStatusTextElement = null;
|
|
45
|
+
let currentWinnerTextElement = null;
|
|
46
|
+
let currentMessageBoxElement = typeof document !== 'undefined' ? document.getElementById('messageBox') : null;
|
|
47
|
+
let currentRendererContainer = null;
|
|
48
|
+
let currentTitleElement = null;
|
|
49
|
+
|
|
50
|
+
function _showMessage(message, type = 'info', duration = 3000) {
|
|
51
|
+
if (typeof document === 'undefined' || !document.body) return;
|
|
52
|
+
if (!currentMessageBoxElement) {
|
|
53
|
+
currentMessageBoxElement = document.createElement('div');
|
|
54
|
+
currentMessageBoxElement.id = 'messageBox';
|
|
55
|
+
currentMessageBoxElement.style.position = 'fixed';
|
|
56
|
+
currentMessageBoxElement.style.top = '10px';
|
|
57
|
+
currentMessageBoxElement.style.left = '50%';
|
|
58
|
+
currentMessageBoxElement.style.transform = 'translateX(-50%)';
|
|
59
|
+
currentMessageBoxElement.style.padding = '0.75rem 1rem';
|
|
60
|
+
currentMessageBoxElement.style.borderRadius = '0.375rem';
|
|
61
|
+
currentMessageBoxElement.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
|
|
62
|
+
currentMessageBoxElement.style.zIndex = '1000';
|
|
63
|
+
currentMessageBoxElement.style.opacity = '0';
|
|
64
|
+
currentMessageBoxElement.style.transition = 'opacity 0.3s ease-in-out, background-color 0.3s';
|
|
65
|
+
currentMessageBoxElement.style.fontSize = '0.875rem';
|
|
66
|
+
currentMessageBoxElement.style.fontFamily = "'Inter', sans-serif";
|
|
67
|
+
document.body.appendChild(currentMessageBoxElement);
|
|
68
|
+
}
|
|
69
|
+
currentMessageBoxElement.textContent = message;
|
|
70
|
+
currentMessageBoxElement.style.backgroundColor = type === 'error' ? '#ef4444' : '#10b981';
|
|
71
|
+
currentMessageBoxElement.style.color = 'white';
|
|
72
|
+
currentMessageBoxElement.style.opacity = '1';
|
|
73
|
+
setTimeout(() => { if (currentMessageBoxElement) currentMessageBoxElement.style.opacity = '0'; }, duration);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function _getStarPoints(boardSize) {
|
|
77
|
+
// Star points for different board sizes
|
|
78
|
+
const starPointsMap = {
|
|
79
|
+
9: [[2, 2], [2, 6], [4, 4], [6, 2], [6, 6]],
|
|
80
|
+
13: [[3, 3], [3, 9], [6, 6], [9, 3], [9, 9]],
|
|
81
|
+
19: [[3, 3], [3, 9], [3, 15], [9, 3], [9, 9], [9, 15], [15, 3], [15, 9], [15, 15]]
|
|
82
|
+
};
|
|
83
|
+
return starPointsMap[boardSize] || [];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _ensureRendererElements(parentElementToClear, boardSize) {
|
|
87
|
+
if (!parentElementToClear) return false;
|
|
88
|
+
parentElementToClear.innerHTML = '';
|
|
89
|
+
|
|
90
|
+
const config = getBoardConfig(boardSize);
|
|
91
|
+
const { intersectionSize, margin, fontSize } = config;
|
|
92
|
+
|
|
93
|
+
currentRendererContainer = document.createElement('div');
|
|
94
|
+
currentRendererContainer.style.display = 'flex';
|
|
95
|
+
currentRendererContainer.style.flexDirection = 'column';
|
|
96
|
+
currentRendererContainer.style.alignItems = 'center';
|
|
97
|
+
currentRendererContainer.style.padding = '20px';
|
|
98
|
+
currentRendererContainer.style.boxSizing = 'border-box';
|
|
99
|
+
currentRendererContainer.style.width = '100%';
|
|
100
|
+
currentRendererContainer.style.height = '100%';
|
|
101
|
+
currentRendererContainer.style.fontFamily = "'Inter', sans-serif";
|
|
102
|
+
|
|
103
|
+
currentTitleElement = document.createElement('h1');
|
|
104
|
+
currentTitleElement.textContent = `Go (${boardSize}×${boardSize})`;
|
|
105
|
+
currentTitleElement.style.fontSize = '1.875rem';
|
|
106
|
+
currentTitleElement.style.fontWeight = 'bold';
|
|
107
|
+
currentTitleElement.style.marginBottom = '1rem';
|
|
108
|
+
currentTitleElement.style.textAlign = 'center';
|
|
109
|
+
currentTitleElement.style.color = '#2563eb';
|
|
110
|
+
currentRendererContainer.appendChild(currentTitleElement);
|
|
111
|
+
|
|
112
|
+
// Calculate SVG dimensions
|
|
113
|
+
const boardPixelSize = (boardSize - 1) * intersectionSize;
|
|
114
|
+
const svgWidth = boardPixelSize + (2 * margin);
|
|
115
|
+
const svgHeight = boardPixelSize + (2 * margin);
|
|
116
|
+
|
|
117
|
+
currentBoardSvgElement = document.createElementNS(SVG_NS, "svg");
|
|
118
|
+
currentBoardSvgElement.setAttribute("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
|
119
|
+
currentBoardSvgElement.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
120
|
+
currentBoardSvgElement.style.width = "auto";
|
|
121
|
+
currentBoardSvgElement.style.maxWidth = `${maxBoardSize}px`;
|
|
122
|
+
currentBoardSvgElement.style.maxHeight = `${maxBoardSize}px`;
|
|
123
|
+
currentBoardSvgElement.style.aspectRatio = "1 / 1";
|
|
124
|
+
currentBoardSvgElement.style.display = "block";
|
|
125
|
+
currentBoardSvgElement.style.margin = "0 auto 20px auto";
|
|
126
|
+
|
|
127
|
+
// Board background
|
|
128
|
+
const boardBgRect = document.createElementNS(SVG_NS, "rect");
|
|
129
|
+
boardBgRect.setAttribute("x", "0");
|
|
130
|
+
boardBgRect.setAttribute("y", "0");
|
|
131
|
+
boardBgRect.setAttribute("width", svgWidth.toString());
|
|
132
|
+
boardBgRect.setAttribute("height", svgHeight.toString());
|
|
133
|
+
boardBgRect.setAttribute("fill", BOARD_COLOR);
|
|
134
|
+
boardBgRect.setAttribute("rx", "8");
|
|
135
|
+
currentBoardSvgElement.appendChild(boardBgRect);
|
|
136
|
+
|
|
137
|
+
// Grid lines
|
|
138
|
+
for (let i = 0; i < boardSize; i++) {
|
|
139
|
+
const x = margin + i * intersectionSize;
|
|
140
|
+
const y = margin + i * intersectionSize;
|
|
141
|
+
|
|
142
|
+
// Vertical lines
|
|
143
|
+
const vLine = document.createElementNS(SVG_NS, "line");
|
|
144
|
+
vLine.setAttribute("x1", x.toString());
|
|
145
|
+
vLine.setAttribute("y1", margin.toString());
|
|
146
|
+
vLine.setAttribute("x2", x.toString());
|
|
147
|
+
vLine.setAttribute("y2", (margin + boardPixelSize).toString());
|
|
148
|
+
vLine.setAttribute("stroke", LINE_COLOR);
|
|
149
|
+
vLine.setAttribute("stroke-width", "1");
|
|
150
|
+
currentBoardSvgElement.appendChild(vLine);
|
|
151
|
+
|
|
152
|
+
// Horizontal lines
|
|
153
|
+
const hLine = document.createElementNS(SVG_NS, "line");
|
|
154
|
+
hLine.setAttribute("x1", margin.toString());
|
|
155
|
+
hLine.setAttribute("y1", y.toString());
|
|
156
|
+
hLine.setAttribute("x2", (margin + boardPixelSize).toString());
|
|
157
|
+
hLine.setAttribute("y2", y.toString());
|
|
158
|
+
hLine.setAttribute("stroke", LINE_COLOR);
|
|
159
|
+
hLine.setAttribute("stroke-width", "1");
|
|
160
|
+
currentBoardSvgElement.appendChild(hLine);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Star points
|
|
164
|
+
const starPoints = _getStarPoints(boardSize);
|
|
165
|
+
starPoints.forEach(([row, col]) => {
|
|
166
|
+
const x = margin + col * intersectionSize;
|
|
167
|
+
const y = margin + row * intersectionSize;
|
|
168
|
+
const starPoint = document.createElementNS(SVG_NS, "circle");
|
|
169
|
+
starPoint.setAttribute("cx", x.toString());
|
|
170
|
+
starPoint.setAttribute("cy", y.toString());
|
|
171
|
+
starPoint.setAttribute("r", "3");
|
|
172
|
+
starPoint.setAttribute("fill", STAR_POINT_COLOR);
|
|
173
|
+
currentBoardSvgElement.appendChild(starPoint);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Coordinate labels
|
|
177
|
+
const labelOffset = Math.max(15, margin * 0.6);
|
|
178
|
+
|
|
179
|
+
for (let i = 0; i < boardSize; i++) {
|
|
180
|
+
// Column labels (top and bottom)
|
|
181
|
+
if (i < COLUMN_LABELS.length) {
|
|
182
|
+
const x = margin + i * intersectionSize;
|
|
183
|
+
|
|
184
|
+
// Top labels
|
|
185
|
+
const topLabel = document.createElementNS(SVG_NS, "text");
|
|
186
|
+
topLabel.setAttribute("x", x.toString());
|
|
187
|
+
topLabel.setAttribute("y", labelOffset.toString());
|
|
188
|
+
topLabel.setAttribute("text-anchor", "middle");
|
|
189
|
+
topLabel.setAttribute("dominant-baseline", "middle");
|
|
190
|
+
topLabel.setAttribute("font-family", "Arial, sans-serif");
|
|
191
|
+
topLabel.setAttribute("font-size", fontSize.toString());
|
|
192
|
+
topLabel.setAttribute("fill", LABEL_COLOR);
|
|
193
|
+
topLabel.textContent = COLUMN_LABELS[i];
|
|
194
|
+
currentBoardSvgElement.appendChild(topLabel);
|
|
195
|
+
|
|
196
|
+
// Bottom labels
|
|
197
|
+
const bottomLabel = document.createElementNS(SVG_NS, "text");
|
|
198
|
+
bottomLabel.setAttribute("x", x.toString());
|
|
199
|
+
bottomLabel.setAttribute("y", (svgHeight - labelOffset + 5).toString());
|
|
200
|
+
bottomLabel.setAttribute("text-anchor", "middle");
|
|
201
|
+
bottomLabel.setAttribute("dominant-baseline", "middle");
|
|
202
|
+
bottomLabel.setAttribute("font-family", "Arial, sans-serif");
|
|
203
|
+
bottomLabel.setAttribute("font-size", fontSize.toString());
|
|
204
|
+
bottomLabel.setAttribute("fill", LABEL_COLOR);
|
|
205
|
+
bottomLabel.textContent = COLUMN_LABELS[i];
|
|
206
|
+
currentBoardSvgElement.appendChild(bottomLabel);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Row labels (left and right) - Go rows are numbered from bottom to top
|
|
210
|
+
const rowNumber = boardSize - i;
|
|
211
|
+
const y = margin + i * intersectionSize;
|
|
212
|
+
|
|
213
|
+
// Left labels
|
|
214
|
+
const leftLabel = document.createElementNS(SVG_NS, "text");
|
|
215
|
+
leftLabel.setAttribute("x", labelOffset.toString());
|
|
216
|
+
leftLabel.setAttribute("y", y.toString());
|
|
217
|
+
leftLabel.setAttribute("text-anchor", "middle");
|
|
218
|
+
leftLabel.setAttribute("dominant-baseline", "middle");
|
|
219
|
+
leftLabel.setAttribute("font-family", "Arial, sans-serif");
|
|
220
|
+
leftLabel.setAttribute("font-size", fontSize.toString());
|
|
221
|
+
leftLabel.setAttribute("fill", LABEL_COLOR);
|
|
222
|
+
leftLabel.textContent = rowNumber.toString();
|
|
223
|
+
currentBoardSvgElement.appendChild(leftLabel);
|
|
224
|
+
|
|
225
|
+
// Right labels
|
|
226
|
+
const rightLabel = document.createElementNS(SVG_NS, "text");
|
|
227
|
+
rightLabel.setAttribute("x", (svgWidth - labelOffset).toString());
|
|
228
|
+
rightLabel.setAttribute("y", y.toString());
|
|
229
|
+
rightLabel.setAttribute("text-anchor", "middle");
|
|
230
|
+
rightLabel.setAttribute("dominant-baseline", "middle");
|
|
231
|
+
rightLabel.setAttribute("font-family", "Arial, sans-serif");
|
|
232
|
+
rightLabel.setAttribute("font-size", fontSize.toString());
|
|
233
|
+
rightLabel.setAttribute("fill", LABEL_COLOR);
|
|
234
|
+
rightLabel.textContent = rowNumber.toString();
|
|
235
|
+
currentBoardSvgElement.appendChild(rightLabel);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Create intersection circles for stones
|
|
239
|
+
const stoneRadius = Math.max(8, intersectionSize * 0.4);
|
|
240
|
+
|
|
241
|
+
for (let row = 0; row < boardSize; row++) {
|
|
242
|
+
for (let col = 0; col < boardSize; col++) {
|
|
243
|
+
const x = margin + col * intersectionSize;
|
|
244
|
+
const y = margin + row * intersectionSize;
|
|
245
|
+
const stone = document.createElementNS(SVG_NS, "circle");
|
|
246
|
+
stone.setAttribute("id", `stone-${row}-${col}`);
|
|
247
|
+
stone.setAttribute("cx", x.toString());
|
|
248
|
+
stone.setAttribute("cy", y.toString());
|
|
249
|
+
stone.setAttribute("r", stoneRadius.toString());
|
|
250
|
+
stone.setAttribute("fill", "transparent");
|
|
251
|
+
stone.setAttribute("stroke", "none");
|
|
252
|
+
currentBoardSvgElement.appendChild(stone);
|
|
253
|
+
|
|
254
|
+
// Create a smaller circle for indicating the most recent move
|
|
255
|
+
const recentMoveRadius = Math.max(3, stoneRadius * 0.55);
|
|
256
|
+
const recentMoveIndicator = document.createElementNS(SVG_NS, "circle");
|
|
257
|
+
recentMoveIndicator.setAttribute("id", `recent-move-${row}-${col}`);
|
|
258
|
+
recentMoveIndicator.setAttribute("cx", x.toString());
|
|
259
|
+
recentMoveIndicator.setAttribute("cy", y.toString());
|
|
260
|
+
recentMoveIndicator.setAttribute("r", recentMoveRadius.toString());
|
|
261
|
+
recentMoveIndicator.setAttribute("fill", "transparent");
|
|
262
|
+
recentMoveIndicator.setAttribute("stroke", "none");
|
|
263
|
+
currentBoardSvgElement.appendChild(recentMoveIndicator);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
currentRendererContainer.appendChild(currentBoardSvgElement);
|
|
268
|
+
|
|
269
|
+
const statusContainer = document.createElement('div');
|
|
270
|
+
statusContainer.style.padding = '10px 15px';
|
|
271
|
+
statusContainer.style.backgroundColor = 'white';
|
|
272
|
+
statusContainer.style.borderRadius = '8px';
|
|
273
|
+
statusContainer.style.boxShadow = '0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06)';
|
|
274
|
+
statusContainer.style.textAlign = 'center';
|
|
275
|
+
statusContainer.style.width = 'auto';
|
|
276
|
+
statusContainer.style.minWidth = '200px';
|
|
277
|
+
statusContainer.style.maxWidth = '90vw';
|
|
278
|
+
currentRendererContainer.appendChild(statusContainer);
|
|
279
|
+
|
|
280
|
+
currentStatusTextElement = document.createElement('p');
|
|
281
|
+
currentStatusTextElement.style.fontSize = '1.1rem';
|
|
282
|
+
currentStatusTextElement.style.fontWeight = '600';
|
|
283
|
+
currentStatusTextElement.style.margin = '0 0 5px 0';
|
|
284
|
+
statusContainer.appendChild(currentStatusTextElement);
|
|
285
|
+
|
|
286
|
+
currentWinnerTextElement = document.createElement('p');
|
|
287
|
+
currentWinnerTextElement.style.fontSize = '1.25rem';
|
|
288
|
+
currentWinnerTextElement.style.fontWeight = '700';
|
|
289
|
+
currentWinnerTextElement.style.margin = '5px 0 0 0';
|
|
290
|
+
statusContainer.appendChild(currentWinnerTextElement);
|
|
291
|
+
|
|
292
|
+
parentElementToClear.appendChild(currentRendererContainer);
|
|
293
|
+
|
|
294
|
+
if (typeof document !== 'undefined' && !document.body.hasAttribute('data-renderer-initialized')) {
|
|
295
|
+
_showMessage("Go Renderer initialized.", "info", 1500);
|
|
296
|
+
document.body.setAttribute('data-renderer-initialized', 'true');
|
|
297
|
+
}
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function _renderBoardDisplay_svg(gameStateToDisplay, boardSize) {
|
|
302
|
+
if (!currentBoardSvgElement || !currentStatusTextElement || !currentWinnerTextElement) return;
|
|
303
|
+
|
|
304
|
+
// Clear all stones and recent move indicators first
|
|
305
|
+
for (let row = 0; row < boardSize; row++) {
|
|
306
|
+
for (let col = 0; col < boardSize; col++) {
|
|
307
|
+
const stoneElement = currentBoardSvgElement.querySelector(`#stone-${row}-${col}`);
|
|
308
|
+
if (stoneElement) {
|
|
309
|
+
stoneElement.setAttribute("fill", "transparent");
|
|
310
|
+
stoneElement.setAttribute("stroke", "none");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const recentMoveElement = currentBoardSvgElement.querySelector(`#recent-move-${row}-${col}`);
|
|
314
|
+
if (recentMoveElement) {
|
|
315
|
+
recentMoveElement.setAttribute("fill", "transparent");
|
|
316
|
+
recentMoveElement.setAttribute("stroke", "none");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!gameStateToDisplay || !gameStateToDisplay.board_grid) {
|
|
322
|
+
currentStatusTextElement.textContent = "Waiting for game data...";
|
|
323
|
+
currentWinnerTextElement.textContent = "";
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const { board_grid, current_player_to_move, move_number, komi, previous_move_a1 } = gameStateToDisplay;
|
|
328
|
+
|
|
329
|
+
// Render stones on the board
|
|
330
|
+
// board_grid[0] is the top row (row 9 in a 9x9 board), board_grid[8] is bottom row (row 1)
|
|
331
|
+
for (let gridRow = 0; gridRow < board_grid.length && gridRow < boardSize; gridRow++) {
|
|
332
|
+
const rowData = board_grid[gridRow];
|
|
333
|
+
if (!Array.isArray(rowData)) continue;
|
|
334
|
+
|
|
335
|
+
for (let gridCol = 0; gridCol < rowData.length && gridCol < boardSize; gridCol++) {
|
|
336
|
+
const intersection = rowData[gridCol];
|
|
337
|
+
if (!intersection || typeof intersection !== 'object') continue;
|
|
338
|
+
|
|
339
|
+
// Extract the stone state from the intersection dictionary
|
|
340
|
+
const coordinate = Object.keys(intersection)[0];
|
|
341
|
+
const stoneState = intersection[coordinate];
|
|
342
|
+
|
|
343
|
+
if (stoneState && (stoneState === 'B' || stoneState === 'W')) {
|
|
344
|
+
const stoneElement = currentBoardSvgElement.querySelector(`#stone-${gridRow}-${gridCol}`);
|
|
345
|
+
if (stoneElement) {
|
|
346
|
+
stoneElement.setAttribute("fill", STONE_COLORS[stoneState]);
|
|
347
|
+
stoneElement.setAttribute("stroke", stoneState === 'W' ? '#666' : 'none');
|
|
348
|
+
stoneElement.setAttribute("stroke-width", stoneState === 'W' ? "1" : "0");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Highlight the most recent move if available
|
|
355
|
+
if (previous_move_a1) {
|
|
356
|
+
// Parse the coordinate (e.g., "F4" -> column F, row 4)
|
|
357
|
+
const colLetter = previous_move_a1[0];
|
|
358
|
+
const rowNumber = parseInt(previous_move_a1.slice(1));
|
|
359
|
+
|
|
360
|
+
// Convert to array indices
|
|
361
|
+
const COLUMN_LABELS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'];
|
|
362
|
+
const colIndex = COLUMN_LABELS.indexOf(colLetter);
|
|
363
|
+
const rowIndex = boardSize - rowNumber; // Convert Go row numbering to array index
|
|
364
|
+
|
|
365
|
+
if (rowIndex >= 0 && rowIndex < boardSize && colIndex >= 0 && colIndex < boardSize) {
|
|
366
|
+
const recentMoveElement = currentBoardSvgElement.querySelector(`#recent-move-${rowIndex}-${colIndex}`);
|
|
367
|
+
const stoneElement = currentBoardSvgElement.querySelector(`#stone-${rowIndex}-${colIndex}`);
|
|
368
|
+
|
|
369
|
+
if (recentMoveElement && stoneElement) {
|
|
370
|
+
// Get the color of the stone at this position to determine the indicator color
|
|
371
|
+
const stoneFill = stoneElement.getAttribute("fill");
|
|
372
|
+
|
|
373
|
+
if (stoneFill === STONE_COLORS['B']) {
|
|
374
|
+
// Black stone - use white circle outline
|
|
375
|
+
recentMoveElement.setAttribute("fill", "transparent");
|
|
376
|
+
recentMoveElement.setAttribute("stroke", STONE_COLORS['W']);
|
|
377
|
+
recentMoveElement.setAttribute("stroke-width", "1.25");
|
|
378
|
+
} else if (stoneFill === STONE_COLORS['W']) {
|
|
379
|
+
// White stone - use black circle outline
|
|
380
|
+
recentMoveElement.setAttribute("fill", "transparent");
|
|
381
|
+
recentMoveElement.setAttribute("stroke", STONE_COLORS['B']);
|
|
382
|
+
recentMoveElement.setAttribute("stroke-width", "1.25");
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Update status display
|
|
389
|
+
const playerColor = current_player_to_move === 'B' ? '#2d3748' : '#f7fafc';
|
|
390
|
+
const playerName = current_player_to_move === 'B' ? 'Black' : 'White';
|
|
391
|
+
|
|
392
|
+
currentStatusTextElement.innerHTML = `Move ${move_number || 1}: <span style="color: ${playerColor}; font-weight: bold; ${current_player_to_move === 'W' ? 'text-shadow: 1px 1px 2px rgba(0,0,0,0.3);' : ''}">${playerName}</span> to play`;
|
|
393
|
+
|
|
394
|
+
if (previous_move_a1) {
|
|
395
|
+
currentWinnerTextElement.textContent = `Last move: ${previous_move_a1}${komi ? ` • Komi: ${komi}` : ''}`;
|
|
396
|
+
} else {
|
|
397
|
+
currentWinnerTextElement.textContent = komi ? `Komi: ${komi}` : '';
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// --- Main execution logic ---
|
|
402
|
+
let boardSize = DEFAULT_BOARD_SIZE;
|
|
403
|
+
|
|
404
|
+
// Try to extract board size from game state
|
|
405
|
+
if (environment && environment.steps && environment.steps[step]) {
|
|
406
|
+
const currentStepAgents = environment.steps[step];
|
|
407
|
+
if (Array.isArray(currentStepAgents) && currentStepAgents.length > 0) {
|
|
408
|
+
const gameMasterAgent = currentStepAgents[currentStepAgents.length - 1];
|
|
409
|
+
if (gameMasterAgent && gameMasterAgent.observation) {
|
|
410
|
+
let gameState = null;
|
|
411
|
+
|
|
412
|
+
// Try to parse game state from observation
|
|
413
|
+
if (gameMasterAgent.observation.observationString) {
|
|
414
|
+
try {
|
|
415
|
+
gameState = JSON.parse(gameMasterAgent.observation.observationString);
|
|
416
|
+
} catch (e) {}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (!gameState && gameMasterAgent.observation.json) {
|
|
420
|
+
try {
|
|
421
|
+
gameState = JSON.parse(gameMasterAgent.observation.json);
|
|
422
|
+
} catch (e) {}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (gameState && gameState.board_size) {
|
|
426
|
+
boardSize = gameState.board_size;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (!_ensureRendererElements(parent, boardSize)) {
|
|
433
|
+
if (parent && typeof parent.innerHTML !== 'undefined') {
|
|
434
|
+
parent.innerHTML = "<p style='color:red; font-family: sans-serif;'>Critical Error: Renderer element setup failed.</p>";
|
|
435
|
+
}
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (!environment || !environment.steps || !environment.steps[step]) {
|
|
440
|
+
_renderBoardDisplay_svg(null, boardSize);
|
|
441
|
+
if(currentStatusTextElement) currentStatusTextElement.textContent = "Initializing environment...";
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const currentStepAgents = environment.steps[step];
|
|
446
|
+
if (!currentStepAgents || !Array.isArray(currentStepAgents) || currentStepAgents.length === 0) {
|
|
447
|
+
_renderBoardDisplay_svg(null, boardSize);
|
|
448
|
+
if(currentStatusTextElement) currentStatusTextElement.textContent = "Waiting for agent data...";
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const gameMasterAgentIndex = currentStepAgents.length - 1;
|
|
453
|
+
const gameMasterAgent = currentStepAgents[gameMasterAgentIndex];
|
|
454
|
+
|
|
455
|
+
if (!gameMasterAgent || typeof gameMasterAgent.observation === 'undefined') {
|
|
456
|
+
_renderBoardDisplay_svg(null, boardSize);
|
|
457
|
+
if(currentStatusTextElement) currentStatusTextElement.textContent = "Waiting for observation data...";
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const observationForRenderer = gameMasterAgent.observation;
|
|
462
|
+
let gameSpecificState = null;
|
|
463
|
+
|
|
464
|
+
if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
|
|
465
|
+
try {
|
|
466
|
+
gameSpecificState = JSON.parse(observationForRenderer.observationString);
|
|
467
|
+
} catch (e) {
|
|
468
|
+
_showMessage("Error: Corrupted game state (obs_string).", 'error');
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (!gameSpecificState && observationForRenderer && typeof observationForRenderer.json === 'string' && observationForRenderer.json.trim() !== '') {
|
|
473
|
+
try {
|
|
474
|
+
gameSpecificState = JSON.parse(observationForRenderer.json);
|
|
475
|
+
} catch (e) {
|
|
476
|
+
_showMessage("Error: Corrupted game state (json).", 'error');
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
_renderBoardDisplay_svg(gameSpecificState, boardSize);
|
|
481
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Change Go state and action string representations."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import pyspiel
|
|
7
|
+
|
|
8
|
+
from ... import proxy
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GoState(proxy.State):
|
|
12
|
+
"""Go state proxy."""
|
|
13
|
+
|
|
14
|
+
def _player_string(self, player: int) -> str:
|
|
15
|
+
if player < 0:
|
|
16
|
+
return pyspiel.PlayerId(player).name.lower()
|
|
17
|
+
elif player == 0:
|
|
18
|
+
return "B"
|
|
19
|
+
elif player == 1:
|
|
20
|
+
return "W"
|
|
21
|
+
else:
|
|
22
|
+
raise ValueError(f"Invalid player: {player}")
|
|
23
|
+
|
|
24
|
+
def _board_string_to_dict(self, board_string: str) -> dict:
|
|
25
|
+
lines = board_string.strip().splitlines()
|
|
26
|
+
if len(lines) < 3:
|
|
27
|
+
raise ValueError("Input string is too short to be a valid board.")
|
|
28
|
+
# The last line contains the column labels (e.g., "ABC...")
|
|
29
|
+
column_labels = lines[-1].strip()
|
|
30
|
+
board_rows = lines[2:-1]
|
|
31
|
+
board_size = len(column_labels)
|
|
32
|
+
if len(board_rows) != board_size:
|
|
33
|
+
raise ValueError(f"Board dimension mismatch: {len(column_labels)} columns but {len(board_rows)} rows.")
|
|
34
|
+
grid = []
|
|
35
|
+
symbol_map = {"+": ".", "X": "B", "O": "W"}
|
|
36
|
+
for i, row_line in enumerate(board_rows):
|
|
37
|
+
row_number = board_size - i
|
|
38
|
+
try:
|
|
39
|
+
board_content = row_line.split(maxsplit=1)[1]
|
|
40
|
+
except IndexError:
|
|
41
|
+
raise ValueError(f"Malformed board row: '{row_line}'")
|
|
42
|
+
current_row_list = []
|
|
43
|
+
for j, stone_char in enumerate(board_content):
|
|
44
|
+
col_letter = column_labels[j]
|
|
45
|
+
coordinate = f"{col_letter}{row_number}"
|
|
46
|
+
# TODO
|
|
47
|
+
point_dict = {coordinate: symbol_map.get(stone_char, "?")}
|
|
48
|
+
current_row_list.append(point_dict)
|
|
49
|
+
grid.append(current_row_list)
|
|
50
|
+
return grid
|
|
51
|
+
|
|
52
|
+
def state_dict(self) -> dict[str, Any]:
|
|
53
|
+
clone_state = self.get_game().__wrapped__.new_initial_state()
|
|
54
|
+
action_strs = []
|
|
55
|
+
for action in self.history():
|
|
56
|
+
action_strs.append(clone_state.action_to_string(action))
|
|
57
|
+
clone_state.apply_action(action)
|
|
58
|
+
prev_move = None if not action_strs else action_strs[-1]
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
"board_size": self.get_game().get_parameters()["board_size"],
|
|
62
|
+
"komi": self.get_game().get_parameters()["komi"],
|
|
63
|
+
"current_player_to_move": self._player_string(self.current_player()),
|
|
64
|
+
"move_number": len(self.history()) + 1,
|
|
65
|
+
"previous_move_a1": prev_move,
|
|
66
|
+
"board_grid": self._board_string_to_dict(self.__wrapped__.__str__()),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def to_json(self) -> str:
|
|
70
|
+
return json.dumps(self.state_dict())
|
|
71
|
+
|
|
72
|
+
def observation_string(self, player: int) -> str:
|
|
73
|
+
return self.observation_json(player)
|
|
74
|
+
|
|
75
|
+
def observation_json(self, player: int) -> str:
|
|
76
|
+
del player
|
|
77
|
+
return self.to_json()
|
|
78
|
+
|
|
79
|
+
def __str__(self):
|
|
80
|
+
return self.to_json()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class GoGame(proxy.Game):
|
|
84
|
+
"""Go game proxy."""
|
|
85
|
+
|
|
86
|
+
def __init__(self, params: Any | None = None):
|
|
87
|
+
params = params or {}
|
|
88
|
+
wrapped = pyspiel.load_game("go", params)
|
|
89
|
+
super().__init__(
|
|
90
|
+
wrapped,
|
|
91
|
+
short_name="go_proxy",
|
|
92
|
+
long_name="Go (proxy)",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def new_initial_state(self, *args) -> GoState:
|
|
96
|
+
return GoState(self.__wrapped__.new_initial_state(*args), game=self)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
pyspiel.register_game(GoGame().get_type(), GoGame)
|
|
File without changes
|