kaggle-environments 1.23.1__py3-none-any.whl → 1.23.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kaggle-environments might be problematic. Click here for more details.

Files changed (22) hide show
  1. kaggle_environments/envs/connectx/visualizer/default/index.html +13 -0
  2. kaggle_environments/envs/connectx/visualizer/default/package.json +22 -0
  3. kaggle_environments/envs/connectx/visualizer/default/replays/test-replay.json +1129 -0
  4. kaggle_environments/envs/connectx/visualizer/default/src/main.ts +11 -0
  5. kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +381 -0
  6. kaggle_environments/envs/connectx/visualizer/default/src/style.css +38 -0
  7. kaggle_environments/envs/connectx/visualizer/default/tsconfig.json +4 -0
  8. kaggle_environments/envs/connectx/visualizer/default/vite.config.ts +7 -0
  9. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/index.html +13 -0
  10. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +22 -0
  11. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json +1 -0
  12. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +267 -0
  13. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.js +19 -0
  14. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +37 -0
  15. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.js +493 -0
  16. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json +7 -0
  17. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts +6 -0
  18. {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.2.dist-info}/METADATA +1 -1
  19. {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.2.dist-info}/RECORD +22 -5
  20. {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.2.dist-info}/WHEEL +0 -0
  21. {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.2.dist-info}/entry_points.txt +0 -0
  22. {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,11 @@
1
+ import { Player, PreactAdapter } from "@kaggle-environments/core";
2
+ import { Renderer } from "./renderer";
3
+ import "./style.css";
4
+
5
+ const app = document.getElementById("app");
6
+ if (!app) {
7
+ throw new Error("Could not find app element");
8
+ }
9
+
10
+ const adapter = new PreactAdapter(Renderer);
11
+ new Player(app, adapter);
@@ -0,0 +1,381 @@
1
+ import { h, FunctionComponent } from "preact";
2
+ import { useEffect, useRef } from "preact/hooks";
3
+ import htm from "htm";
4
+ import { ReplayData } from "@kaggle-environments/core";
5
+
6
+ const html = htm.bind(h);
7
+
8
+ // --- Props Interface ---
9
+ interface RendererProps {
10
+ replay: ReplayData;
11
+ step: number;
12
+ agents: any[];
13
+ }
14
+
15
+ // --- Constants and Drawing Paths (K, Goose) ---
16
+ const kPath = new Path2D(
17
+ `M78.3,96.5c-0.1,0.4-0.5,0.6-1.1,0.6H64.9c-0.7,0-1.4-0.3-1.9-1l-20.3-26L37,75.5v20.1 c0,0.9-0.5,1.4-1.4,1.4H26c-0.9,0-1.4-0.5-1.4-1.4V3.9c0-0.9,0.5-1.4,1.4-1.4h9.5C36.5,2.5,37,3,37,3.9v56.5l24.3-24.7 c0.6-0.6,1.3-1,1.9-1H76c0.6,0,0.9,0.2,1.1,0.7c0.2,0.6,0.1,1-0.1,1.2l-25.7,25L78,95.1C78.4,95.5,78.5,95.9,78.3,96.5z`
18
+ );
19
+ const goose1Path = new Path2D(
20
+ `M8.8,92.7c-4-18.5,4.7-37.2,20.7-46.2c0,0,2.7-1.4,3.4-1.9c2.2-1.6,3-2.1,3-5c0-5-2.1-7.2-2.1-7.2 c-3.9-3.3-6.3-8.2-6.3-13.7c0-10,8.1-18.1,18.1-18.1s18.1,8.1,18.1,18.1c0,6-1.5,32.7-2.3,38.8l-0.1,1`
21
+ );
22
+ const goose2Path = new Path2D(`M27.4,19L8.2,27.6c0,0-7.3,2.9,2.6,5c6.1,1.3,24,5.9,24,5.9l1,0.3`);
23
+ const goose3Path = new Path2D(`M63.7,99.6C52.3,99.6,43,90.3,43,78.9s9.3-20.7,20.7-20.7c10.6,0,34.4,0.1,35.8,9`);
24
+
25
+ const getColor = (mark: number, opacity = 1) => {
26
+ if (mark === 1) return `rgba(0, 255, 255, ${opacity})`; // Cyan
27
+ if (mark === 2) return `rgba(255, 255, 255, ${opacity})`; // White
28
+ return "#fff";
29
+ };
30
+
31
+ // --- Helper function to draw a token to a canvas and get a Data URL ---
32
+ const getTokenAsDataURL = (mark: number): string => {
33
+ const canvas = document.createElement("canvas");
34
+ canvas.width = 100;
35
+ canvas.height = 100;
36
+ const c = canvas.getContext("2d");
37
+ if (!c) return "";
38
+
39
+ // This is a simplified version of the main drawPiece function
40
+ c.fillStyle = getColor(mark, 0.1);
41
+ c.strokeStyle = getColor(mark);
42
+ c.shadowColor = getColor(mark);
43
+ c.shadowBlur = 8;
44
+ c.lineWidth = 1;
45
+
46
+ c.save();
47
+ c.beginPath();
48
+ c.arc(50, 50, 50, 0, 2 * Math.PI);
49
+ c.closePath();
50
+ c.lineWidth *= 4;
51
+ c.stroke();
52
+ c.fill();
53
+ c.restore();
54
+
55
+ c.beginPath();
56
+ c.arc(50, 50, 40, 0, 2 * Math.PI);
57
+ c.closePath();
58
+ c.stroke();
59
+
60
+ if (mark === 1) {
61
+ const scale = 0.54;
62
+ c.save();
63
+ c.translate(23, 23);
64
+ c.scale(scale, scale);
65
+ c.lineWidth /= scale;
66
+ c.shadowBlur /= scale;
67
+ c.stroke(kPath);
68
+ c.restore();
69
+ }
70
+
71
+ if (mark === 2) {
72
+ const scale = 0.6;
73
+ c.save();
74
+ c.translate(24, 28);
75
+ c.scale(scale, scale);
76
+ c.lineWidth /= scale;
77
+ c.shadowBlur /= scale;
78
+ c.stroke(goose1Path);
79
+ c.stroke(goose2Path);
80
+ c.stroke(goose3Path);
81
+ c.beginPath();
82
+ c.arc(38.5, 18.6, 2.7, 0, Math.PI * 2);
83
+ c.closePath();
84
+ c.fill();
85
+ c.restore();
86
+ }
87
+
88
+ return canvas.toDataURL();
89
+ };
90
+
91
+ // --- Game Status Component ---
92
+ const GameStatus: FunctionComponent<RendererProps> = ({ replay, step, agents }) => {
93
+ const isLastStep = step === replay.steps.length - 1;
94
+ if (!isLastStep) {
95
+ return html`<div class="status-bar"></div>`; // Reserve space
96
+ }
97
+
98
+ const finalStep = replay.steps[step];
99
+ const winnerStep = finalStep.find((agentStep) => agentStep.reward === 1);
100
+
101
+ let message = "Game Over";
102
+ let tokenUrl = null;
103
+
104
+ if (winnerStep) {
105
+ const winnerIndex = finalStep.indexOf(winnerStep);
106
+ const winnerAgent = agents.find((a) => a.index === winnerIndex);
107
+ tokenUrl = getTokenAsDataURL(winnerIndex + 1);
108
+ let winnerName = null;
109
+ if (winnerAgent && winnerAgent.name) {
110
+ winnerName = winnerAgent.name;
111
+ } else if (replay.info && replay.info.TeamNames && replay.info.TeamNames[winnerIndex]) {
112
+ winnerName = replay.info.TeamNames[winnerIndex];
113
+ }
114
+
115
+ if (winnerName) {
116
+ message = `Winner: ${winnerName}`;
117
+ } else {
118
+ message = `Winner: Player ${winnerIndex + 1}`;
119
+ }
120
+ } else if (finalStep.every((agentStep) => agentStep.reward === 0)) {
121
+ message = "Draw";
122
+ }
123
+
124
+ return html`
125
+ <div class="status-bar">
126
+ ${tokenUrl && html`<img src=${tokenUrl} class="token" />`}
127
+ <span>${message}</span>
128
+ </div>
129
+ `;
130
+ };
131
+
132
+ // --- Main Renderer Component ---
133
+ export const Renderer: FunctionComponent<RendererProps> = ({ replay, step, agents }) => {
134
+ const canvasRef = useRef<HTMLCanvasElement>(null);
135
+ const animationFrameId = useRef<number>();
136
+ const prevStep = useRef(step);
137
+
138
+ useEffect(() => {
139
+ const isBackStep = step < prevStep.current;
140
+ prevStep.current = step;
141
+ const canvas = canvasRef.current;
142
+ if (!canvas) return;
143
+ const c = canvas.getContext("2d");
144
+ if (!c) return;
145
+
146
+ const { configuration, steps } = replay;
147
+ const { columns, rows, inarow } = configuration;
148
+ const board = steps[step][0].observation.board;
149
+
150
+ const draw = (frame: number) => {
151
+ const { width, height } = canvas.getBoundingClientRect();
152
+ canvas.width = width;
153
+ canvas.height = height;
154
+
155
+ const unit = 8;
156
+ const minCanvasSize = Math.min(height, width);
157
+ const minOffset = minCanvasSize > 400 ? 30 : unit / 2;
158
+ const cellSize = Math.min((width - minOffset * 2) / columns, (height - minOffset * 2) / rows);
159
+ const cellInset = 0.8;
160
+ const pieceScale = cellSize / 100;
161
+ const xOffset = Math.max(0, (width - cellSize * columns) / 2);
162
+ const yOffset = Math.max(0, (height - cellSize * rows) / 2);
163
+
164
+ c.fillStyle = "#000B2A";
165
+ c.fillRect(0, 0, canvas.width, canvas.height);
166
+
167
+ const getRowCol = (cell: number) => [Math.floor(cell / columns), cell % columns];
168
+
169
+ const drawCellCircle = (cell: number) => {
170
+ const [row, col] = getRowCol(cell);
171
+ c.arc(
172
+ xOffset + (col * cellSize + cellSize / 2),
173
+ yOffset + (row * cellSize + cellSize / 2),
174
+ (cellInset * cellSize) / 2,
175
+ 0,
176
+ 2 * Math.PI,
177
+ false as any
178
+ );
179
+ };
180
+
181
+ const drawPiece = (mark: number) => {
182
+ const opacity = minCanvasSize < 300 ? 0.6 - minCanvasSize / 1000 : 0.1;
183
+ c.fillStyle = getColor(mark, opacity);
184
+ c.strokeStyle = getColor(mark);
185
+ c.shadowColor = getColor(mark);
186
+ c.shadowBlur = 8 / cellInset;
187
+ c.lineWidth = 1 / cellInset;
188
+
189
+ c.save();
190
+ c.beginPath();
191
+ c.arc(50, 50, 50, 2 * Math.PI, false as any);
192
+ c.closePath();
193
+ c.lineWidth *= 4;
194
+ c.stroke();
195
+ c.fill();
196
+ c.restore();
197
+
198
+ c.beginPath();
199
+ c.arc(50, 50, 40, 2 * Math.PI, false as any);
200
+ c.closePath();
201
+ c.stroke();
202
+
203
+ if (mark === 1) {
204
+ const scale = 0.54;
205
+ c.save();
206
+ c.translate(23, 23);
207
+ c.scale(scale, scale);
208
+ c.lineWidth /= scale;
209
+ c.shadowBlur /= scale;
210
+ c.stroke(kPath);
211
+ c.restore();
212
+ }
213
+
214
+ if (mark === 2) {
215
+ const scale = 0.6;
216
+ c.save();
217
+ c.translate(24, 28);
218
+ c.scale(scale, scale);
219
+ c.lineWidth /= scale;
220
+ c.shadowBlur /= scale;
221
+ c.stroke(goose1Path);
222
+ c.stroke(goose2Path);
223
+ c.stroke(goose3Path);
224
+ c.beginPath();
225
+ c.arc(38.5, 18.6, 2.7, 0, Math.PI * 2, false as any);
226
+ c.closePath();
227
+ c.fill();
228
+ c.restore();
229
+ }
230
+ };
231
+
232
+ for (let i = 0; i < board.length; i++) {
233
+ const [row, col] = getRowCol(i);
234
+ if (board[i] === 0) continue;
235
+
236
+ let yFrame = 1;
237
+ if (!isBackStep && step > 0 && replay.steps[step - 1][0].observation.board[i] !== board[i]) {
238
+ yFrame = Math.min(1, frame * 2);
239
+ }
240
+
241
+ c.save();
242
+ c.translate(
243
+ xOffset + cellSize * col + (cellSize - cellSize * cellInset) / 2,
244
+ yOffset + yFrame * (cellSize * row) + (cellSize - cellSize * cellInset) / 2
245
+ );
246
+ c.scale(pieceScale * cellInset, pieceScale * cellInset);
247
+ drawPiece(board[i]);
248
+ c.restore();
249
+ }
250
+
251
+ const bgRadius = (Math.min(rows, columns) * cellSize) / 2;
252
+ const bgStyle = c.createRadialGradient(
253
+ xOffset + (cellSize * columns) / 2,
254
+ yOffset + (cellSize * rows) / 2,
255
+ 0,
256
+ xOffset + (cellSize * columns) / 2,
257
+ yOffset + (cellSize * rows) / 2,
258
+ bgRadius
259
+ );
260
+ bgStyle.addColorStop(0, "#000B49");
261
+ bgStyle.addColorStop(1, "#000B2A");
262
+
263
+ c.beginPath();
264
+ c.rect(0, 0, canvas.width, canvas.height);
265
+ c.closePath();
266
+ c.shadowBlur = 0;
267
+ for (let i = 0; i < board.length; i++) {
268
+ drawCellCircle(i);
269
+ c.closePath();
270
+ }
271
+ c.fillStyle = bgStyle;
272
+ c.fill("evenodd");
273
+
274
+ for (let i = 0; i < board.length; i++) {
275
+ c.beginPath();
276
+ drawCellCircle(i);
277
+ c.strokeStyle = "#0361B2";
278
+ c.lineWidth = 1;
279
+ c.stroke();
280
+ c.closePath();
281
+ }
282
+
283
+ const drawLine = (fromCell: number, toCell: number) => {
284
+ if (frame < 0.5) return;
285
+ const lineFrame = (frame - 0.5) / 0.5;
286
+ const x1 = xOffset + (fromCell % columns) * cellSize + cellSize / 2;
287
+ const x2 = x1 + lineFrame * (xOffset + ((toCell % columns) * cellSize + cellSize / 2) - x1);
288
+ const y1 = yOffset + Math.floor(fromCell / columns) * cellSize + cellSize / 2;
289
+ const y2 = y1 + lineFrame * (yOffset + Math.floor(toCell / columns) * cellSize + cellSize / 2 - y1);
290
+ c.beginPath();
291
+ c.lineCap = "round";
292
+ c.lineWidth = 4;
293
+ c.strokeStyle = getColor(board[fromCell]);
294
+ c.shadowBlur = 8;
295
+ c.shadowColor = getColor(board[fromCell]);
296
+ c.moveTo(x1, y1);
297
+ c.lineTo(x2, y2);
298
+ c.stroke();
299
+ };
300
+
301
+ const getCell = (cell: number, rowOffset: number, columnOffset: number) => {
302
+ const row = Math.floor(cell / columns) + rowOffset;
303
+ const col = (cell % columns) + columnOffset;
304
+ if (row < 0 || row >= rows || col < 0 || col >= columns) return -1;
305
+ return col + row * columns;
306
+ };
307
+
308
+ const makeNode = (cell: number) => {
309
+ const node = { cell, directions: [] as number[], value: board[cell] };
310
+ for (let r = -1; r <= 1; r++) {
311
+ for (let c = -1; c <= 1; c++) {
312
+ if (r === 0 && c === 0) continue;
313
+ node.directions.push(getCell(cell, r, c));
314
+ }
315
+ }
316
+ return node;
317
+ };
318
+ const graph = board.map((_: any, i: number) => makeNode(i));
319
+
320
+ const getSequence = (node: ReturnType<typeof makeNode>, direction: number) => {
321
+ const sequence = [node.cell];
322
+ while (sequence.length < inarow) {
323
+ const nextNodeIndex = node.directions[direction];
324
+ if (nextNodeIndex === -1) return;
325
+ const next = graph[nextNodeIndex];
326
+ if (!next || node.value !== next.value || next.value === 0) return;
327
+ node = next;
328
+ sequence.push(node.cell);
329
+ }
330
+ return sequence;
331
+ };
332
+
333
+ if (replay.steps[step].some((s) => s.status === "DONE")) {
334
+ for (let i = 0; i < board.length; i++) {
335
+ for (let d = 0; d < 8; d++) {
336
+ const seq = getSequence(graph[i], d);
337
+ if (seq) {
338
+ drawLine(seq[0], seq[inarow - 1]);
339
+ i = board.length;
340
+ break;
341
+ }
342
+ }
343
+ }
344
+ }
345
+ };
346
+
347
+ let start = Date.now();
348
+ const animate = () => {
349
+ const frame = Math.min((Date.now() - start) / 500, 1);
350
+ draw(frame);
351
+ if (frame < 1) {
352
+ animationFrameId.current = requestAnimationFrame(animate);
353
+ }
354
+ };
355
+
356
+ animate();
357
+
358
+ const resizeObserver = new ResizeObserver(() => {
359
+ if (animationFrameId.current) {
360
+ cancelAnimationFrame(animationFrameId.current);
361
+ }
362
+ start = Date.now();
363
+ animate();
364
+ });
365
+ resizeObserver.observe(canvas);
366
+
367
+ return () => {
368
+ resizeObserver.disconnect();
369
+ if (animationFrameId.current) {
370
+ cancelAnimationFrame(animationFrameId.current);
371
+ }
372
+ };
373
+ }, [replay, step]);
374
+
375
+ return html`
376
+ <div class="renderer-container">
377
+ <canvas ref=${canvasRef} />
378
+ <${GameStatus} replay=${replay} step=${step} agents=${agents} />
379
+ </div>
380
+ `;
381
+ };
@@ -0,0 +1,38 @@
1
+ html, body, #app {
2
+ width: 100%;
3
+ height: 100%;
4
+ margin: 0;
5
+ padding: 0;
6
+ overflow: hidden;
7
+ }
8
+
9
+ .renderer-container {
10
+ display: flex;
11
+ flex-direction: column;
12
+ width: 100%;
13
+ height: 100%;
14
+ background: #000B2A;
15
+ }
16
+
17
+ .renderer-container canvas {
18
+ flex-grow: 1;
19
+ }
20
+
21
+ .status-bar {
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ padding: 8px;
26
+ color: white;
27
+ font-family: sans-serif;
28
+ font-size: 14px;
29
+ font-weight: 500;
30
+ min-height: 18px;
31
+ flex-shrink: 0;
32
+ }
33
+
34
+ .status-bar .token {
35
+ width: 20px;
36
+ height: 20px;
37
+ margin-right: 8px;
38
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../../../web/tsconfig.base.json",
3
+ "include": ["src"]
4
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig, mergeConfig } from 'vite';
2
+ import baseConfig from '../../../../../web/vite.config.base';
3
+
4
+ // https://vitejs.dev/config/
5
+ export default mergeConfig(baseConfig, defineConfig({
6
+ publicDir: 'replays',
7
+ }));
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Repeated Poker Visualizer</title>
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ <script type="module" src="/src/main.ts"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@kaggle-environments/repeated-poker-visualizer",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "dev-with-replay": "cross-env VITE_REPLAY_FILE=./replays/test-replay.json vite",
9
+ "build": "tsc && vite build",
10
+ "preview": "vite preview"
11
+ },
12
+ "devDependencies": {
13
+ "cross-env": "^10.1.0",
14
+ "typescript": "^5.0.0",
15
+ "vite": "^5.0.0"
16
+ },
17
+ "dependencies": {
18
+ "@kaggle-environments/core": "workspace:*",
19
+ "htm": "^3.1.1",
20
+ "preact": "^10.13.2"
21
+ }
22
+ }