kaggle-environments 1.17.6__py2.py3-none-any.whl → 1.17.8__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/envs/chess/chess.js +27 -23
- kaggle_environments/envs/open_spiel/games/chess/chess.js +65 -28
- kaggle_environments/envs/open_spiel/open_spiel.py +86 -42
- kaggle_environments/envs/open_spiel/test_open_spiel.py +66 -3
- kaggle_environments/static/player.html +50 -13
- {kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/METADATA +1 -1
- {kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/RECORD +12 -12
- {kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/WHEEL +0 -0
- {kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/entry_points.txt +0 -0
- {kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/licenses/LICENSE +0 -0
- {kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/top_level.txt +0 -0
kaggle_environments/__init__.py
CHANGED
|
@@ -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,14 +152,39 @@ 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
|
}
|
|
152
158
|
return true;
|
|
153
159
|
}
|
|
154
160
|
|
|
161
|
+
// White is in position 1, Black is in position 0
|
|
162
|
+
function _getTeamNameForColor(color, teamNames) {
|
|
163
|
+
if (!teamNames || teamNames.length < 2) return null;
|
|
164
|
+
return color.toLowerCase() === 'white' ? teamNames[1] : teamNames[0];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function _deriveWinnerFromRewards(currentStepAgents, teamNames) {
|
|
168
|
+
if (!currentStepAgents || currentStepAgents.length < 2) return null;
|
|
169
|
+
|
|
170
|
+
const player0Reward = currentStepAgents[0].reward;
|
|
171
|
+
const player1Reward = currentStepAgents[1].reward;
|
|
172
|
+
|
|
173
|
+
if (player0Reward === player1Reward) {
|
|
174
|
+
return 'draw';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const winnerPlayerIndex = player0Reward === 1 ? 0 : 1;
|
|
178
|
+
const color = winnerPlayerIndex === 0 ? 'Black' : 'White';
|
|
179
|
+
|
|
180
|
+
if (teamNames) {
|
|
181
|
+
const teamName = _getTeamNameForColor(color, teamNames);
|
|
182
|
+
return `${color} (${teamName})`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return color.toLowerCase();
|
|
186
|
+
}
|
|
187
|
+
|
|
155
188
|
function _parseFen(fen) {
|
|
156
189
|
if (!fen || typeof fen !== 'string') return null;
|
|
157
190
|
|
|
@@ -204,8 +237,9 @@ function renderer(options) {
|
|
|
204
237
|
}
|
|
205
238
|
|
|
206
239
|
|
|
207
|
-
const { board, activeColor,
|
|
240
|
+
const { board, activeColor, isTerminal, winner } = gameStateToDisplay;
|
|
208
241
|
|
|
242
|
+
const pieceSize = Math.floor(squareSize * 0.9);
|
|
209
243
|
for (let r_data = 0; r_data < displayRows; r_data++) {
|
|
210
244
|
for (let c_data = 0; c_data < displayCols; c_data++) {
|
|
211
245
|
const piece = board[r_data][c_data];
|
|
@@ -213,8 +247,8 @@ function renderer(options) {
|
|
|
213
247
|
if (squareElement && piece) {
|
|
214
248
|
const pieceImg = document.createElement('img');
|
|
215
249
|
pieceImg.src = PIECE_SVG_URLS[piece];
|
|
216
|
-
pieceImg.style.width =
|
|
217
|
-
pieceImg.style.height =
|
|
250
|
+
pieceImg.style.width = `${pieceSize}px`;
|
|
251
|
+
pieceImg.style.height = `${pieceSize}px`;
|
|
218
252
|
squareElement.appendChild(pieceImg);
|
|
219
253
|
}
|
|
220
254
|
}
|
|
@@ -222,21 +256,23 @@ function renderer(options) {
|
|
|
222
256
|
|
|
223
257
|
currentStatusTextElement.innerHTML = '';
|
|
224
258
|
currentWinnerTextElement.innerHTML = '';
|
|
225
|
-
if (
|
|
259
|
+
if (isTerminal) {
|
|
226
260
|
currentStatusTextElement.textContent = "Game Over!";
|
|
227
261
|
if (winner) {
|
|
228
262
|
if (String(winner).toLowerCase() === 'draw') {
|
|
229
263
|
currentWinnerTextElement.textContent = "It's a Draw!";
|
|
230
264
|
} else {
|
|
231
|
-
|
|
232
|
-
currentWinnerTextElement.innerHTML = `Winner: <span style="font-weight: bold;">${winnerColor}</span>`;
|
|
265
|
+
currentWinnerTextElement.innerHTML = `Winner: <span style="font-weight: bold;">${winner}</span>`;
|
|
233
266
|
}
|
|
234
267
|
} else {
|
|
235
268
|
currentWinnerTextElement.textContent = "Game ended.";
|
|
236
269
|
}
|
|
237
270
|
} else {
|
|
238
|
-
|
|
239
|
-
|
|
271
|
+
const playerColor = String(activeColor).toLowerCase() === 'w' ? 'White' : 'Black';
|
|
272
|
+
const teamName = _getTeamNameForColor(playerColor, environment.info?.TeamNames);
|
|
273
|
+
const currentPlayerText = teamName ? `${playerColor} (${teamName})` : playerColor;
|
|
274
|
+
|
|
275
|
+
currentStatusTextElement.innerHTML = `Current Player: <span style="font-weight: bold;">${currentPlayerText}</span>`;
|
|
240
276
|
}
|
|
241
277
|
}
|
|
242
278
|
|
|
@@ -278,11 +314,12 @@ function renderer(options) {
|
|
|
278
314
|
const fen = observationForRenderer.observationString;
|
|
279
315
|
const parsedFen = _parseFen(fen);
|
|
280
316
|
if (parsedFen) {
|
|
281
|
-
|
|
317
|
+
const winner = observationForRenderer.isTerminal ?
|
|
318
|
+
_deriveWinnerFromRewards(currentStepAgents, environment.info?.TeamNames) : null;
|
|
282
319
|
gameSpecificState = {
|
|
283
320
|
...parsedFen,
|
|
284
|
-
|
|
285
|
-
winner:
|
|
321
|
+
isTerminal: observationForRenderer.isTerminal,
|
|
322
|
+
winner: winner
|
|
286
323
|
};
|
|
287
324
|
}
|
|
288
325
|
} catch (e) {
|
|
@@ -291,4 +328,4 @@ function renderer(options) {
|
|
|
291
328
|
}
|
|
292
329
|
|
|
293
330
|
_renderBoardDisplay(gameSpecificState, DEFAULT_NUM_ROWS, DEFAULT_NUM_COLS);
|
|
294
|
-
}
|
|
331
|
+
}
|
|
@@ -19,6 +19,7 @@ DONE = "DONE"
|
|
|
19
19
|
INACTIVE = "INACTIVE"
|
|
20
20
|
ACTIVE = "ACTIVE"
|
|
21
21
|
TIMEOUT = "TIMEOUT"
|
|
22
|
+
INVALID = "INVALID"
|
|
22
23
|
|
|
23
24
|
_log = logging.getLogger(__name__)
|
|
24
25
|
_log.setLevel(logging.INFO)
|
|
@@ -41,8 +42,16 @@ for proxy_file in GAMES_DIR.glob("**/*_proxy.py"):
|
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
# --- Constants ---
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
46
55
|
# Buffer in addition to max game length to account for timeouts, retrys, etc.
|
|
47
56
|
DEFAULT_STEP_BUFFER = 100
|
|
48
57
|
# TODO(jhtschultz): Add individual game descriptions.
|
|
@@ -71,6 +80,11 @@ CONFIGURATION_SPEC_TEMPLATE = {
|
|
|
71
80
|
"type": "object",
|
|
72
81
|
"default": {}
|
|
73
82
|
},
|
|
83
|
+
"metadata": {
|
|
84
|
+
"description": "Arbitrary metadata.",
|
|
85
|
+
"type": "object",
|
|
86
|
+
"default": {}
|
|
87
|
+
},
|
|
74
88
|
}
|
|
75
89
|
|
|
76
90
|
OBSERVATION_SPEC_TEMPLATE = {
|
|
@@ -113,6 +127,10 @@ OBSERVATION_SPEC_TEMPLATE = {
|
|
|
113
127
|
"description": "Boolean indicating game end.",
|
|
114
128
|
"type": "boolean"
|
|
115
129
|
},
|
|
130
|
+
"serializedGameAndState": {
|
|
131
|
+
"description": "Enables reconstructing the Game and State objects.",
|
|
132
|
+
"type": "string"
|
|
133
|
+
},
|
|
116
134
|
"remainingOverageTime": 60,
|
|
117
135
|
"step": 0
|
|
118
136
|
},
|
|
@@ -171,19 +189,6 @@ def interpreter(
|
|
|
171
189
|
os_game = env.os_game
|
|
172
190
|
os_state = env.os_state
|
|
173
191
|
num_players = os_game.num_players()
|
|
174
|
-
statuses = [
|
|
175
|
-
kaggle_state[player_id].status for player_id in range(num_players)
|
|
176
|
-
]
|
|
177
|
-
if not any(status == ACTIVE for status in statuses):
|
|
178
|
-
for player_id in range(num_players):
|
|
179
|
-
p = kaggle_state[player_id]
|
|
180
|
-
if p.status in [ERROR, TIMEOUT]:
|
|
181
|
-
# TODO: properly set the reward per game
|
|
182
|
-
p.reward = -1
|
|
183
|
-
elif p.status in [INACTIVE]:
|
|
184
|
-
p.reward = 1
|
|
185
|
-
p.status = DONE
|
|
186
|
-
return;
|
|
187
192
|
|
|
188
193
|
# TODO(jhtschultz): Test reset behavior.
|
|
189
194
|
is_initial_step = len(env.steps) == 1
|
|
@@ -193,31 +198,36 @@ def interpreter(
|
|
|
193
198
|
|
|
194
199
|
# --- Apply agent action ---
|
|
195
200
|
acting_agent = os_state.current_player()
|
|
196
|
-
action_submitted = None
|
|
197
|
-
|
|
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
|
|
198
205
|
if is_initial_step:
|
|
199
206
|
pass
|
|
200
207
|
elif 0 <= acting_agent < num_players:
|
|
201
|
-
if kaggle_state[acting_agent]
|
|
208
|
+
if kaggle_state[acting_agent]["status"] != "ACTIVE":
|
|
202
209
|
pass
|
|
203
210
|
else:
|
|
204
|
-
action_submitted = kaggle_state[acting_agent]
|
|
211
|
+
action_submitted = kaggle_state[acting_agent]["action"]["submission"]
|
|
205
212
|
if action_submitted in os_state.legal_actions():
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
kaggle_state[acting_agent].status = "ERROR"
|
|
214
|
-
else:
|
|
215
|
-
kaggle_state[acting_agent].status = "INVALID"
|
|
216
|
-
if "duration" in logs[acting_agent]:
|
|
217
|
-
move_duration = round(logs[acting_agent]["duration"], 3)
|
|
218
|
-
env.info["moveDurations"].append(move_duration)
|
|
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"
|
|
219
220
|
else:
|
|
220
|
-
|
|
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
|
+
|
|
221
231
|
elif acting_agent == pyspiel.PlayerId.SIMULTANEOUS:
|
|
222
232
|
raise NotImplementedError
|
|
223
233
|
elif acting_agent == pyspiel.PlayerId.TERMINAL:
|
|
@@ -236,10 +246,36 @@ def interpreter(
|
|
|
236
246
|
env.info['stateHistory'].append(str(os_state))
|
|
237
247
|
|
|
238
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
|
|
239
264
|
for player_id, agent_state in enumerate(kaggle_state):
|
|
240
265
|
reward = None
|
|
241
|
-
if
|
|
242
|
-
|
|
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"
|
|
243
279
|
elif os_state.is_terminal():
|
|
244
280
|
status = "DONE"
|
|
245
281
|
reward = os_state.returns()[player_id]
|
|
@@ -251,11 +287,17 @@ def interpreter(
|
|
|
251
287
|
)
|
|
252
288
|
else:
|
|
253
289
|
status = "INACTIVE"
|
|
290
|
+
assert status is not None
|
|
254
291
|
|
|
255
292
|
info_dict = {}
|
|
256
293
|
if acting_agent == player_id:
|
|
257
294
|
info_dict["actionSubmitted"] = action_submitted
|
|
295
|
+
info_dict["actionSubmittedToString"] = action_submitted_to_string
|
|
258
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"
|
|
259
301
|
|
|
260
302
|
obs_update_dict = {
|
|
261
303
|
"observationString": os_state.observation_string(player_id),
|
|
@@ -267,14 +309,17 @@ def interpreter(
|
|
|
267
309
|
"currentPlayer": os_state.current_player(),
|
|
268
310
|
"playerId": player_id,
|
|
269
311
|
"isTerminal": os_state.is_terminal(),
|
|
312
|
+
"serializedGameAndState": pyspiel.serialize_game_and_state(
|
|
313
|
+
os_game, os_state
|
|
314
|
+
),
|
|
270
315
|
}
|
|
271
316
|
|
|
272
317
|
# Apply updates
|
|
273
318
|
for k, v in obs_update_dict.items():
|
|
274
319
|
setattr(agent_state.observation, k, v)
|
|
275
|
-
agent_state
|
|
276
|
-
agent_state
|
|
277
|
-
agent_state
|
|
320
|
+
agent_state["reward"] = reward
|
|
321
|
+
agent_state["info"] = info_dict
|
|
322
|
+
agent_state["status"] = status
|
|
278
323
|
|
|
279
324
|
return kaggle_state
|
|
280
325
|
|
|
@@ -400,14 +445,13 @@ def _build_env(game_string: str) -> dict[str, Any]:
|
|
|
400
445
|
env_spec["title"] = f"Open Spiel: {short_name}"
|
|
401
446
|
env_spec["agents"] = [game.num_players()]
|
|
402
447
|
|
|
403
|
-
env_config =
|
|
404
|
-
env_spec["configuration"] = env_config
|
|
448
|
+
env_config = env_spec["configuration"]
|
|
405
449
|
env_config["episodeSteps"] = game.max_history_length() + DEFAULT_STEP_BUFFER
|
|
406
450
|
env_config["openSpielGameString"]["default"] = str(game)
|
|
407
451
|
env_config["openSpielGameName"]["default"] = short_name
|
|
452
|
+
env_config["openSpielGameParameters"]["default"] = game.get_parameters()
|
|
408
453
|
|
|
409
|
-
env_obs =
|
|
410
|
-
env_spec["observation"] = env_obs
|
|
454
|
+
env_obs = env_spec["observation"]
|
|
411
455
|
env_obs["properties"]["openSpielGameString"]["default"] = str(game)
|
|
412
456
|
env_obs["properties"]["openSpielGameName"]["default"] = short_name
|
|
413
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,4 +1,4 @@
|
|
|
1
|
-
kaggle_environments/__init__.py,sha256=
|
|
1
|
+
kaggle_environments/__init__.py,sha256=_wgrdspX3nmKV-ySMVlvuqmo-d6UmFceru-fk2fFpVg,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
4
|
kaggle_environments/core.py,sha256=Ense_M-2rP4KmVeuKFjM0NQ8M6ucUZTbhwrGekyR9LY,27857
|
|
@@ -8,7 +8,7 @@ kaggle_environments/main.py,sha256=10wtcEFcGIjdOd9AEps5WOAwslc6Wsx3eZ43LXJa8jE,1
|
|
|
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,12 +191,12 @@ 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=JYL3nDL_sayz3YPeMpsuE-waTZKkkuK4VRJN9lZYCKc,14045
|
|
200
200
|
kaggle_environments/envs/open_spiel/games/connect_four/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
201
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
|
|
@@ -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.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
228
|
+
kaggle_environments-1.17.8.dist-info/METADATA,sha256=pP8vJJsca01VGe2qDDRjfGgcOpb4VQVchXzX7qyO8AM,10955
|
|
229
|
+
kaggle_environments-1.17.8.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
|
230
|
+
kaggle_environments-1.17.8.dist-info/entry_points.txt,sha256=HbVC-LKGQFV6lEEYBYyDTtrkHgdHJUWQ8_qt9KHGqz4,70
|
|
231
|
+
kaggle_environments-1.17.8.dist-info/top_level.txt,sha256=v3MMWIPMQFcI-WuF_dJngHWe9Bb2yH_6p4wat1x4gAc,20
|
|
232
|
+
kaggle_environments-1.17.8.dist-info/RECORD,,
|
|
File without changes
|
{kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{kaggle_environments-1.17.6.dist-info → kaggle_environments-1.17.8.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|