kaggle-environments 1.23.1__py3-none-any.whl → 1.23.3__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/envs/connectx/visualizer/default/index.html +13 -0
- kaggle_environments/envs/connectx/visualizer/default/package.json +22 -0
- kaggle_environments/envs/connectx/visualizer/default/replays/test-replay.json +1129 -0
- kaggle_environments/envs/connectx/visualizer/default/src/main.ts +11 -0
- kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +381 -0
- kaggle_environments/envs/connectx/visualizer/default/src/style.css +38 -0
- kaggle_environments/envs/connectx/visualizer/default/tsconfig.json +4 -0
- kaggle_environments/envs/connectx/visualizer/default/vite.config.ts +7 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/index.html +13 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json +1 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +267 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.js +19 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +37 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.js +499 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json +7 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts +6 -0
- {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.3.dist-info}/METADATA +1 -1
- {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.3.dist-info}/RECORD +22 -5
- {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.3.dist-info}/WHEEL +0 -0
- {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.3.dist-info}/entry_points.txt +0 -0
- {kaggle_environments-1.23.1.dist-info → kaggle_environments-1.23.3.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,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
|
+
}
|