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.

@@ -20,7 +20,7 @@ from .core import *
20
20
  from .main import http_request
21
21
  from . import errors
22
22
 
23
- __version__ = "1.17.5"
23
+ __version__ = "1.17.7"
24
24
 
25
25
  __all__ = ["Agent", "environments", "errors", "evaluate", "http_request",
26
26
  "make", "register", "utils", "__version__",
@@ -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
- parent.appendChild(downloadButton);
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
- const info = environment.info;
4183
- const agent1 = info?.TeamNames?.[0] || "Agent 1";
4184
- const agent2 = info?.TeamNames?.[1] || "Agent 2";
4185
- const firstGame = environment.steps[step][0].observation.mark == "white";
4186
- const fontSize = Math.round(0.33 * offset);
4187
- c.font = `${fontSize}px sans-serif`;
4188
- c.fillStyle = "#FFFFFF";
4189
- const agent1Reward = environment.steps[step][0].reward;
4190
- const agent2Reward = environment.steps[step][1].reward;
4191
- const charCount = agent1.length + agent2.length + 12;
4192
- const title = `${
4193
- firstGame ? "\u25A0" : "\u25A1"
4194
- }${agent1} (${agent1Reward}) vs ${
4195
- firstGame ? "\u25A1" : "\u25A0"
4196
- }${agent2} (${agent2Reward})`;
4197
- c.fillText(
4198
- title,
4199
- offset + 4 * squareSize - Math.floor((charCount * fontSize) / 4),
4200
- 40
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, interactive, isInteractive } = options;
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
- currentTitleElement = document.createElement('h1');
78
- currentTitleElement.textContent = 'Chess';
79
- // Identical styling to the Connect Four renderer's title
80
- Object.assign(currentTitleElement.style, {
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
- currentRendererContainer.appendChild(currentTitleElement);
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}, 50px)`,
93
- gridTemplateRows: `repeat(${rows}, 50px)`,
94
- width: `${cols * 50}px`,
95
- height: `${rows * 50}px`,
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: '50px',
105
- height: '50px',
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
- currentRendererContainer.appendChild(statusContainer);
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, is_terminal, winner } = gameStateToDisplay;
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 = '45px';
217
- pieceImg.style.height = '45px';
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 (is_terminal) {
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
- const playerColor = String(activeColor).toLowerCase() === 'w' ? 'White' : 'Black';
239
- currentStatusTextElement.innerHTML = `Current Player: <span style="font-weight: bold;">${playerColor}</span>`;
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.observation_string === 'string' && observationForRenderer.observation_string.trim() !== '') {
283
+ if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
277
284
  try {
278
- const fen = observationForRenderer.observation_string;
285
+ const fen = observationForRenderer.observationString;
279
286
  const parsedFen = _parseFen(fen);
280
287
  if (parsedFen) {
281
- // Assuming `is_terminal` and `winner` are provided in the top-level observation
288
+ // Assuming `isTerminal` and `winner` are provided in the top-level observation
282
289
  gameSpecificState = {
283
290
  ...parsedFen,
284
- is_terminal: observationForRenderer.is_terminal,
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.observation_string === 'string' && observationForRenderer.observation_string.trim() !== '') {
267
+ if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
268
268
  try {
269
- gameSpecificState = JSON.parse(observationForRenderer.observation_string);
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.observation_string) {
413
+ if (gameMasterAgent.observation.observationString) {
414
414
  try {
415
- gameState = JSON.parse(gameMasterAgent.observation.observation_string);
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.observation_string === 'string' && observationForRenderer.observation_string.trim() !== '') {
464
+ if (observationForRenderer && typeof observationForRenderer.observationString === 'string' && observationForRenderer.observationString.trim() !== '') {
465
465
  try {
466
- gameSpecificState = JSON.parse(observationForRenderer.observation_string);
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.observation_string === 'string' && observationForBoardState.observation_string.trim().startsWith('{')) {
286
+ if (typeof observationForBoardState.observationString === 'string' && observationForBoardState.observationString.trim().startsWith('{')) {
287
287
  try {
288
- const parsedState = JSON.parse(observationForBoardState.observation_string);
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 observation_string JSON:", e);
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.current_player === 0) { currentPlayerForState = 'x'; }
310
- else if (observationForBoardState.current_player === 1) { currentPlayerForState = 'o'; }
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.current_player === -2 && winnerForState === null) {
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.observation_string);
251
- obsP1 = JSON.parse(currentStepAgents[1].observation.observation_string);
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
- DEFAULT_ACT_TIMEOUT = 5
39
- DEFAULT_RUN_TIMEOUT = 1200
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
- "observation_string": {
100
+ "observationString": {
81
101
  "description": "String representation of state.",
82
102
  "type": "string"
83
103
  },
84
- # TODO(jhtschultz): Use camel case for consistency with spec, or snake
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
- "legal_action_strings": {
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
- "current_player": {
118
+ "currentPlayer": {
101
119
  "description": "ID of player whose turn it is.",
102
120
  "type": "integer"
103
121
  },
104
- "player_id": {
122
+ "playerId": {
105
123
  "description": "ID of the agent receiving this observation.",
106
124
  "type": "integer"
107
125
  },
108
- "is_terminal": {
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 "state_history" not in env.info:
161
- env.info['state_history'] = [str(env.os_state)]
162
- env.info['action_history'] = []
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
- action_applied = None
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].status != "ACTIVE":
208
+ if kaggle_state[acting_agent]["status"] != "ACTIVE":
187
209
  pass
188
210
  else:
189
- action_submitted = kaggle_state[acting_agent].action
211
+ action_submitted = kaggle_state[acting_agent]["action"]["submission"]
190
212
  if action_submitted in os_state.legal_actions():
191
- try:
192
- os_state.apply_action(action_submitted)
193
- action_applied = action_submitted
194
- env.info['action_history'].append(str(action_applied))
195
- env.info['state_history'].append(str(os_state))
196
- except Exception as e: # pylint: disable=broad-exception-caught
197
- _log.debug(e)
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].status = "INVALID"
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['action_history'].append(str(chance_action))
216
- env.info['state_history'].append(str(os_state))
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 agent_state.status in ["TIMEOUT", "ERROR", "INVALID"]:
222
- status = agent_state.status
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["action_submitted"] = action_submitted
238
- info_dict["action_applied"] = action_applied
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
- "observation_string": os_state.observation_string(player_id),
242
- "legal_actions": os_state.legal_actions(player_id),
243
- "legal_action_strings": [
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
- "current_player": os_state.current_player(),
248
- "is_terminal": os_state.is_terminal(),
249
- "player_id": player_id,
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.reward = reward
256
- agent_state.info = info_dict
257
- agent_state.status = status
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.observation_string === 'string') {
299
- obsString = currentStepData[agentObsIndex].observation.observation_string;
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.observation_string === 'string') {
305
- obsString = environment.steps[0][agentObsIndex].observation.observation_string;
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("legal_actions")
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 = copy.deepcopy(CONFIGURATION_SPEC_TEMPLATE)
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 = copy.deepcopy(OBSERVATION_SPEC_TEMPLATE)
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 test_tic_tac_toe_playthrough(self):
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: #000b2a;
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: #000b2a;
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.playing) {
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
- updateContext(event.data);
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaggle-environments
3
- Version: 1.17.5
3
+ Version: 1.17.7
4
4
  Summary: Kaggle Environments
5
5
  Home-page: https://github.com/Kaggle/kaggle-environments
6
6
  Author: Kaggle
@@ -1,14 +1,14 @@
1
- kaggle_environments/__init__.py,sha256=NFCwapaNv9MXVBKTTm7AgYLswbUKb7RPELyxidmJqxs,2175
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=IrEkN9cIA2djBAxI8Sz1GRpGNKjhqbnBdV6irAeTm8Q,27851
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=sZBnS1RKkP1kss2FrxMI6ceurjnlAA4yUJU_jfkgCZw,274447
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=kJDOApsaSPJ53MVcG9vKXuMW-MJNx093gn32vj2TFKw,15304
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=YhmEyyxc68JmjzmsdoIUEO-ds1O8HiICsiCKkMFth5s,1033
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=XoX0R7zYqPGh4EYnxUJCXPBb44fbLAVsDLQ8p9oibhA,12547
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=sT8rVfjkyY_DUQSHpZUP7I7QEoJwa7Oq9H82wD7vnbQ,15440
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=cmwq64L77iVjYJpMKCKaRDfNXDaO7R7PJT78xu60Qwg,23756
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=_W7zGtpnKlqw3ghZspwwXYe3sdOdL3h_yYzo9wHAnzA,17345
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=eDtjUYtt1a26zQXOk-BhgcIsYfTCD0OLSZikC2Z5YKQ,21822
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=XyVoe0XxMa2MO1fTDY_rjyjzPN-JZgbVwJIDoLSnlw0,23016
227
- kaggle_environments-1.17.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
228
- kaggle_environments-1.17.5.dist-info/METADATA,sha256=6E3MWC0cXRLQJrMBbBdxnmSCNBTYIM49xS68wmIYTzE,10955
229
- kaggle_environments-1.17.5.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
230
- kaggle_environments-1.17.5.dist-info/entry_points.txt,sha256=HbVC-LKGQFV6lEEYBYyDTtrkHgdHJUWQ8_qt9KHGqz4,70
231
- kaggle_environments-1.17.5.dist-info/top_level.txt,sha256=v3MMWIPMQFcI-WuF_dJngHWe9Bb2yH_6p4wat1x4gAc,20
232
- kaggle_environments-1.17.5.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (78.1.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any