kaggle-environments 1.17.5__py2.py3-none-any.whl → 1.17.7__py2.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 +1 -1
- kaggle_environments/core.py +1 -1
- kaggle_environments/envs/chess/chess.js +27 -23
- kaggle_environments/envs/open_spiel/games/chess/chess.js +34 -27
- kaggle_environments/envs/open_spiel/games/connect_four/connect_four.js +2 -14
- kaggle_environments/envs/open_spiel/games/go/go.js +4 -4
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe.js +6 -6
- kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker.js +2 -2
- kaggle_environments/envs/open_spiel/open_spiel.py +125 -61
- kaggle_environments/envs/open_spiel/test_open_spiel.py +66 -3
- kaggle_environments/static/player.html +50 -13
- {kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/METADATA +1 -1
- {kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/RECORD +17 -17
- {kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/WHEEL +1 -1
- {kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/entry_points.txt +0 -0
- {kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/licenses/LICENSE +0 -0
- {kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/top_level.txt +0 -0
kaggle_environments/__init__.py
CHANGED
kaggle_environments/core.py
CHANGED
|
@@ -579,7 +579,7 @@ class Environment:
|
|
|
579
579
|
try:
|
|
580
580
|
with StringIO() as out_buffer, StringIO() as err_buffer, redirect_stdout(out_buffer), redirect_stderr(err_buffer):
|
|
581
581
|
try:
|
|
582
|
-
args = [structify(state), self]
|
|
582
|
+
args = [structify(state), self, logs]
|
|
583
583
|
new_state = structify(self.interpreter(
|
|
584
584
|
*args[:self.interpreter.__code__.co_argcount]))
|
|
585
585
|
new_state[0].observation.step = (
|
|
@@ -4045,14 +4045,14 @@ async function renderer(context) {
|
|
|
4045
4045
|
|
|
4046
4046
|
// Create the Download PGN button
|
|
4047
4047
|
let downloadButton = parent.querySelector("#copy-pgn");
|
|
4048
|
-
if (!downloadButton) {
|
|
4048
|
+
if (!downloadButton && environment.steps.length) {
|
|
4049
4049
|
try {
|
|
4050
4050
|
const board = environment.steps[0][0].observation.board;
|
|
4051
4051
|
const info = environment.info;
|
|
4052
4052
|
const agent1 = info?.TeamNames?.[0] || "Agent 1";
|
|
4053
4053
|
const agent2 = info?.TeamNames?.[1] || "Agent 2";
|
|
4054
4054
|
const game = new Chess();
|
|
4055
|
-
let result = environment.rewards;
|
|
4055
|
+
let result = environment.rewards ?? [];
|
|
4056
4056
|
if (result.some((r) => r === undefined || r === null)) {
|
|
4057
4057
|
result = result.map((r) => (r === undefined || r === null ? 0 : 1));
|
|
4058
4058
|
}
|
|
@@ -4103,7 +4103,9 @@ async function renderer(context) {
|
|
|
4103
4103
|
downloadButton.style.top = "10px";
|
|
4104
4104
|
downloadButton.style.left = "10px";
|
|
4105
4105
|
downloadButton.style.zIndex = 1;
|
|
4106
|
-
|
|
4106
|
+
if(!environment.viewer) {
|
|
4107
|
+
parent.appendChild(downloadButton);
|
|
4108
|
+
}
|
|
4107
4109
|
|
|
4108
4110
|
downloadButton.addEventListener("click", async () => {
|
|
4109
4111
|
try {
|
|
@@ -4179,26 +4181,28 @@ async function renderer(context) {
|
|
|
4179
4181
|
}
|
|
4180
4182
|
}
|
|
4181
4183
|
// Draw the team names and game status
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4184
|
+
if (!environment.viewer) {
|
|
4185
|
+
const info = environment.info;
|
|
4186
|
+
const agent1 = info?.TeamNames?.[0] || "Agent 1";
|
|
4187
|
+
const agent2 = info?.TeamNames?.[1] || "Agent 2";
|
|
4188
|
+
const firstGame = environment.steps[step][0].observation.mark == "white";
|
|
4189
|
+
const fontSize = Math.round(0.33 * offset);
|
|
4190
|
+
c.font = `${fontSize}px sans-serif`;
|
|
4191
|
+
c.fillStyle = "#FFFFFF";
|
|
4192
|
+
const agent1Reward = environment.steps[step][0].reward;
|
|
4193
|
+
const agent2Reward = environment.steps[step][1].reward;
|
|
4194
|
+
const charCount = agent1.length + agent2.length + 12;
|
|
4195
|
+
const title = `${
|
|
4196
|
+
firstGame ? "\u25A0" : "\u25A1"
|
|
4197
|
+
}${agent1} (${agent1Reward}) vs ${
|
|
4198
|
+
firstGame ? "\u25A1" : "\u25A0"
|
|
4199
|
+
}${agent2} (${agent2Reward})`;
|
|
4200
|
+
c.fillText(
|
|
4201
|
+
title,
|
|
4202
|
+
offset + 4 * squareSize - Math.floor((charCount * fontSize) / 4),
|
|
4203
|
+
40
|
|
4204
|
+
);
|
|
4205
|
+
}
|
|
4202
4206
|
|
|
4203
4207
|
// Draw the Pieces
|
|
4204
4208
|
const board = environment.steps[step][0].observation.board;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function renderer(options) {
|
|
2
|
-
const { environment, step, parent,
|
|
2
|
+
const { environment, step, parent, width = 400, height = 400 } = options;
|
|
3
3
|
|
|
4
4
|
// Chess-specific constants
|
|
5
5
|
const DEFAULT_NUM_ROWS = 8;
|
|
@@ -28,6 +28,7 @@ function renderer(options) {
|
|
|
28
28
|
let currentMessageBoxElement = typeof document !== 'undefined' ? document.getElementById('messageBox') : null;
|
|
29
29
|
let currentRendererContainer = null;
|
|
30
30
|
let currentTitleElement = null;
|
|
31
|
+
let squareSize = 50;
|
|
31
32
|
|
|
32
33
|
function _showMessage(message, type = 'info', duration = 3000) {
|
|
33
34
|
if (typeof document === 'undefined' || !document.body) return;
|
|
@@ -74,25 +75,30 @@ function renderer(options) {
|
|
|
74
75
|
fontFamily: "'Inter', sans-serif"
|
|
75
76
|
});
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
if (!environment.viewer) {
|
|
79
|
+
currentTitleElement = document.createElement('h1');
|
|
80
|
+
currentTitleElement.textContent = 'Chess';
|
|
81
|
+
// Identical styling to the Connect Four renderer's title
|
|
82
|
+
Object.assign(currentTitleElement.style, {
|
|
81
83
|
fontSize: '1.875rem',
|
|
82
84
|
fontWeight: 'bold',
|
|
83
85
|
marginBottom: '1rem',
|
|
84
86
|
textAlign: 'center',
|
|
85
87
|
color: '#2563eb'
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
});
|
|
89
|
+
currentRendererContainer.appendChild(currentTitleElement);
|
|
90
|
+
}
|
|
91
|
+
parentElementToClear.appendChild(currentRendererContainer);
|
|
88
92
|
|
|
93
|
+
const smallestParentEdge = Math.min(width, height);
|
|
94
|
+
squareSize = Math.floor(smallestParentEdge / DEFAULT_NUM_COLS);
|
|
89
95
|
currentBoardElement = document.createElement('div');
|
|
90
96
|
Object.assign(currentBoardElement.style, {
|
|
91
97
|
display: 'grid',
|
|
92
|
-
gridTemplateColumns: `repeat(${cols},
|
|
93
|
-
gridTemplateRows: `repeat(${rows},
|
|
94
|
-
width: `${cols *
|
|
95
|
-
height: `${rows *
|
|
98
|
+
gridTemplateColumns: `repeat(${cols}, ${squareSize}px)`,
|
|
99
|
+
gridTemplateRows: `repeat(${rows}, ${squareSize}px)`,
|
|
100
|
+
width: `${cols * squareSize}px`,
|
|
101
|
+
height: `${rows * squareSize}px`,
|
|
96
102
|
border: '2px solid #333'
|
|
97
103
|
});
|
|
98
104
|
|
|
@@ -101,8 +107,8 @@ function renderer(options) {
|
|
|
101
107
|
const square = document.createElement('div');
|
|
102
108
|
square.id = `cell-${r}-${c}`;
|
|
103
109
|
Object.assign(square.style, {
|
|
104
|
-
width:
|
|
105
|
-
height:
|
|
110
|
+
width: `${squareSize}px`,
|
|
111
|
+
height: `${squareSize}px`,
|
|
106
112
|
backgroundColor: (r + c) % 2 === 0 ? LIGHT_SQUARE_COLOR : DARK_SQUARE_COLOR,
|
|
107
113
|
display: 'flex',
|
|
108
114
|
alignItems: 'center',
|
|
@@ -126,7 +132,9 @@ function renderer(options) {
|
|
|
126
132
|
maxWidth: '90vw',
|
|
127
133
|
marginTop: '20px'
|
|
128
134
|
});
|
|
129
|
-
|
|
135
|
+
if (!environment.viewer) {
|
|
136
|
+
currentRendererContainer.appendChild(statusContainer);
|
|
137
|
+
}
|
|
130
138
|
|
|
131
139
|
currentStatusTextElement = document.createElement('p');
|
|
132
140
|
Object.assign(currentStatusTextElement.style, {
|
|
@@ -144,8 +152,6 @@ function renderer(options) {
|
|
|
144
152
|
});
|
|
145
153
|
statusContainer.appendChild(currentWinnerTextElement);
|
|
146
154
|
|
|
147
|
-
parentElementToClear.appendChild(currentRendererContainer);
|
|
148
|
-
|
|
149
155
|
if (typeof document !== 'undefined' && !document.body.hasAttribute('data-renderer-initialized')) {
|
|
150
156
|
document.body.setAttribute('data-renderer-initialized', 'true');
|
|
151
157
|
}
|
|
@@ -204,8 +210,9 @@ function renderer(options) {
|
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
|
|
207
|
-
const { board, activeColor,
|
|
213
|
+
const { board, activeColor, isTerminal, winner } = gameStateToDisplay;
|
|
208
214
|
|
|
215
|
+
const pieceSize = Math.floor(squareSize * 0.9);
|
|
209
216
|
for (let r_data = 0; r_data < displayRows; r_data++) {
|
|
210
217
|
for (let c_data = 0; c_data < displayCols; c_data++) {
|
|
211
218
|
const piece = board[r_data][c_data];
|
|
@@ -213,8 +220,8 @@ function renderer(options) {
|
|
|
213
220
|
if (squareElement && piece) {
|
|
214
221
|
const pieceImg = document.createElement('img');
|
|
215
222
|
pieceImg.src = PIECE_SVG_URLS[piece];
|
|
216
|
-
pieceImg.style.width =
|
|
217
|
-
pieceImg.style.height =
|
|
223
|
+
pieceImg.style.width = `${pieceSize}px`;
|
|
224
|
+
pieceImg.style.height = `${pieceSize}px`;
|
|
218
225
|
squareElement.appendChild(pieceImg);
|
|
219
226
|
}
|
|
220
227
|
}
|
|
@@ -222,7 +229,7 @@ function renderer(options) {
|
|
|
222
229
|
|
|
223
230
|
currentStatusTextElement.innerHTML = '';
|
|
224
231
|
currentWinnerTextElement.innerHTML = '';
|
|
225
|
-
if (
|
|
232
|
+
if (isTerminal) {
|
|
226
233
|
currentStatusTextElement.textContent = "Game Over!";
|
|
227
234
|
if (winner) {
|
|
228
235
|
if (String(winner).toLowerCase() === 'draw') {
|
|
@@ -235,8 +242,8 @@ function renderer(options) {
|
|
|
235
242
|
currentWinnerTextElement.textContent = "Game ended.";
|
|
236
243
|
}
|
|
237
244
|
} else {
|
|
238
|
-
|
|
239
|
-
|
|
245
|
+
const playerColor = String(activeColor).toLowerCase() === 'w' ? 'White' : 'Black';
|
|
246
|
+
currentStatusTextElement.innerHTML = `Current Player: <span style="font-weight: bold;">${playerColor}</span>`;
|
|
240
247
|
}
|
|
241
248
|
}
|
|
242
249
|
|
|
@@ -273,15 +280,15 @@ function renderer(options) {
|
|
|
273
280
|
|
|
274
281
|
let gameSpecificState = null;
|
|
275
282
|
|
|
276
|
-
if (observationForRenderer && typeof observationForRenderer.
|
|
283
|
+
if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
|
|
277
284
|
try {
|
|
278
|
-
const fen = observationForRenderer.
|
|
285
|
+
const fen = observationForRenderer.observationString;
|
|
279
286
|
const parsedFen = _parseFen(fen);
|
|
280
287
|
if (parsedFen) {
|
|
281
|
-
// Assuming `
|
|
288
|
+
// Assuming `isTerminal` and `winner` are provided in the top-level observation
|
|
282
289
|
gameSpecificState = {
|
|
283
290
|
...parsedFen,
|
|
284
|
-
|
|
291
|
+
isTerminal: observationForRenderer.isTerminal,
|
|
285
292
|
winner: observationForRenderer.winner
|
|
286
293
|
};
|
|
287
294
|
}
|
|
@@ -291,4 +298,4 @@ function renderer(options) {
|
|
|
291
298
|
}
|
|
292
299
|
|
|
293
300
|
_renderBoardDisplay(gameSpecificState, DEFAULT_NUM_ROWS, DEFAULT_NUM_COLS);
|
|
294
|
-
}
|
|
301
|
+
}
|
|
@@ -264,9 +264,9 @@ function renderer(options) {
|
|
|
264
264
|
|
|
265
265
|
let gameSpecificState = null;
|
|
266
266
|
|
|
267
|
-
if (observationForRenderer && typeof observationForRenderer.
|
|
267
|
+
if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
|
|
268
268
|
try {
|
|
269
|
-
gameSpecificState = JSON.parse(observationForRenderer.
|
|
269
|
+
gameSpecificState = JSON.parse(observationForRenderer.observationString);
|
|
270
270
|
} catch (e) {
|
|
271
271
|
_showMessage("Error: Corrupted game state (obs_string).", 'error');
|
|
272
272
|
}
|
|
@@ -280,17 +280,5 @@ function renderer(options) {
|
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
if (!gameSpecificState && observationForRenderer &&
|
|
284
|
-
Array.isArray(observationForRenderer.board) &&
|
|
285
|
-
typeof observationForRenderer.current_player !== 'undefined'
|
|
286
|
-
) {
|
|
287
|
-
if( (observationForRenderer.board.length === DEFAULT_NUM_ROWS &&
|
|
288
|
-
(observationForRenderer.board.length === 0 ||
|
|
289
|
-
(Array.isArray(observationForRenderer.board[0]) && observationForRenderer.board[0].length === DEFAULT_NUM_COLS)))
|
|
290
|
-
){
|
|
291
|
-
gameSpecificState = observationForRenderer;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
283
|
_renderBoardDisplay_svg(gameSpecificState, DEFAULT_NUM_ROWS, DEFAULT_NUM_COLS);
|
|
296
284
|
}
|
|
@@ -410,9 +410,9 @@ function renderer(options) {
|
|
|
410
410
|
let gameState = null;
|
|
411
411
|
|
|
412
412
|
// Try to parse game state from observation
|
|
413
|
-
if (gameMasterAgent.observation.
|
|
413
|
+
if (gameMasterAgent.observation.observationString) {
|
|
414
414
|
try {
|
|
415
|
-
gameState = JSON.parse(gameMasterAgent.observation.
|
|
415
|
+
gameState = JSON.parse(gameMasterAgent.observation.observationString);
|
|
416
416
|
} catch (e) {}
|
|
417
417
|
}
|
|
418
418
|
|
|
@@ -461,9 +461,9 @@ function renderer(options) {
|
|
|
461
461
|
const observationForRenderer = gameMasterAgent.observation;
|
|
462
462
|
let gameSpecificState = null;
|
|
463
463
|
|
|
464
|
-
if (observationForRenderer && typeof observationForRenderer.
|
|
464
|
+
if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
|
|
465
465
|
try {
|
|
466
|
-
gameSpecificState = JSON.parse(observationForRenderer.
|
|
466
|
+
gameSpecificState = JSON.parse(observationForRenderer.observationString);
|
|
467
467
|
} catch (e) {
|
|
468
468
|
_showMessage("Error: Corrupted game state (obs_string).", 'error');
|
|
469
469
|
}
|
|
@@ -283,9 +283,9 @@ function renderer(options) {
|
|
|
283
283
|
let boardArray = null;
|
|
284
284
|
let currentPlayerForState = null;
|
|
285
285
|
|
|
286
|
-
if (typeof observationForBoardState.
|
|
286
|
+
if (typeof observationForBoardState.observationString === 'string' && observationForBoardState.observationString.trim().startsWith('{')) {
|
|
287
287
|
try {
|
|
288
|
-
const parsedState = JSON.parse(observationForBoardState.
|
|
288
|
+
const parsedState = JSON.parse(observationForBoardState.observationString);
|
|
289
289
|
if (parsedState && Array.isArray(parsedState.board)) {
|
|
290
290
|
boardArray = parsedState.board;
|
|
291
291
|
}
|
|
@@ -294,7 +294,7 @@ function renderer(options) {
|
|
|
294
294
|
}
|
|
295
295
|
} catch (e) {
|
|
296
296
|
_showMessage("Error parsing game state from observation string.", 'error');
|
|
297
|
-
console.error("Failed to parse
|
|
297
|
+
console.error("Failed to parse observation string JSON:", e);
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
@@ -306,8 +306,8 @@ function renderer(options) {
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
if (!currentPlayerForState) {
|
|
309
|
-
if (observationForBoardState.
|
|
310
|
-
else if (observationForBoardState.
|
|
309
|
+
if (observationForBoardState.currentPlayer === 0) { currentPlayerForState = 'x'; }
|
|
310
|
+
else if (observationForBoardState.currentPlayer === 1) { currentPlayerForState = 'o'; }
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
const isTerminal = !!observationForBoardState.is_terminal;
|
|
@@ -320,7 +320,7 @@ function renderer(options) {
|
|
|
320
320
|
else if (finalRewards[1] === 1.0) winnerForState = 'o';
|
|
321
321
|
else if (finalRewards[0] === 0.0 && finalRewards[1] === 0.0) winnerForState = 'draw';
|
|
322
322
|
}
|
|
323
|
-
if (observationForBoardState.
|
|
323
|
+
if (observationForBoardState.currentPlayer === -2 && winnerForState === null) {
|
|
324
324
|
winnerForState = 'draw';
|
|
325
325
|
}
|
|
326
326
|
}
|
|
@@ -247,8 +247,8 @@ function renderer(options) {
|
|
|
247
247
|
// --- Observation Extraction & Merging ---
|
|
248
248
|
let obsP0 = null, obsP1 = null;
|
|
249
249
|
try {
|
|
250
|
-
obsP0 = JSON.parse(currentStepAgents[0].observation.
|
|
251
|
-
obsP1 = JSON.parse(currentStepAgents[1].observation.
|
|
250
|
+
obsP0 = JSON.parse(currentStepAgents[0].observation.observationString);
|
|
251
|
+
obsP1 = JSON.parse(currentStepAgents[1].observation.observationString);
|
|
252
252
|
} catch (e) {
|
|
253
253
|
defaultUIData.gameMessage = "Error parsing observation JSON.";
|
|
254
254
|
return defaultUIData;
|
|
@@ -14,6 +14,13 @@ from kaggle_environments import utils
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
import pyspiel
|
|
16
16
|
|
|
17
|
+
ERROR = "ERROR"
|
|
18
|
+
DONE = "DONE"
|
|
19
|
+
INACTIVE = "INACTIVE"
|
|
20
|
+
ACTIVE = "ACTIVE"
|
|
21
|
+
TIMEOUT = "TIMEOUT"
|
|
22
|
+
INVALID = "INVALID"
|
|
23
|
+
|
|
17
24
|
_log = logging.getLogger(__name__)
|
|
18
25
|
_log.setLevel(logging.INFO)
|
|
19
26
|
_handler = logging.StreamHandler(sys.stdout)
|
|
@@ -35,8 +42,16 @@ for proxy_file in GAMES_DIR.glob("**/*_proxy.py"):
|
|
|
35
42
|
|
|
36
43
|
|
|
37
44
|
# --- Constants ---
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
# TODO(jhtschultz): Make this configurable per-game. For instance, in poker, a
|
|
46
|
+
# invalid action would likely result in a fold, forfeiting the player's
|
|
47
|
+
# contribution to the pot.
|
|
48
|
+
DEFAULT_INVALID_ACTION_REWARD = -1
|
|
49
|
+
|
|
50
|
+
# Can be used by agents to signal an internal error to the environement.
|
|
51
|
+
AGENT_ERROR_ACTION = -2
|
|
52
|
+
|
|
53
|
+
DEFAULT_ACT_TIMEOUT = 60 * 60 # sixty minutes
|
|
54
|
+
DEFAULT_RUN_TIMEOUT = 60 * 60 * 30 # thirty hours
|
|
40
55
|
# Buffer in addition to max game length to account for timeouts, retrys, etc.
|
|
41
56
|
DEFAULT_STEP_BUFFER = 100
|
|
42
57
|
# TODO(jhtschultz): Add individual game descriptions.
|
|
@@ -65,6 +80,11 @@ CONFIGURATION_SPEC_TEMPLATE = {
|
|
|
65
80
|
"type": "object",
|
|
66
81
|
"default": {}
|
|
67
82
|
},
|
|
83
|
+
"metadata": {
|
|
84
|
+
"description": "Arbitrary metadata.",
|
|
85
|
+
"type": "object",
|
|
86
|
+
"default": {}
|
|
87
|
+
},
|
|
68
88
|
}
|
|
69
89
|
|
|
70
90
|
OBSERVATION_SPEC_TEMPLATE = {
|
|
@@ -77,44 +97,51 @@ OBSERVATION_SPEC_TEMPLATE = {
|
|
|
77
97
|
"description": "Short name of the OpenSpiel game.",
|
|
78
98
|
"type": "string"
|
|
79
99
|
},
|
|
80
|
-
"
|
|
100
|
+
"observationString": {
|
|
81
101
|
"description": "String representation of state.",
|
|
82
102
|
"type": "string"
|
|
83
103
|
},
|
|
84
|
-
|
|
85
|
-
# case for consistency with pyspiel?
|
|
86
|
-
"legal_actions": {
|
|
104
|
+
"legalActions": {
|
|
87
105
|
"description": "List of OpenSpiel legal action integers.",
|
|
88
106
|
"type": "array",
|
|
89
107
|
"items": {
|
|
90
108
|
"type": "integer"
|
|
91
109
|
}
|
|
92
110
|
},
|
|
93
|
-
"
|
|
111
|
+
"legalActionStrings": {
|
|
94
112
|
"description": "List of OpenSpiel legal actions strings.",
|
|
95
113
|
"type": "array",
|
|
96
114
|
"items": {
|
|
97
115
|
"type": "string"
|
|
98
116
|
}
|
|
99
117
|
},
|
|
100
|
-
"
|
|
118
|
+
"currentPlayer": {
|
|
101
119
|
"description": "ID of player whose turn it is.",
|
|
102
120
|
"type": "integer"
|
|
103
121
|
},
|
|
104
|
-
"
|
|
122
|
+
"playerId": {
|
|
105
123
|
"description": "ID of the agent receiving this observation.",
|
|
106
124
|
"type": "integer"
|
|
107
125
|
},
|
|
108
|
-
"
|
|
126
|
+
"isTerminal": {
|
|
109
127
|
"description": "Boolean indicating game end.",
|
|
110
128
|
"type": "boolean"
|
|
111
129
|
},
|
|
130
|
+
"serializedGameAndState": {
|
|
131
|
+
"description": "Enables reconstructing the Game and State objects.",
|
|
132
|
+
"type": "string"
|
|
133
|
+
},
|
|
112
134
|
"remainingOverageTime": 60,
|
|
113
135
|
"step": 0
|
|
114
136
|
},
|
|
115
137
|
"default": {}
|
|
116
138
|
}
|
|
117
139
|
|
|
140
|
+
ACTION_SPEC_TEMPLATE = {
|
|
141
|
+
"description": "Action object MUST contain a field `submission`, and MAY contain arbitrary additional information.",
|
|
142
|
+
"type": "object",
|
|
143
|
+
"default": {"submission": -1}
|
|
144
|
+
}
|
|
118
145
|
|
|
119
146
|
ENV_SPEC_TEMPLATE = {
|
|
120
147
|
"name": "PLACEHOLDER_NAME",
|
|
@@ -124,11 +151,7 @@ ENV_SPEC_TEMPLATE = {
|
|
|
124
151
|
"agents": ["PLACEHOLDER_NUM_AGENTS"],
|
|
125
152
|
"configuration": CONFIGURATION_SPEC_TEMPLATE,
|
|
126
153
|
"observation": OBSERVATION_SPEC_TEMPLATE,
|
|
127
|
-
"action":
|
|
128
|
-
"type": ["integer"],
|
|
129
|
-
"minimum": -1,
|
|
130
|
-
"default": -1
|
|
131
|
-
},
|
|
154
|
+
"action": ACTION_SPEC_TEMPLATE,
|
|
132
155
|
"reward": {
|
|
133
156
|
"type": ["number"],
|
|
134
157
|
"default": 0.0
|
|
@@ -141,6 +164,7 @@ ENV_SPEC_TEMPLATE = {
|
|
|
141
164
|
def interpreter(
|
|
142
165
|
state: list[utils.Struct],
|
|
143
166
|
env: core.Environment,
|
|
167
|
+
logs: list[dict[str, Any]],
|
|
144
168
|
) -> list[utils.Struct]:
|
|
145
169
|
"""Updates environment using player responses and returns new observations."""
|
|
146
170
|
kaggle_state = state # Not to be confused with OpenSpiel state.
|
|
@@ -157,18 +181,14 @@ def interpreter(
|
|
|
157
181
|
env.os_game = pyspiel.load_game(game_string)
|
|
158
182
|
if not hasattr(env, 'os_state'):
|
|
159
183
|
env.os_state = env.os_game.new_initial_state()
|
|
160
|
-
if "
|
|
161
|
-
env.info['
|
|
162
|
-
env.info['
|
|
184
|
+
if "stateHistory" not in env.info:
|
|
185
|
+
env.info['stateHistory'] = [str(env.os_state)]
|
|
186
|
+
env.info['actionHistory'] = []
|
|
187
|
+
env.info['moveDurations'] = []
|
|
163
188
|
|
|
164
189
|
os_game = env.os_game
|
|
165
190
|
os_state = env.os_state
|
|
166
191
|
num_players = os_game.num_players()
|
|
167
|
-
statuses = [
|
|
168
|
-
kaggle_state[player_id].status for player_id in range(num_players)
|
|
169
|
-
]
|
|
170
|
-
if not any(status == "ACTIVE" for status in statuses):
|
|
171
|
-
raise ValueError("Environment not done and no active agents.")
|
|
172
192
|
|
|
173
193
|
# TODO(jhtschultz): Test reset behavior.
|
|
174
194
|
is_initial_step = len(env.steps) == 1
|
|
@@ -178,26 +198,36 @@ def interpreter(
|
|
|
178
198
|
|
|
179
199
|
# --- Apply agent action ---
|
|
180
200
|
acting_agent = os_state.current_player()
|
|
181
|
-
action_submitted = None
|
|
182
|
-
|
|
201
|
+
action_submitted: int | None = None
|
|
202
|
+
action_submitted_to_string: str | None = None
|
|
203
|
+
action_applied: int | None = None
|
|
204
|
+
move_duration: float | None = None
|
|
183
205
|
if is_initial_step:
|
|
184
206
|
pass
|
|
185
207
|
elif 0 <= acting_agent < num_players:
|
|
186
|
-
if kaggle_state[acting_agent]
|
|
208
|
+
if kaggle_state[acting_agent]["status"] != "ACTIVE":
|
|
187
209
|
pass
|
|
188
210
|
else:
|
|
189
|
-
action_submitted = kaggle_state[acting_agent]
|
|
211
|
+
action_submitted = kaggle_state[acting_agent]["action"]["submission"]
|
|
190
212
|
if action_submitted in os_state.legal_actions():
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
kaggle_state[acting_agent].status = "ERROR"
|
|
213
|
+
action_submitted_to_string = os_state.action_to_string(action_submitted)
|
|
214
|
+
os_state.apply_action(action_submitted)
|
|
215
|
+
action_applied = action_submitted
|
|
216
|
+
env.info['actionHistory'].append(str(action_applied))
|
|
217
|
+
env.info['stateHistory'].append(str(os_state))
|
|
218
|
+
elif action_submitted == AGENT_ERROR_ACTION:
|
|
219
|
+
kaggle_state[acting_agent]["status"] = "ERROR"
|
|
199
220
|
else:
|
|
200
|
-
kaggle_state[acting_agent]
|
|
221
|
+
kaggle_state[acting_agent]["status"] = "INVALID"
|
|
222
|
+
try:
|
|
223
|
+
if "duration" in logs[acting_agent]:
|
|
224
|
+
move_duration = round(logs[acting_agent]["duration"], 3)
|
|
225
|
+
env.info["moveDurations"].append(move_duration)
|
|
226
|
+
else:
|
|
227
|
+
env.info["moveDurations"].append(None)
|
|
228
|
+
except Exception:
|
|
229
|
+
pass # No logs when stepping the env manually.
|
|
230
|
+
|
|
201
231
|
elif acting_agent == pyspiel.PlayerId.SIMULTANEOUS:
|
|
202
232
|
raise NotImplementedError
|
|
203
233
|
elif acting_agent == pyspiel.PlayerId.TERMINAL:
|
|
@@ -212,14 +242,40 @@ def interpreter(
|
|
|
212
242
|
outcomes, probs = zip(*os_state.chance_outcomes())
|
|
213
243
|
chance_action = np.random.choice(outcomes, p=probs)
|
|
214
244
|
os_state.apply_action(chance_action)
|
|
215
|
-
env.info['
|
|
216
|
-
env.info['
|
|
245
|
+
env.info['actionHistory'].append(str(chance_action))
|
|
246
|
+
env.info['stateHistory'].append(str(os_state))
|
|
217
247
|
|
|
218
248
|
# --- Update agent states ---
|
|
249
|
+
agent_error = any(
|
|
250
|
+
kaggle_state[player_id]["status"] in ["TIMEOUT", "ERROR"]
|
|
251
|
+
for player_id in range(num_players)
|
|
252
|
+
)
|
|
253
|
+
if agent_error:
|
|
254
|
+
_log.info("AGENT ERROR DETECTED")
|
|
255
|
+
|
|
256
|
+
invalid_action = any(
|
|
257
|
+
kaggle_state[player_id]["status"] == "INVALID"
|
|
258
|
+
for player_id in range(num_players)
|
|
259
|
+
)
|
|
260
|
+
if invalid_action:
|
|
261
|
+
_log.info("INVALID ACTION DETECTED")
|
|
262
|
+
|
|
263
|
+
status: str | None = None
|
|
219
264
|
for player_id, agent_state in enumerate(kaggle_state):
|
|
220
265
|
reward = None
|
|
221
|
-
if
|
|
222
|
-
|
|
266
|
+
if agent_error:
|
|
267
|
+
# Set all agent statuses to ERROR in order not to score episode. Preserve
|
|
268
|
+
# TIMEOUT which has the same effect.
|
|
269
|
+
if agent_state["status"] == "TIMEOUT":
|
|
270
|
+
status = "TIMEOUT"
|
|
271
|
+
else:
|
|
272
|
+
status = "ERROR"
|
|
273
|
+
elif invalid_action:
|
|
274
|
+
if agent_state["status"] == "INVALID":
|
|
275
|
+
reward = DEFAULT_INVALID_ACTION_REWARD
|
|
276
|
+
else:
|
|
277
|
+
reward = -DEFAULT_INVALID_ACTION_REWARD
|
|
278
|
+
status = "DONE"
|
|
223
279
|
elif os_state.is_terminal():
|
|
224
280
|
status = "DONE"
|
|
225
281
|
reward = os_state.returns()[player_id]
|
|
@@ -231,30 +287,39 @@ def interpreter(
|
|
|
231
287
|
)
|
|
232
288
|
else:
|
|
233
289
|
status = "INACTIVE"
|
|
290
|
+
assert status is not None
|
|
234
291
|
|
|
235
292
|
info_dict = {}
|
|
236
293
|
if acting_agent == player_id:
|
|
237
|
-
info_dict["
|
|
238
|
-
info_dict["
|
|
294
|
+
info_dict["actionSubmitted"] = action_submitted
|
|
295
|
+
info_dict["actionSubmittedToString"] = action_submitted_to_string
|
|
296
|
+
info_dict["actionApplied"] = action_applied
|
|
297
|
+
info_dict["timeTaken"] = move_duration
|
|
298
|
+
info_dict[
|
|
299
|
+
"agentSelfReportedStatus"
|
|
300
|
+
] = kaggle_state[acting_agent]["action"].get("status") if kaggle_state[acting_agent]["action"] else "unknown"
|
|
239
301
|
|
|
240
302
|
obs_update_dict = {
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"
|
|
303
|
+
"observationString": os_state.observation_string(player_id),
|
|
304
|
+
"legalActions": os_state.legal_actions(player_id),
|
|
305
|
+
"legalActionStrings": [
|
|
244
306
|
os_state.action_to_string(action) for action
|
|
245
307
|
in os_state.legal_actions(player_id)
|
|
246
308
|
],
|
|
247
|
-
"
|
|
248
|
-
"
|
|
249
|
-
"
|
|
309
|
+
"currentPlayer": os_state.current_player(),
|
|
310
|
+
"playerId": player_id,
|
|
311
|
+
"isTerminal": os_state.is_terminal(),
|
|
312
|
+
"serializedGameAndState": pyspiel.serialize_game_and_state(
|
|
313
|
+
os_game, os_state
|
|
314
|
+
),
|
|
250
315
|
}
|
|
251
316
|
|
|
252
317
|
# Apply updates
|
|
253
318
|
for k, v in obs_update_dict.items():
|
|
254
319
|
setattr(agent_state.observation, k, v)
|
|
255
|
-
agent_state
|
|
256
|
-
agent_state
|
|
257
|
-
agent_state
|
|
320
|
+
agent_state["reward"] = reward
|
|
321
|
+
agent_state["info"] = info_dict
|
|
322
|
+
agent_state["status"] = status
|
|
258
323
|
|
|
259
324
|
return kaggle_state
|
|
260
325
|
|
|
@@ -295,14 +360,14 @@ function renderer(context) {
|
|
|
295
360
|
// Try to get obs_string from game_master of current step
|
|
296
361
|
if (currentStepData[agentObsIndex] &&
|
|
297
362
|
currentStepData[agentObsIndex].observation &&
|
|
298
|
-
typeof currentStepData[agentObsIndex].observation.
|
|
299
|
-
obsString = currentStepData[agentObsIndex].observation.
|
|
363
|
+
typeof currentStepData[agentObsIndex].observation.observationString === 'string') {
|
|
364
|
+
obsString = currentStepData[agentObsIndex].observation.observationString;
|
|
300
365
|
}
|
|
301
366
|
// Fallback to initial step if current is unavailable (e.g. very first render call)
|
|
302
367
|
else if (step === 0 && environment.steps[0] && environment.steps[0][agentObsIndex] &&
|
|
303
368
|
environment.steps[0][agentObsIndex].observation &&
|
|
304
|
-
typeof environment.steps[0][agentObsIndex].observation.
|
|
305
|
-
obsString = environment.steps[0][agentObsIndex].observation.
|
|
369
|
+
typeof environment.steps[0][agentObsIndex].observation.observationString === 'string') {
|
|
370
|
+
obsString = environment.steps[0][agentObsIndex].observation.observationString;
|
|
306
371
|
}
|
|
307
372
|
|
|
308
373
|
const pre = document.createElement("pre");
|
|
@@ -349,11 +414,11 @@ def random_agent(
|
|
|
349
414
|
) -> int:
|
|
350
415
|
"""A built-in random agent specifically for OpenSpiel environments."""
|
|
351
416
|
del configuration
|
|
352
|
-
legal_actions = observation.get("
|
|
417
|
+
legal_actions = observation.get("legalActions")
|
|
353
418
|
if not legal_actions:
|
|
354
419
|
return None
|
|
355
420
|
action = random.choice(legal_actions)
|
|
356
|
-
return int(action)
|
|
421
|
+
return {"submission": int(action)}
|
|
357
422
|
|
|
358
423
|
|
|
359
424
|
AGENT_REGISTRY = {
|
|
@@ -380,14 +445,13 @@ def _build_env(game_string: str) -> dict[str, Any]:
|
|
|
380
445
|
env_spec["title"] = f"Open Spiel: {short_name}"
|
|
381
446
|
env_spec["agents"] = [game.num_players()]
|
|
382
447
|
|
|
383
|
-
env_config =
|
|
384
|
-
env_spec["configuration"] = env_config
|
|
448
|
+
env_config = env_spec["configuration"]
|
|
385
449
|
env_config["episodeSteps"] = game.max_history_length() + DEFAULT_STEP_BUFFER
|
|
386
450
|
env_config["openSpielGameString"]["default"] = str(game)
|
|
387
451
|
env_config["openSpielGameName"]["default"] = short_name
|
|
452
|
+
env_config["openSpielGameParameters"]["default"] = game.get_parameters()
|
|
388
453
|
|
|
389
|
-
env_obs =
|
|
390
|
-
env_spec["observation"] = env_obs
|
|
454
|
+
env_obs = env_spec["observation"]
|
|
391
455
|
env_obs["properties"]["openSpielGameString"]["default"] = str(game)
|
|
392
456
|
env_obs["properties"]["openSpielGameName"]["default"] = short_name
|
|
393
457
|
|
|
@@ -19,15 +19,78 @@ class OpenSpielEnvTest(absltest.TestCase):
|
|
|
19
19
|
)
|
|
20
20
|
self.assertTrue(len(envs) > _REGISTERED_GAMES_THRESHOLD)
|
|
21
21
|
|
|
22
|
-
def
|
|
22
|
+
def test_tic_tac_toe_agent_playthrough(self):
|
|
23
23
|
envs = open_spiel_env._register_game_envs(["tic_tac_toe"])
|
|
24
|
-
print(envs)
|
|
25
24
|
env = make("open_spiel_tic_tac_toe", debug=True)
|
|
26
25
|
env.run(["random", "random"])
|
|
27
26
|
json = env.toJSON()
|
|
28
27
|
self.assertEqual(json["name"], "open_spiel_tic_tac_toe")
|
|
29
28
|
self.assertTrue(all([status == "DONE" for status in json["statuses"]]))
|
|
30
29
|
|
|
30
|
+
def test_tic_tac_toe_manual_playthrough(self):
|
|
31
|
+
envs = open_spiel_env._register_game_envs(["tic_tac_toe"])
|
|
32
|
+
env = make("open_spiel_tic_tac_toe", debug=True)
|
|
33
|
+
env.reset()
|
|
34
|
+
env.step([{"submission": -1}, {"submission": -1}]) # Initial setup step.
|
|
35
|
+
env.step([{"submission": 0}, {"submission": -1}])
|
|
36
|
+
env.step([{"submission": -1}, {"submission": 1}])
|
|
37
|
+
env.step([{"submission": 3}, {"submission": -1}])
|
|
38
|
+
env.step([{"submission": -1}, {"submission": 4}])
|
|
39
|
+
env.step([{"submission": 6}, {"submission": -1}])
|
|
40
|
+
self.assertTrue(env.done)
|
|
41
|
+
self.assertEqual(env.toJSON()["rewards"], [1, -1])
|
|
42
|
+
|
|
43
|
+
def test_invalid_action(self):
|
|
44
|
+
envs = open_spiel_env._register_game_envs(["tic_tac_toe"])
|
|
45
|
+
env = make("open_spiel_tic_tac_toe", debug=True)
|
|
46
|
+
env.reset()
|
|
47
|
+
for i in range(5): # Try repeatedly applying an illegal action
|
|
48
|
+
env.step([
|
|
49
|
+
{"submission": pyspiel.INVALID_ACTION},
|
|
50
|
+
{"submission": pyspiel.INVALID_ACTION},
|
|
51
|
+
])
|
|
52
|
+
if env.done:
|
|
53
|
+
break
|
|
54
|
+
self.assertEqual(i, 1) # Zeroth step is setup step, should fail next step.
|
|
55
|
+
json = env.toJSON()
|
|
56
|
+
self.assertTrue(all([status == "DONE" for status in json["statuses"]]))
|
|
57
|
+
self.assertEqual(
|
|
58
|
+
json["rewards"],
|
|
59
|
+
[
|
|
60
|
+
open_spiel_env.DEFAULT_INVALID_ACTION_REWARD,
|
|
61
|
+
-open_spiel_env.DEFAULT_INVALID_ACTION_REWARD,
|
|
62
|
+
]
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def test_serialized_game_and_state(self):
|
|
66
|
+
envs = open_spiel_env._register_game_envs(["tic_tac_toe"])
|
|
67
|
+
env = make("open_spiel_tic_tac_toe", debug=True)
|
|
68
|
+
env.reset()
|
|
69
|
+
env.step([{"submission": -1}, {"submission": -1}]) # Initial setup step.
|
|
70
|
+
kaggle_state = env.step([{"submission": 0}, {"submission": -1}])
|
|
71
|
+
serialize_game_and_state = kaggle_state[1]["observation"]["serializedGameAndState"]
|
|
72
|
+
game, state = pyspiel.deserialize_game_and_state(serialize_game_and_state)
|
|
73
|
+
self.assertEqual(game.get_type().short_name, "tic_tac_toe_proxy")
|
|
74
|
+
self.assertEqual(state.history(), [0])
|
|
75
|
+
|
|
76
|
+
def test_agent_error(self):
|
|
77
|
+
envs = open_spiel_env._register_game_envs(["tic_tac_toe"])
|
|
78
|
+
env = make("open_spiel_tic_tac_toe", debug=True)
|
|
79
|
+
env.reset()
|
|
80
|
+
# Setup step
|
|
81
|
+
env.step([
|
|
82
|
+
{"submission": pyspiel.INVALID_ACTION},
|
|
83
|
+
{"submission": pyspiel.INVALID_ACTION},
|
|
84
|
+
])
|
|
85
|
+
env.step([
|
|
86
|
+
{"submission": open_spiel_env.AGENT_ERROR_ACTION},
|
|
87
|
+
{"submission": pyspiel.INVALID_ACTION},
|
|
88
|
+
])
|
|
89
|
+
self.assertTrue(env.done)
|
|
90
|
+
json = env.toJSON()
|
|
91
|
+
self.assertEqual(json["rewards"], [None, None])
|
|
92
|
+
self.assertEqual(json["statuses"], ["ERROR", "ERROR"])
|
|
93
|
+
|
|
31
94
|
|
|
32
95
|
if __name__ == '__main__':
|
|
33
|
-
absltest.main()
|
|
96
|
+
absltest.main()
|
|
@@ -199,12 +199,7 @@
|
|
|
199
199
|
${processing && h`<${Processing} />`}
|
|
200
200
|
</div>`;
|
|
201
201
|
})`
|
|
202
|
-
background-color: #
|
|
203
|
-
background-image: radial-gradient(
|
|
204
|
-
circle closest-side,
|
|
205
|
-
#000b49,
|
|
206
|
-
#000b2a
|
|
207
|
-
);
|
|
202
|
+
background-color: #1C1D20;
|
|
208
203
|
display: flex;
|
|
209
204
|
flex: 1;
|
|
210
205
|
overflow: hidden;
|
|
@@ -242,7 +237,7 @@
|
|
|
242
237
|
</ul>`)}
|
|
243
238
|
</div>`;
|
|
244
239
|
})`
|
|
245
|
-
background-color: #
|
|
240
|
+
background-color: #1C1D20;
|
|
246
241
|
font-family: sans-serif;
|
|
247
242
|
font-size: 14px;
|
|
248
243
|
height: 48px;
|
|
@@ -442,7 +437,6 @@
|
|
|
442
437
|
})`
|
|
443
438
|
align-items: center;
|
|
444
439
|
background: #212121;
|
|
445
|
-
border: 4px solid #212121;
|
|
446
440
|
box-sizing: border-box;
|
|
447
441
|
display: flex;
|
|
448
442
|
flex-direction: column;
|
|
@@ -450,6 +444,10 @@
|
|
|
450
444
|
justify-content: center;
|
|
451
445
|
position: relative;
|
|
452
446
|
width: 100%;
|
|
447
|
+
|
|
448
|
+
&:not(.no-border) {
|
|
449
|
+
border: 4px solid #212121;
|
|
450
|
+
}
|
|
453
451
|
`;
|
|
454
452
|
|
|
455
453
|
const App = () => {
|
|
@@ -545,7 +543,7 @@
|
|
|
545
543
|
// Initialize context with window.kaggle.
|
|
546
544
|
updateContext(window.kaggle || {});
|
|
547
545
|
|
|
548
|
-
if (window.kaggle
|
|
546
|
+
if (window.kaggle?.playing) {
|
|
549
547
|
play(true);
|
|
550
548
|
}
|
|
551
549
|
|
|
@@ -556,10 +554,49 @@
|
|
|
556
554
|
// Ensure the environment names match before updating.
|
|
557
555
|
try {
|
|
558
556
|
if (
|
|
559
|
-
event.data.environment.name
|
|
560
|
-
contextRef.current.environment.name
|
|
557
|
+
event.data.environment?.name == contextRef.current.environment.name ||
|
|
558
|
+
event.data.environment?.name && !contextRef.current.environment.name ||
|
|
559
|
+
event.data.environment?.loading !== contextRef.current.environment.loading
|
|
561
560
|
) {
|
|
562
|
-
|
|
561
|
+
const nextContext = {
|
|
562
|
+
...event.data,
|
|
563
|
+
environment: {
|
|
564
|
+
...event.data.environment,
|
|
565
|
+
steps: event.data.environment?.steps ?? []
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
window.kaggle = nextContext;
|
|
569
|
+
if (!window.kaggle.renderer) {
|
|
570
|
+
window.kaggle.renderer = window.renderer;
|
|
571
|
+
}
|
|
572
|
+
updateContext(nextContext);
|
|
573
|
+
}
|
|
574
|
+
if (event.data.setSteps) {
|
|
575
|
+
const nextContext = {
|
|
576
|
+
...(window.kaggle ?? {}),
|
|
577
|
+
environment: {
|
|
578
|
+
...(window.kaggle?.environment ?? {}),
|
|
579
|
+
steps: event.data.setSteps
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
window.kaggle = nextContext;
|
|
583
|
+
if (!window.kaggle.renderer) {
|
|
584
|
+
window.kaggle.renderer = window.renderer;
|
|
585
|
+
}
|
|
586
|
+
updateContext(nextContext)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Side load the renderer script if it is specified by the post message event and not already loaded.
|
|
590
|
+
const renderScriptId = 'rendererScript'
|
|
591
|
+
if (event.data.environment?.rendererUrl && !document.querySelector(`#${renderScriptId}`)) {
|
|
592
|
+
window.rendererUrl = event.data.environment?.rendererUrl;
|
|
593
|
+
const script = document.createElement('script');
|
|
594
|
+
script.id = renderScriptId;
|
|
595
|
+
script.onload = () => {
|
|
596
|
+
window.kaggle.renderer = window.renderer;
|
|
597
|
+
};
|
|
598
|
+
script.src = window.rendererUrl;
|
|
599
|
+
document.body.appendChild(script);
|
|
563
600
|
}
|
|
564
601
|
} catch {}
|
|
565
602
|
},
|
|
@@ -674,7 +711,7 @@
|
|
|
674
711
|
|
|
675
712
|
return h`
|
|
676
713
|
<${Context.Provider} value=${contextRef.current}>
|
|
677
|
-
<${Player} />
|
|
714
|
+
<${Player} className="${contextRef.current.environment.viewer ? 'no-border' : ''}" />
|
|
678
715
|
<//>`;
|
|
679
716
|
};
|
|
680
717
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
kaggle_environments/__init__.py,sha256=
|
|
1
|
+
kaggle_environments/__init__.py,sha256=GzrKQBWH-dKbhfDK2K0GYTnHxw31m8DhnbzcHNMRn7c,2175
|
|
2
2
|
kaggle_environments/agent.py,sha256=j9rLnCK_Gy0eRIuvlJ9vcMh3vxn-Wvu-pjCpannOolc,6703
|
|
3
3
|
kaggle_environments/api.py,sha256=eLBKqr11Ku4tdsMUdUqy74FIVEA_hdV3_QUpX84x3Z8,798
|
|
4
|
-
kaggle_environments/core.py,sha256=
|
|
4
|
+
kaggle_environments/core.py,sha256=Ense_M-2rP4KmVeuKFjM0NQ8M6ucUZTbhwrGekyR9LY,27857
|
|
5
5
|
kaggle_environments/errors.py,sha256=SzKjkZP7pJbf9g0GDjGq4XG194hCQXLMwrlMCcm7Ai8,3336
|
|
6
6
|
kaggle_environments/helpers.py,sha256=xkOMXaOMifYHHstDZo8bexk-Qq9suPM7Gkfi2JbXu8M,10627
|
|
7
7
|
kaggle_environments/main.py,sha256=10wtcEFcGIjdOd9AEps5WOAwslc6Wsx3eZ43LXJa8jE,11705
|
|
8
8
|
kaggle_environments/schemas.json,sha256=zGzLyhqPdH6QQ0d48SrP5LKbvupprrWvgfQBerLqmhw,3307
|
|
9
9
|
kaggle_environments/status_codes.json,sha256=6a8HuS_Vth95W0f2fov21QLdRfA3KbizUvjKmJhYtBc,995
|
|
10
10
|
kaggle_environments/utils.py,sha256=FcI17PA4QK2-hyNp0dryS0TQ2pFlH9K19zDUMmuF4-E,5713
|
|
11
|
-
kaggle_environments/envs/chess/chess.js,sha256=
|
|
11
|
+
kaggle_environments/envs/chess/chess.js,sha256=QYA1arYF_qOfchN8HHQ4hL5z3C9XeT5hYigT75CgvKo,274596
|
|
12
12
|
kaggle_environments/envs/chess/chess.json,sha256=fc8Qa1IHWmYbiEgorXIjMj2JmqP95x_reqFe6Mon2Wk,1692
|
|
13
13
|
kaggle_environments/envs/chess/chess.py,sha256=41LMA8--APQOhl6aeWgJvkSaRBjAch2FgS7ELIoOT3w,245361
|
|
14
14
|
kaggle_environments/envs/chess/test_chess.py,sha256=ayZEIWRSD3D6BqhJv0q_M5a-j8-pMm8kb4ACAW-DhBE,1748
|
|
@@ -191,24 +191,24 @@ kaggle_environments/envs/mab/mab.py,sha256=bkSIxkstS98Vr3eOA9kxQkseDqa1MlG2Egfze
|
|
|
191
191
|
kaggle_environments/envs/open_spiel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
192
192
|
kaggle_environments/envs/open_spiel/html_playthrough_generator.py,sha256=qzvi9wMZKz1WfpaIpBxP5LPlVYKAk9npEtdKLXYHMWo,950
|
|
193
193
|
kaggle_environments/envs/open_spiel/observation.py,sha256=yrJ_iZ9sBUTB6YOyEpKNwYiQEWmsPPtaDYtL4zsw1Ko,4834
|
|
194
|
-
kaggle_environments/envs/open_spiel/open_spiel.py,sha256=
|
|
194
|
+
kaggle_environments/envs/open_spiel/open_spiel.py,sha256=HzN1ngjeOqxLoetI1g56PdlioRY26VoCJMQpbD4S-Vk,17517
|
|
195
195
|
kaggle_environments/envs/open_spiel/proxy.py,sha256=8Shane4KWYKvbP9nV3l8VQfAFOfFSUrS78h_4xQthVM,4881
|
|
196
196
|
kaggle_environments/envs/open_spiel/proxy_test.py,sha256=QkmRo_uS0DgDDm2pbU2vwal5KOMCWKw92rC2_g3MziM,1837
|
|
197
|
-
kaggle_environments/envs/open_spiel/test_open_spiel.py,sha256=
|
|
197
|
+
kaggle_environments/envs/open_spiel/test_open_spiel.py,sha256=MwyjH-e00-3SP8_r10drYTFvplacbo0cDCI0XKtE4wU,3596
|
|
198
198
|
kaggle_environments/envs/open_spiel/games/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
199
|
-
kaggle_environments/envs/open_spiel/games/chess/chess.js,sha256=
|
|
199
|
+
kaggle_environments/envs/open_spiel/games/chess/chess.js,sha256=e5QFnMCaNXMRskO0qbdhy7q0W3ov9yFGmvfpC48Dd6k,12931
|
|
200
200
|
kaggle_environments/envs/open_spiel/games/connect_four/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
201
|
-
kaggle_environments/envs/open_spiel/games/connect_four/connect_four.js,sha256=
|
|
201
|
+
kaggle_environments/envs/open_spiel/games/connect_four/connect_four.js,sha256=iO74ar3Hh64VYEx9v3eysgrPU-Mcokl9dkFxie6uISg,14893
|
|
202
202
|
kaggle_environments/envs/open_spiel/games/connect_four/connect_four_proxy.py,sha256=2otG99felDYhNhWpsadbM9YUaHtrXqhV1GFNEHhuPwA,2348
|
|
203
203
|
kaggle_environments/envs/open_spiel/games/connect_four/connect_four_proxy_test.py,sha256=vYn-QDPyRRigL8XdaHMN4FTO9zc1T9YB096HDGQH_T4,1870
|
|
204
204
|
kaggle_environments/envs/open_spiel/games/go/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
205
|
-
kaggle_environments/envs/open_spiel/games/go/go.js,sha256=
|
|
205
|
+
kaggle_environments/envs/open_spiel/games/go/go.js,sha256=SWUPrnQCMBlDjUiKTgVn9LeTUM85YbR10JRrq3ddw14,23751
|
|
206
206
|
kaggle_environments/envs/open_spiel/games/go/go_proxy.py,sha256=f5jaS6O7mngq8LHRkxfyf_M57BTb_3yxb7FjELR2aqg,3146
|
|
207
207
|
kaggle_environments/envs/open_spiel/games/tic_tac_toe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
208
|
-
kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe.js,sha256=
|
|
208
|
+
kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe.js,sha256=OD7FbhhOqmL8OC7UqPt0S9znwcUY4YTuhRCdsBd3ALE,17339
|
|
209
209
|
kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe_proxy.py,sha256=3Imu-0-lMNUF9FQQ4V3Y3NnkS-9_-IhbSprlWgecTLA,2771
|
|
210
210
|
kaggle_environments/envs/open_spiel/games/universal_poker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
211
|
-
kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker.js,sha256=
|
|
211
|
+
kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker.js,sha256=7QQlSITZjzEJbnS930Ht2MzDSMBulhU59HaSwnKvf4g,21820
|
|
212
212
|
kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker_proxy.py,sha256=WKFgbdES3JGyL5Su5wi6jE8yrSJaBCvXL3z_IgmWJLs,5219
|
|
213
213
|
kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker_proxy_test.py,sha256=YHWaVVO8fA9NKrTMM7VpAH_U94yh5d0Z-gNhXX4A7sA,1531
|
|
214
214
|
kaggle_environments/envs/rps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -223,10 +223,10 @@ kaggle_environments/envs/tictactoe/test_tictactoe.py,sha256=6CgQbRz-yxNoMfD5tzmC
|
|
|
223
223
|
kaggle_environments/envs/tictactoe/tictactoe.js,sha256=NZDT-oSG0a6a-rso9Ldh9qkJwVrxrAsjKUC3_tJu3tw,8002
|
|
224
224
|
kaggle_environments/envs/tictactoe/tictactoe.json,sha256=zMXZ8-fpT7FBhzz2FFBvRLn4XwtngjEqOieMvI6cCj8,1121
|
|
225
225
|
kaggle_environments/envs/tictactoe/tictactoe.py,sha256=uq3sTHWNMg0dxX2v9pTbJAKM7fwerxQt7OQjCX96m-Y,3657
|
|
226
|
-
kaggle_environments/static/player.html,sha256=
|
|
227
|
-
kaggle_environments-1.17.
|
|
228
|
-
kaggle_environments-1.17.
|
|
229
|
-
kaggle_environments-1.17.
|
|
230
|
-
kaggle_environments-1.17.
|
|
231
|
-
kaggle_environments-1.17.
|
|
232
|
-
kaggle_environments-1.17.
|
|
226
|
+
kaggle_environments/static/player.html,sha256=TTxN-EU7_KCNIVDX4E4TrZ61FRWkGUDHMSbnUYsQSvg,24975
|
|
227
|
+
kaggle_environments-1.17.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
228
|
+
kaggle_environments-1.17.7.dist-info/METADATA,sha256=va0iBjyCpXB4osbBWVdDGdhgUUig8nPEIR540OJU7vM,10955
|
|
229
|
+
kaggle_environments-1.17.7.dist-info/WHEEL,sha256=7wAbZI8A1UjN-j4-aYf66qBxOZ0Ioy0QNykkY5NcGJo,109
|
|
230
|
+
kaggle_environments-1.17.7.dist-info/entry_points.txt,sha256=HbVC-LKGQFV6lEEYBYyDTtrkHgdHJUWQ8_qt9KHGqz4,70
|
|
231
|
+
kaggle_environments-1.17.7.dist-info/top_level.txt,sha256=v3MMWIPMQFcI-WuF_dJngHWe9Bb2yH_6p4wat1x4gAc,20
|
|
232
|
+
kaggle_environments-1.17.7.dist-info/RECORD,,
|
{kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{kaggle_environments-1.17.5.dist-info → kaggle_environments-1.17.7.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|