kaggle-environments 1.15.2__py2.py3-none-any.whl → 1.16.0__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.

Files changed (69) hide show
  1. kaggle_environments/__init__.py +1 -1
  2. kaggle_environments/envs/chess/chess.js +63 -22
  3. kaggle_environments/envs/chess/chess.json +4 -4
  4. kaggle_environments/envs/chess/chess.py +209 -51
  5. kaggle_environments/envs/chess/test_chess.py +43 -1
  6. kaggle_environments/envs/connectx/connectx.ipynb +3183 -0
  7. kaggle_environments/envs/football/football.ipynb +75 -0
  8. kaggle_environments/envs/halite/halite.ipynb +44736 -0
  9. kaggle_environments/envs/kore_fleets/kore_fleets.ipynb +112 -0
  10. kaggle_environments/envs/kore_fleets/starter_bots/java/Bot.java +54 -0
  11. kaggle_environments/envs/kore_fleets/starter_bots/java/README.md +26 -0
  12. kaggle_environments/envs/kore_fleets/starter_bots/java/jars/hamcrest-core-1.3.jar +0 -0
  13. kaggle_environments/envs/kore_fleets/starter_bots/java/jars/junit-4.13.2.jar +0 -0
  14. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Board.java +518 -0
  15. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Cell.java +61 -0
  16. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Configuration.java +24 -0
  17. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Direction.java +166 -0
  18. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Fleet.java +72 -0
  19. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/KoreJson.java +97 -0
  20. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Observation.java +72 -0
  21. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Pair.java +13 -0
  22. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Player.java +68 -0
  23. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Point.java +65 -0
  24. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Shipyard.java +70 -0
  25. kaggle_environments/envs/kore_fleets/starter_bots/java/kore/ShipyardAction.java +59 -0
  26. kaggle_environments/envs/kore_fleets/starter_bots/java/test/BoardTest.java +567 -0
  27. kaggle_environments/envs/kore_fleets/starter_bots/java/test/ConfigurationTest.java +25 -0
  28. kaggle_environments/envs/kore_fleets/starter_bots/java/test/KoreJsonTest.java +62 -0
  29. kaggle_environments/envs/kore_fleets/starter_bots/java/test/ObservationTest.java +46 -0
  30. kaggle_environments/envs/kore_fleets/starter_bots/java/test/PointTest.java +21 -0
  31. kaggle_environments/envs/kore_fleets/starter_bots/java/test/ShipyardTest.java +22 -0
  32. kaggle_environments/envs/kore_fleets/starter_bots/ts/README.md +55 -0
  33. kaggle_environments/envs/lux_ai_2021/README.md +3 -0
  34. kaggle_environments/envs/lux_ai_2021/dimensions/754.js.LICENSE.txt +296 -0
  35. kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/simple.tar.gz +0 -0
  36. kaggle_environments/envs/lux_ai_2021/testing.md +23 -0
  37. kaggle_environments/envs/lux_ai_2021/todo.md.og +18 -0
  38. kaggle_environments/envs/lux_ai_s2/.gitignore +1 -0
  39. kaggle_environments/envs/lux_ai_s2/README.md +21 -0
  40. kaggle_environments/envs/lux_ai_s2/luxai_s2/.DS_Store +0 -0
  41. kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/.DS_Store +0 -0
  42. kaggle_environments/envs/lux_ai_s3/README.md +21 -0
  43. kaggle_environments/envs/lux_ai_s3/agents.py +4 -0
  44. kaggle_environments/envs/lux_ai_s3/index.html +42 -0
  45. kaggle_environments/envs/lux_ai_s3/lux_ai_s3.json +47 -0
  46. kaggle_environments/envs/lux_ai_s3/lux_ai_s3.py +138 -0
  47. kaggle_environments/envs/lux_ai_s3/luxai_s3/__init__.py +1 -0
  48. kaggle_environments/envs/lux_ai_s3/luxai_s3/env.py +924 -0
  49. kaggle_environments/envs/lux_ai_s3/luxai_s3/globals.py +13 -0
  50. kaggle_environments/envs/lux_ai_s3/luxai_s3/params.py +101 -0
  51. kaggle_environments/envs/lux_ai_s3/luxai_s3/profiler.py +140 -0
  52. kaggle_environments/envs/lux_ai_s3/luxai_s3/pygame_render.py +270 -0
  53. kaggle_environments/envs/lux_ai_s3/luxai_s3/spaces.py +30 -0
  54. kaggle_environments/envs/lux_ai_s3/luxai_s3/state.py +399 -0
  55. kaggle_environments/envs/lux_ai_s3/luxai_s3/utils.py +12 -0
  56. kaggle_environments/envs/lux_ai_s3/luxai_s3/wrappers.py +187 -0
  57. kaggle_environments/envs/lux_ai_s3/test_agents/python/agent.py +71 -0
  58. kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/__init__.py +0 -0
  59. kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/kit.py +27 -0
  60. kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/utils.py +17 -0
  61. kaggle_environments/envs/lux_ai_s3/test_agents/python/main.py +53 -0
  62. kaggle_environments/envs/lux_ai_s3/test_lux.py +9 -0
  63. kaggle_environments/envs/tictactoe/tictactoe.ipynb +1393 -0
  64. {kaggle_environments-1.15.2.dist-info → kaggle_environments-1.16.0.dist-info}/METADATA +2 -2
  65. {kaggle_environments-1.15.2.dist-info → kaggle_environments-1.16.0.dist-info}/RECORD +69 -11
  66. {kaggle_environments-1.15.2.dist-info → kaggle_environments-1.16.0.dist-info}/WHEEL +1 -1
  67. {kaggle_environments-1.15.2.dist-info → kaggle_environments-1.16.0.dist-info}/LICENSE +0 -0
  68. {kaggle_environments-1.15.2.dist-info → kaggle_environments-1.16.0.dist-info}/entry_points.txt +0 -0
  69. {kaggle_environments-1.15.2.dist-info → kaggle_environments-1.16.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,3183 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# ConnectX - Kaggle Environment"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "code",
12
+ "execution_count": 1,
13
+ "metadata": {},
14
+ "outputs": [
15
+ {
16
+ "name": "stdout",
17
+ "output_type": "stream",
18
+ "text": [
19
+ "connectx 1.0.1\n",
20
+ "Default Agents: random negamax\n"
21
+ ]
22
+ }
23
+ ],
24
+ "source": [
25
+ "from kaggle_environments import make\n",
26
+ "env = make(\"connectx\")\n",
27
+ "print(env.name, env.version)\n",
28
+ "print(\"Default Agents: \", *env.agents)"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "markdown",
33
+ "metadata": {},
34
+ "source": [
35
+ "## TLDR;"
36
+ ]
37
+ },
38
+ {
39
+ "cell_type": "code",
40
+ "execution_count": 2,
41
+ "metadata": {},
42
+ "outputs": [
43
+ {
44
+ "data": {
45
+ "text/html": [
46
+ "<iframe srcdoc=\"<!--\n",
47
+ " Copyright 2020 Kaggle Inc\n",
48
+ "\n",
49
+ " Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
50
+ " you may not use this file except in compliance with the License.\n",
51
+ " You may obtain a copy of the License at\n",
52
+ "\n",
53
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
54
+ "\n",
55
+ " Unless required by applicable law or agreed to in writing, software\n",
56
+ " distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
57
+ " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
58
+ " See the License for the specific language governing permissions and\n",
59
+ " limitations under the License.\n",
60
+ "-->\n",
61
+ "<!DOCTYPE html>\n",
62
+ "<html lang=&quot;en&quot;>\n",
63
+ " <head>\n",
64
+ " <title>Kaggle Simulation Player</title>\n",
65
+ " <meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot; />\n",
66
+ " <link\n",
67
+ " rel=&quot;stylesheet&quot;\n",
68
+ " href=&quot;https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css&quot;\n",
69
+ " crossorigin=&quot;anonymous&quot;\n",
70
+ " />\n",
71
+ " <style type=&quot;text/css&quot;>\n",
72
+ " html,\n",
73
+ " body {\n",
74
+ " height: 100%;\n",
75
+ " font-family: sans-serif;\n",
76
+ " }\n",
77
+ " canvas {\n",
78
+ " /* image-rendering: -moz-crisp-edges;\n",
79
+ " image-rendering: -webkit-crisp-edges;\n",
80
+ " image-rendering: pixelated;\n",
81
+ " image-rendering: crisp-edges; */\n",
82
+ " }\n",
83
+ " </style>\n",
84
+ " <script src=&quot;https://unpkg.com/preact@10.0.1/dist/preact.umd.js&quot;></script>\n",
85
+ " <script src=&quot;https://unpkg.com/preact@10.0.1/hooks/dist/hooks.umd.js&quot;></script>\n",
86
+ " <script src=&quot;https://unpkg.com/htm@2.2.1/dist/htm.umd.js&quot;></script>\n",
87
+ " <script>\n",
88
+ " // Polyfill for Styled Components\n",
89
+ " window.React = {\n",
90
+ " ...preact,\n",
91
+ " createElement: preact.h,\n",
92
+ " PropTypes: { func: {} },\n",
93
+ " };\n",
94
+ " </script>\n",
95
+ " <script src=&quot;https://unpkg.com/styled-components@3.5.0-0/dist/styled-components.min.js&quot;></script>\n",
96
+ " </head>\n",
97
+ " <body>\n",
98
+ " <script>\n",
99
+ " \n",
100
+ "window.kaggle = {\n",
101
+ " &quot;debug&quot;: true,\n",
102
+ " &quot;autoplay&quot;: true,\n",
103
+ " &quot;step&quot;: 0,\n",
104
+ " &quot;controls&quot;: true,\n",
105
+ " &quot;environment&quot;: {\n",
106
+ " &quot;id&quot;: &quot;44d5d36c-8bfb-11ea-8609-acde48001122&quot;,\n",
107
+ " &quot;name&quot;: &quot;connectx&quot;,\n",
108
+ " &quot;title&quot;: &quot;ConnectX&quot;,\n",
109
+ " &quot;description&quot;: &quot;Classic Connect in a row but configurable.&quot;,\n",
110
+ " &quot;version&quot;: &quot;1.0.1&quot;,\n",
111
+ " &quot;configuration&quot;: {\n",
112
+ " &quot;episodeSteps&quot;: 1000,\n",
113
+ " &quot;agentExec&quot;: &quot;PROCESS&quot;,\n",
114
+ " &quot;agentTimeout&quot;: 10,\n",
115
+ " &quot;actTimeout&quot;: 2,\n",
116
+ " &quot;runTimeout&quot;: 600,\n",
117
+ " &quot;columns&quot;: 7,\n",
118
+ " &quot;rows&quot;: 6,\n",
119
+ " &quot;inarow&quot;: 4\n",
120
+ " },\n",
121
+ " &quot;specification&quot;: {\n",
122
+ " &quot;action&quot;: {\n",
123
+ " &quot;description&quot;: &quot;Column to drop a checker onto the board.&quot;,\n",
124
+ " &quot;type&quot;: &quot;integer&quot;,\n",
125
+ " &quot;minimum&quot;: 0,\n",
126
+ " &quot;default&quot;: 0\n",
127
+ " },\n",
128
+ " &quot;agents&quot;: [\n",
129
+ " 2\n",
130
+ " ],\n",
131
+ " &quot;configuration&quot;: {\n",
132
+ " &quot;episodeSteps&quot;: {\n",
133
+ " &quot;description&quot;: &quot;Maximum number of steps in the episode.&quot;,\n",
134
+ " &quot;type&quot;: &quot;integer&quot;,\n",
135
+ " &quot;minimum&quot;: 1,\n",
136
+ " &quot;default&quot;: 1000\n",
137
+ " },\n",
138
+ " &quot;agentExec&quot;: {\n",
139
+ " &quot;description&quot;: &quot;How the agent is executed alongside the running envionment.&quot;,\n",
140
+ " &quot;type&quot;: &quot;string&quot;,\n",
141
+ " &quot;default&quot;: &quot;PROCESS&quot;,\n",
142
+ " &quot;enum&quot;: [\n",
143
+ " &quot;LOCAL&quot;,\n",
144
+ " &quot;PROCESS&quot;\n",
145
+ " ]\n",
146
+ " },\n",
147
+ " &quot;agentTimeout&quot;: {\n",
148
+ " &quot;description&quot;: &quot;Maximum runtime (seconds) to initialize an agent.&quot;,\n",
149
+ " &quot;type&quot;: &quot;integer&quot;,\n",
150
+ " &quot;minimum&quot;: 1,\n",
151
+ " &quot;default&quot;: 10\n",
152
+ " },\n",
153
+ " &quot;actTimeout&quot;: {\n",
154
+ " &quot;description&quot;: &quot;Maximum runtime (seconds) to obtain an action from an agent.&quot;,\n",
155
+ " &quot;type&quot;: &quot;integer&quot;,\n",
156
+ " &quot;minimum&quot;: 1,\n",
157
+ " &quot;default&quot;: 2\n",
158
+ " },\n",
159
+ " &quot;runTimeout&quot;: {\n",
160
+ " &quot;description&quot;: &quot;Maximum runtime (seconds) of an episode (not necessarily DONE).&quot;,\n",
161
+ " &quot;type&quot;: &quot;integer&quot;,\n",
162
+ " &quot;minimum&quot;: 1,\n",
163
+ " &quot;default&quot;: 600\n",
164
+ " },\n",
165
+ " &quot;columns&quot;: {\n",
166
+ " &quot;description&quot;: &quot;The number of columns on the board&quot;,\n",
167
+ " &quot;type&quot;: &quot;integer&quot;,\n",
168
+ " &quot;default&quot;: 7,\n",
169
+ " &quot;minimum&quot;: 1\n",
170
+ " },\n",
171
+ " &quot;rows&quot;: {\n",
172
+ " &quot;description&quot;: &quot;The number of rows on the board&quot;,\n",
173
+ " &quot;type&quot;: &quot;integer&quot;,\n",
174
+ " &quot;default&quot;: 6,\n",
175
+ " &quot;minimum&quot;: 1\n",
176
+ " },\n",
177
+ " &quot;inarow&quot;: {\n",
178
+ " &quot;description&quot;: &quot;The number of checkers in a row required to win.&quot;,\n",
179
+ " &quot;type&quot;: &quot;integer&quot;,\n",
180
+ " &quot;default&quot;: 4,\n",
181
+ " &quot;minimum&quot;: 1\n",
182
+ " }\n",
183
+ " },\n",
184
+ " &quot;info&quot;: {},\n",
185
+ " &quot;observation&quot;: {\n",
186
+ " &quot;board&quot;: {\n",
187
+ " &quot;description&quot;: &quot;Serialized grid (rows x columns). 0 = Empty, 1 = P1, 2 = P2&quot;,\n",
188
+ " &quot;type&quot;: &quot;array&quot;,\n",
189
+ " &quot;shared&quot;: true,\n",
190
+ " &quot;default&quot;: []\n",
191
+ " },\n",
192
+ " &quot;mark&quot;: {\n",
193
+ " &quot;defaults&quot;: [\n",
194
+ " 1,\n",
195
+ " 2\n",
196
+ " ],\n",
197
+ " &quot;description&quot;: &quot;Which checkers are the agents.&quot;,\n",
198
+ " &quot;enum&quot;: [\n",
199
+ " 1,\n",
200
+ " 2\n",
201
+ " ]\n",
202
+ " }\n",
203
+ " },\n",
204
+ " &quot;reward&quot;: {\n",
205
+ " &quot;description&quot;: &quot;-1 = Lost, 0 = Draw/Ongoing, 1 = Won&quot;,\n",
206
+ " &quot;enum&quot;: [\n",
207
+ " -1,\n",
208
+ " 0,\n",
209
+ " 1\n",
210
+ " ],\n",
211
+ " &quot;default&quot;: 0,\n",
212
+ " &quot;type&quot;: [\n",
213
+ " &quot;number&quot;,\n",
214
+ " &quot;null&quot;\n",
215
+ " ]\n",
216
+ " }\n",
217
+ " },\n",
218
+ " &quot;steps&quot;: [\n",
219
+ " [\n",
220
+ " {\n",
221
+ " &quot;action&quot;: 0,\n",
222
+ " &quot;reward&quot;: 0,\n",
223
+ " &quot;info&quot;: {},\n",
224
+ " &quot;observation&quot;: {\n",
225
+ " &quot;board&quot;: [\n",
226
+ " 0,\n",
227
+ " 0,\n",
228
+ " 0,\n",
229
+ " 0,\n",
230
+ " 0,\n",
231
+ " 0,\n",
232
+ " 0,\n",
233
+ " 0,\n",
234
+ " 0,\n",
235
+ " 0,\n",
236
+ " 0,\n",
237
+ " 0,\n",
238
+ " 0,\n",
239
+ " 0,\n",
240
+ " 0,\n",
241
+ " 0,\n",
242
+ " 0,\n",
243
+ " 0,\n",
244
+ " 0,\n",
245
+ " 0,\n",
246
+ " 0,\n",
247
+ " 0,\n",
248
+ " 0,\n",
249
+ " 0,\n",
250
+ " 0,\n",
251
+ " 0,\n",
252
+ " 0,\n",
253
+ " 0,\n",
254
+ " 0,\n",
255
+ " 0,\n",
256
+ " 0,\n",
257
+ " 0,\n",
258
+ " 0,\n",
259
+ " 0,\n",
260
+ " 0,\n",
261
+ " 0,\n",
262
+ " 0,\n",
263
+ " 0,\n",
264
+ " 0,\n",
265
+ " 0,\n",
266
+ " 0,\n",
267
+ " 0\n",
268
+ " ],\n",
269
+ " &quot;mark&quot;: 1\n",
270
+ " },\n",
271
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
272
+ " },\n",
273
+ " {\n",
274
+ " &quot;action&quot;: 0,\n",
275
+ " &quot;reward&quot;: 0,\n",
276
+ " &quot;info&quot;: {},\n",
277
+ " &quot;observation&quot;: {\n",
278
+ " &quot;mark&quot;: 2\n",
279
+ " },\n",
280
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
281
+ " }\n",
282
+ " ],\n",
283
+ " [\n",
284
+ " {\n",
285
+ " &quot;action&quot;: 0,\n",
286
+ " &quot;reward&quot;: 0,\n",
287
+ " &quot;info&quot;: {},\n",
288
+ " &quot;observation&quot;: {\n",
289
+ " &quot;board&quot;: [\n",
290
+ " 0,\n",
291
+ " 0,\n",
292
+ " 0,\n",
293
+ " 0,\n",
294
+ " 0,\n",
295
+ " 0,\n",
296
+ " 0,\n",
297
+ " 0,\n",
298
+ " 0,\n",
299
+ " 0,\n",
300
+ " 0,\n",
301
+ " 0,\n",
302
+ " 0,\n",
303
+ " 0,\n",
304
+ " 0,\n",
305
+ " 0,\n",
306
+ " 0,\n",
307
+ " 0,\n",
308
+ " 0,\n",
309
+ " 0,\n",
310
+ " 0,\n",
311
+ " 0,\n",
312
+ " 0,\n",
313
+ " 0,\n",
314
+ " 0,\n",
315
+ " 0,\n",
316
+ " 0,\n",
317
+ " 0,\n",
318
+ " 0,\n",
319
+ " 0,\n",
320
+ " 0,\n",
321
+ " 0,\n",
322
+ " 0,\n",
323
+ " 0,\n",
324
+ " 0,\n",
325
+ " 1,\n",
326
+ " 0,\n",
327
+ " 0,\n",
328
+ " 0,\n",
329
+ " 0,\n",
330
+ " 0,\n",
331
+ " 0\n",
332
+ " ],\n",
333
+ " &quot;mark&quot;: 1\n",
334
+ " },\n",
335
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
336
+ " },\n",
337
+ " {\n",
338
+ " &quot;action&quot;: 0,\n",
339
+ " &quot;reward&quot;: 0,\n",
340
+ " &quot;info&quot;: {},\n",
341
+ " &quot;observation&quot;: {\n",
342
+ " &quot;mark&quot;: 2\n",
343
+ " },\n",
344
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
345
+ " }\n",
346
+ " ],\n",
347
+ " [\n",
348
+ " {\n",
349
+ " &quot;action&quot;: 0,\n",
350
+ " &quot;reward&quot;: 0,\n",
351
+ " &quot;info&quot;: {},\n",
352
+ " &quot;observation&quot;: {\n",
353
+ " &quot;board&quot;: [\n",
354
+ " 0,\n",
355
+ " 0,\n",
356
+ " 0,\n",
357
+ " 0,\n",
358
+ " 0,\n",
359
+ " 0,\n",
360
+ " 0,\n",
361
+ " 0,\n",
362
+ " 0,\n",
363
+ " 0,\n",
364
+ " 0,\n",
365
+ " 0,\n",
366
+ " 0,\n",
367
+ " 0,\n",
368
+ " 0,\n",
369
+ " 0,\n",
370
+ " 0,\n",
371
+ " 0,\n",
372
+ " 0,\n",
373
+ " 0,\n",
374
+ " 0,\n",
375
+ " 0,\n",
376
+ " 0,\n",
377
+ " 0,\n",
378
+ " 0,\n",
379
+ " 0,\n",
380
+ " 0,\n",
381
+ " 0,\n",
382
+ " 0,\n",
383
+ " 0,\n",
384
+ " 0,\n",
385
+ " 0,\n",
386
+ " 0,\n",
387
+ " 0,\n",
388
+ " 0,\n",
389
+ " 1,\n",
390
+ " 0,\n",
391
+ " 2,\n",
392
+ " 0,\n",
393
+ " 0,\n",
394
+ " 0,\n",
395
+ " 0\n",
396
+ " ],\n",
397
+ " &quot;mark&quot;: 1\n",
398
+ " },\n",
399
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
400
+ " },\n",
401
+ " {\n",
402
+ " &quot;action&quot;: 2,\n",
403
+ " &quot;reward&quot;: 0,\n",
404
+ " &quot;info&quot;: {},\n",
405
+ " &quot;observation&quot;: {\n",
406
+ " &quot;mark&quot;: 2\n",
407
+ " },\n",
408
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
409
+ " }\n",
410
+ " ],\n",
411
+ " [\n",
412
+ " {\n",
413
+ " &quot;action&quot;: 0,\n",
414
+ " &quot;reward&quot;: 0,\n",
415
+ " &quot;info&quot;: {},\n",
416
+ " &quot;observation&quot;: {\n",
417
+ " &quot;board&quot;: [\n",
418
+ " 0,\n",
419
+ " 0,\n",
420
+ " 0,\n",
421
+ " 0,\n",
422
+ " 0,\n",
423
+ " 0,\n",
424
+ " 0,\n",
425
+ " 0,\n",
426
+ " 0,\n",
427
+ " 0,\n",
428
+ " 0,\n",
429
+ " 0,\n",
430
+ " 0,\n",
431
+ " 0,\n",
432
+ " 0,\n",
433
+ " 0,\n",
434
+ " 0,\n",
435
+ " 0,\n",
436
+ " 0,\n",
437
+ " 0,\n",
438
+ " 0,\n",
439
+ " 0,\n",
440
+ " 0,\n",
441
+ " 0,\n",
442
+ " 0,\n",
443
+ " 0,\n",
444
+ " 0,\n",
445
+ " 0,\n",
446
+ " 1,\n",
447
+ " 0,\n",
448
+ " 0,\n",
449
+ " 0,\n",
450
+ " 0,\n",
451
+ " 0,\n",
452
+ " 0,\n",
453
+ " 1,\n",
454
+ " 0,\n",
455
+ " 2,\n",
456
+ " 0,\n",
457
+ " 0,\n",
458
+ " 0,\n",
459
+ " 0\n",
460
+ " ],\n",
461
+ " &quot;mark&quot;: 1\n",
462
+ " },\n",
463
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
464
+ " },\n",
465
+ " {\n",
466
+ " &quot;action&quot;: 0,\n",
467
+ " &quot;reward&quot;: 0,\n",
468
+ " &quot;info&quot;: {},\n",
469
+ " &quot;observation&quot;: {\n",
470
+ " &quot;mark&quot;: 2\n",
471
+ " },\n",
472
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
473
+ " }\n",
474
+ " ],\n",
475
+ " [\n",
476
+ " {\n",
477
+ " &quot;action&quot;: 0,\n",
478
+ " &quot;reward&quot;: 0,\n",
479
+ " &quot;info&quot;: {},\n",
480
+ " &quot;observation&quot;: {\n",
481
+ " &quot;board&quot;: [\n",
482
+ " 0,\n",
483
+ " 0,\n",
484
+ " 0,\n",
485
+ " 0,\n",
486
+ " 0,\n",
487
+ " 0,\n",
488
+ " 0,\n",
489
+ " 0,\n",
490
+ " 0,\n",
491
+ " 0,\n",
492
+ " 0,\n",
493
+ " 0,\n",
494
+ " 0,\n",
495
+ " 0,\n",
496
+ " 0,\n",
497
+ " 0,\n",
498
+ " 0,\n",
499
+ " 0,\n",
500
+ " 0,\n",
501
+ " 0,\n",
502
+ " 0,\n",
503
+ " 0,\n",
504
+ " 0,\n",
505
+ " 0,\n",
506
+ " 0,\n",
507
+ " 0,\n",
508
+ " 0,\n",
509
+ " 0,\n",
510
+ " 1,\n",
511
+ " 0,\n",
512
+ " 0,\n",
513
+ " 0,\n",
514
+ " 0,\n",
515
+ " 0,\n",
516
+ " 0,\n",
517
+ " 1,\n",
518
+ " 2,\n",
519
+ " 2,\n",
520
+ " 0,\n",
521
+ " 0,\n",
522
+ " 0,\n",
523
+ " 0\n",
524
+ " ],\n",
525
+ " &quot;mark&quot;: 1\n",
526
+ " },\n",
527
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
528
+ " },\n",
529
+ " {\n",
530
+ " &quot;action&quot;: 1,\n",
531
+ " &quot;reward&quot;: 0,\n",
532
+ " &quot;info&quot;: {},\n",
533
+ " &quot;observation&quot;: {\n",
534
+ " &quot;mark&quot;: 2\n",
535
+ " },\n",
536
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
537
+ " }\n",
538
+ " ],\n",
539
+ " [\n",
540
+ " {\n",
541
+ " &quot;action&quot;: 0,\n",
542
+ " &quot;reward&quot;: 0,\n",
543
+ " &quot;info&quot;: {},\n",
544
+ " &quot;observation&quot;: {\n",
545
+ " &quot;board&quot;: [\n",
546
+ " 0,\n",
547
+ " 0,\n",
548
+ " 0,\n",
549
+ " 0,\n",
550
+ " 0,\n",
551
+ " 0,\n",
552
+ " 0,\n",
553
+ " 0,\n",
554
+ " 0,\n",
555
+ " 0,\n",
556
+ " 0,\n",
557
+ " 0,\n",
558
+ " 0,\n",
559
+ " 0,\n",
560
+ " 0,\n",
561
+ " 0,\n",
562
+ " 0,\n",
563
+ " 0,\n",
564
+ " 0,\n",
565
+ " 0,\n",
566
+ " 0,\n",
567
+ " 1,\n",
568
+ " 0,\n",
569
+ " 0,\n",
570
+ " 0,\n",
571
+ " 0,\n",
572
+ " 0,\n",
573
+ " 0,\n",
574
+ " 1,\n",
575
+ " 0,\n",
576
+ " 0,\n",
577
+ " 0,\n",
578
+ " 0,\n",
579
+ " 0,\n",
580
+ " 0,\n",
581
+ " 1,\n",
582
+ " 2,\n",
583
+ " 2,\n",
584
+ " 0,\n",
585
+ " 0,\n",
586
+ " 0,\n",
587
+ " 0\n",
588
+ " ],\n",
589
+ " &quot;mark&quot;: 1\n",
590
+ " },\n",
591
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
592
+ " },\n",
593
+ " {\n",
594
+ " &quot;action&quot;: 0,\n",
595
+ " &quot;reward&quot;: 0,\n",
596
+ " &quot;info&quot;: {},\n",
597
+ " &quot;observation&quot;: {\n",
598
+ " &quot;mark&quot;: 2\n",
599
+ " },\n",
600
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
601
+ " }\n",
602
+ " ],\n",
603
+ " [\n",
604
+ " {\n",
605
+ " &quot;action&quot;: 0,\n",
606
+ " &quot;reward&quot;: 0,\n",
607
+ " &quot;info&quot;: {},\n",
608
+ " &quot;observation&quot;: {\n",
609
+ " &quot;board&quot;: [\n",
610
+ " 0,\n",
611
+ " 0,\n",
612
+ " 0,\n",
613
+ " 0,\n",
614
+ " 0,\n",
615
+ " 0,\n",
616
+ " 0,\n",
617
+ " 0,\n",
618
+ " 0,\n",
619
+ " 0,\n",
620
+ " 0,\n",
621
+ " 0,\n",
622
+ " 0,\n",
623
+ " 0,\n",
624
+ " 0,\n",
625
+ " 0,\n",
626
+ " 0,\n",
627
+ " 0,\n",
628
+ " 0,\n",
629
+ " 0,\n",
630
+ " 0,\n",
631
+ " 1,\n",
632
+ " 0,\n",
633
+ " 0,\n",
634
+ " 0,\n",
635
+ " 0,\n",
636
+ " 0,\n",
637
+ " 0,\n",
638
+ " 1,\n",
639
+ " 0,\n",
640
+ " 0,\n",
641
+ " 0,\n",
642
+ " 0,\n",
643
+ " 0,\n",
644
+ " 0,\n",
645
+ " 1,\n",
646
+ " 2,\n",
647
+ " 2,\n",
648
+ " 0,\n",
649
+ " 0,\n",
650
+ " 0,\n",
651
+ " 2\n",
652
+ " ],\n",
653
+ " &quot;mark&quot;: 1\n",
654
+ " },\n",
655
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
656
+ " },\n",
657
+ " {\n",
658
+ " &quot;action&quot;: 6,\n",
659
+ " &quot;reward&quot;: 0,\n",
660
+ " &quot;info&quot;: {},\n",
661
+ " &quot;observation&quot;: {\n",
662
+ " &quot;mark&quot;: 2\n",
663
+ " },\n",
664
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
665
+ " }\n",
666
+ " ],\n",
667
+ " [\n",
668
+ " {\n",
669
+ " &quot;action&quot;: 0,\n",
670
+ " &quot;reward&quot;: 1,\n",
671
+ " &quot;info&quot;: {},\n",
672
+ " &quot;observation&quot;: {\n",
673
+ " &quot;board&quot;: [\n",
674
+ " 0,\n",
675
+ " 0,\n",
676
+ " 0,\n",
677
+ " 0,\n",
678
+ " 0,\n",
679
+ " 0,\n",
680
+ " 0,\n",
681
+ " 0,\n",
682
+ " 0,\n",
683
+ " 0,\n",
684
+ " 0,\n",
685
+ " 0,\n",
686
+ " 0,\n",
687
+ " 0,\n",
688
+ " 1,\n",
689
+ " 0,\n",
690
+ " 0,\n",
691
+ " 0,\n",
692
+ " 0,\n",
693
+ " 0,\n",
694
+ " 0,\n",
695
+ " 1,\n",
696
+ " 0,\n",
697
+ " 0,\n",
698
+ " 0,\n",
699
+ " 0,\n",
700
+ " 0,\n",
701
+ " 0,\n",
702
+ " 1,\n",
703
+ " 0,\n",
704
+ " 0,\n",
705
+ " 0,\n",
706
+ " 0,\n",
707
+ " 0,\n",
708
+ " 0,\n",
709
+ " 1,\n",
710
+ " 2,\n",
711
+ " 2,\n",
712
+ " 0,\n",
713
+ " 0,\n",
714
+ " 0,\n",
715
+ " 2\n",
716
+ " ],\n",
717
+ " &quot;mark&quot;: 1\n",
718
+ " },\n",
719
+ " &quot;status&quot;: &quot;DONE&quot;\n",
720
+ " },\n",
721
+ " {\n",
722
+ " &quot;action&quot;: 0,\n",
723
+ " &quot;reward&quot;: -1,\n",
724
+ " &quot;info&quot;: {},\n",
725
+ " &quot;observation&quot;: {\n",
726
+ " &quot;mark&quot;: 2\n",
727
+ " },\n",
728
+ " &quot;status&quot;: &quot;DONE&quot;\n",
729
+ " }\n",
730
+ " ]\n",
731
+ " ],\n",
732
+ " &quot;rewards&quot;: [\n",
733
+ " 1,\n",
734
+ " -1\n",
735
+ " ],\n",
736
+ " &quot;statuses&quot;: [\n",
737
+ " &quot;DONE&quot;,\n",
738
+ " &quot;DONE&quot;\n",
739
+ " ],\n",
740
+ " &quot;schema_version&quot;: 1\n",
741
+ " },\n",
742
+ " &quot;mode&quot;: &quot;ipython&quot;,\n",
743
+ " &quot;width&quot;: 600,\n",
744
+ " &quot;height&quot;: 500,\n",
745
+ " &quot;header&quot;: false\n",
746
+ "};\n",
747
+ "\n",
748
+ "\n",
749
+ "window.kaggle.renderer = // Copyright 2020 Kaggle Inc\n",
750
+ "//\n",
751
+ "// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
752
+ "// you may not use this file except in compliance with the License.\n",
753
+ "// You may obtain a copy of the License at\n",
754
+ "//\n",
755
+ "// http://www.apache.org/licenses/LICENSE-2.0\n",
756
+ "//\n",
757
+ "// Unless required by applicable law or agreed to in writing, software\n",
758
+ "// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
759
+ "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
760
+ "// See the License for the specific language governing permissions and\n",
761
+ "// limitations under the License.\n",
762
+ "\n",
763
+ "function renderer({\n",
764
+ " act,\n",
765
+ " agents,\n",
766
+ " environment,\n",
767
+ " frame,\n",
768
+ " height = 400,\n",
769
+ " interactive,\n",
770
+ " isInteractive,\n",
771
+ " parent,\n",
772
+ " step,\n",
773
+ " update,\n",
774
+ " width = 400,\n",
775
+ "}) {\n",
776
+ " // Configuration.\n",
777
+ " const { rows, columns, inarow } = environment.configuration;\n",
778
+ "\n",
779
+ " // Common Dimensions.\n",
780
+ " const unit = 8;\n",
781
+ " const minCanvasSize = Math.min(height, width);\n",
782
+ " const minOffset = minCanvasSize > 400 ? 30 : unit / 2;\n",
783
+ " const cellSize = Math.min(\n",
784
+ " (width - minOffset * 2) / columns,\n",
785
+ " (height - minOffset * 2) / rows\n",
786
+ " );\n",
787
+ " const cellInset = 0.8;\n",
788
+ " const pieceScale = cellSize / 100;\n",
789
+ " const xOffset = Math.max(0, (width - cellSize * columns) / 2);\n",
790
+ " const yOffset = Math.max(0, (height - cellSize * rows) / 2);\n",
791
+ "\n",
792
+ " // Canvas Setup.\n",
793
+ " let canvas = parent.querySelector(&quot;canvas&quot;);\n",
794
+ " if (!canvas) {\n",
795
+ " canvas = document.createElement(&quot;canvas&quot;);\n",
796
+ " parent.appendChild(canvas);\n",
797
+ "\n",
798
+ " if (interactive) {\n",
799
+ " canvas.addEventListener(&quot;click&quot;, evt => {\n",
800
+ " if (!isInteractive()) return;\n",
801
+ " const rect = evt.target.getBoundingClientRect();\n",
802
+ " const col = Math.floor((evt.clientX - rect.left - xOffset) / cellSize);\n",
803
+ " if (col >= 0 && col < columns) act(col);\n",
804
+ " });\n",
805
+ " }\n",
806
+ " }\n",
807
+ " canvas.style.cursor = isInteractive() ? &quot;pointer&quot; : &quot;default&quot;;\n",
808
+ "\n",
809
+ " // Character Paths (based on 100x100 tiles).\n",
810
+ " const kPath = new Path2D(\n",
811
+ " `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`\n",
812
+ " );\n",
813
+ " const goose1Path = new Path2D(\n",
814
+ " `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`\n",
815
+ " );\n",
816
+ " const goose2Path = new Path2D(\n",
817
+ " `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`\n",
818
+ " );\n",
819
+ " const goose3Path = new Path2D(\n",
820
+ " `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`\n",
821
+ " );\n",
822
+ "\n",
823
+ " // Canvas setup and reset.\n",
824
+ " let c = canvas.getContext(&quot;2d&quot;);\n",
825
+ " canvas.width = width;\n",
826
+ " canvas.height = height;\n",
827
+ " c.fillStyle = &quot;#000B2A&quot;;\n",
828
+ " c.fillRect(0, 0, canvas.width, canvas.height);\n",
829
+ "\n",
830
+ " const getRowCol = cell => [Math.floor(cell / columns), cell % columns];\n",
831
+ "\n",
832
+ " const getColor = (mark, opacity = 1) => {\n",
833
+ " if (mark === 1) return `rgba(0,255,255,${opacity})`;\n",
834
+ " if (mark === 2) return `rgba(255,255,255,${opacity})`;\n",
835
+ " return &quot;#fff&quot;;\n",
836
+ " };\n",
837
+ "\n",
838
+ " const drawCellCircle = (cell, xFrame = 1, yFrame = 1, radiusOffset = 0) => {\n",
839
+ " const [row, col] = getRowCol(cell);\n",
840
+ " c.arc(\n",
841
+ " xOffset + xFrame * (col * cellSize + cellSize / 2),\n",
842
+ " yOffset + yFrame * (row * cellSize + cellSize / 2),\n",
843
+ " (cellInset * cellSize) / 2 - radiusOffset,\n",
844
+ " 2 * Math.PI,\n",
845
+ " false\n",
846
+ " );\n",
847
+ " };\n",
848
+ "\n",
849
+ " // Render the pieces.\n",
850
+ " const board = environment.steps[step][0].observation.board;\n",
851
+ "\n",
852
+ " const drawPiece = mark => {\n",
853
+ " // Base Styles.\n",
854
+ " const opacity = minCanvasSize < 300 ? 0.6 - minCanvasSize / 1000 : 0.1;\n",
855
+ " c.fillStyle = getColor(mark, opacity);\n",
856
+ " c.strokeStyle = getColor(mark);\n",
857
+ " c.shadowColor = getColor(mark);\n",
858
+ " c.shadowBlur = 8 / cellInset;\n",
859
+ " c.lineWidth = 1 / cellInset;\n",
860
+ "\n",
861
+ " // Outer circle.\n",
862
+ " c.save();\n",
863
+ " c.beginPath();\n",
864
+ " c.arc(50, 50, 50, 2 * Math.PI, false);\n",
865
+ " c.closePath();\n",
866
+ " c.lineWidth *= 4;\n",
867
+ " c.stroke();\n",
868
+ " c.fill();\n",
869
+ " c.restore();\n",
870
+ "\n",
871
+ " // Inner circle.\n",
872
+ " c.beginPath();\n",
873
+ " c.arc(50, 50, 40, 2 * Math.PI, false);\n",
874
+ " c.closePath();\n",
875
+ " c.stroke();\n",
876
+ "\n",
877
+ " // Kaggle &quot;K&quot;.\n",
878
+ " if (mark === 1) {\n",
879
+ " const scale = 0.54;\n",
880
+ " c.save();\n",
881
+ " c.translate(23, 23);\n",
882
+ " c.scale(scale, scale);\n",
883
+ " c.lineWidth /= scale;\n",
884
+ " c.shadowBlur /= scale;\n",
885
+ " c.stroke(kPath);\n",
886
+ " c.restore();\n",
887
+ " }\n",
888
+ "\n",
889
+ " // Kaggle &quot;Goose&quot;.\n",
890
+ " if (mark === 2) {\n",
891
+ " const scale = 0.6;\n",
892
+ " c.save();\n",
893
+ " c.translate(24, 28);\n",
894
+ " c.scale(scale, scale);\n",
895
+ " c.lineWidth /= scale;\n",
896
+ " c.shadowBlur /= scale;\n",
897
+ " c.stroke(goose1Path);\n",
898
+ " c.stroke(goose2Path);\n",
899
+ " c.stroke(goose3Path);\n",
900
+ " c.beginPath();\n",
901
+ " c.arc(38.5, 18.6, 2.7, 0, Math.PI * 2, false);\n",
902
+ " c.closePath();\n",
903
+ " c.fill();\n",
904
+ " c.restore();\n",
905
+ " }\n",
906
+ " };\n",
907
+ "\n",
908
+ " for (let i = 0; i < board.length; i++) {\n",
909
+ " const [row, col] = getRowCol(i);\n",
910
+ " if (board[i] === 0) continue;\n",
911
+ " // Easing In.\n",
912
+ " let yFrame = Math.min(\n",
913
+ " (columns * Math.pow(frame, 3)) / Math.floor(i / columns),\n",
914
+ " 1\n",
915
+ " );\n",
916
+ "\n",
917
+ " if (\n",
918
+ " step > 1 &&\n",
919
+ " environment.steps[step - 1][0].observation.board[i] === board[i]\n",
920
+ " ) {\n",
921
+ " yFrame = 1;\n",
922
+ " }\n",
923
+ "\n",
924
+ " c.save();\n",
925
+ " c.translate(\n",
926
+ " xOffset + cellSize * col + (cellSize - cellSize * cellInset) / 2,\n",
927
+ " yOffset +\n",
928
+ " yFrame * (cellSize * row) +\n",
929
+ " (cellSize - cellSize * cellInset) / 2\n",
930
+ " );\n",
931
+ " c.scale(pieceScale * cellInset, pieceScale * cellInset);\n",
932
+ " drawPiece(board[i]);\n",
933
+ " c.restore();\n",
934
+ " }\n",
935
+ "\n",
936
+ " // Background Gradient.\n",
937
+ " const bgRadius = (Math.min(rows, columns) * cellSize) / 2;\n",
938
+ " const bgStyle = c.createRadialGradient(\n",
939
+ " xOffset + (cellSize * columns) / 2,\n",
940
+ " yOffset + (cellSize * rows) / 2,\n",
941
+ " 0,\n",
942
+ " xOffset + (cellSize * columns) / 2,\n",
943
+ " yOffset + (cellSize * rows) / 2,\n",
944
+ " bgRadius\n",
945
+ " );\n",
946
+ " bgStyle.addColorStop(0, &quot;#000B49&quot;);\n",
947
+ " bgStyle.addColorStop(1, &quot;#000B2A&quot;);\n",
948
+ "\n",
949
+ " // Render the board overlay.\n",
950
+ " c.beginPath();\n",
951
+ " c.rect(0, 0, canvas.width, canvas.height);\n",
952
+ " c.closePath();\n",
953
+ " c.shadowBlur = 0;\n",
954
+ " for (let i = 0; i < board.length; i++) {\n",
955
+ " drawCellCircle(i);\n",
956
+ " c.closePath();\n",
957
+ " }\n",
958
+ " c.fillStyle = bgStyle;\n",
959
+ " c.fill(&quot;evenodd&quot;);\n",
960
+ "\n",
961
+ " // Render the board overlay cell outlines.\n",
962
+ " for (let i = 0; i < board.length; i++) {\n",
963
+ " c.beginPath();\n",
964
+ " drawCellCircle(i);\n",
965
+ " c.strokeStyle = &quot;#0361B2&quot;;\n",
966
+ " c.lineWidth = 1;\n",
967
+ " c.stroke();\n",
968
+ " c.closePath();\n",
969
+ " }\n",
970
+ "\n",
971
+ " const drawLine = (fromCell, toCell) => {\n",
972
+ " if (frame < 0.5) return;\n",
973
+ " const lineFrame = (frame - 0.5) / 0.5;\n",
974
+ " const x1 = xOffset + (fromCell % columns) * cellSize + cellSize / 2;\n",
975
+ " const x2 =\n",
976
+ " x1 +\n",
977
+ " lineFrame *\n",
978
+ " (xOffset + ((toCell % columns) * cellSize + cellSize / 2) - x1);\n",
979
+ " const y1 =\n",
980
+ " yOffset + Math.floor(fromCell / columns) * cellSize + cellSize / 2;\n",
981
+ " const y2 =\n",
982
+ " y1 +\n",
983
+ " lineFrame *\n",
984
+ " (yOffset + Math.floor(toCell / columns) * cellSize + cellSize / 2 - y1);\n",
985
+ " c.beginPath();\n",
986
+ " c.lineCap = &quot;round&quot;;\n",
987
+ " c.lineWidth = 4;\n",
988
+ " c.strokeStyle = getColor(board[fromCell]);\n",
989
+ " c.shadowBlur = 8;\n",
990
+ " c.shadowColor = getColor(board[fromCell]);\n",
991
+ " c.moveTo(x1, y1);\n",
992
+ " c.lineTo(x2, y2);\n",
993
+ " c.stroke();\n",
994
+ " };\n",
995
+ "\n",
996
+ " // Generate a graph of the board.\n",
997
+ " const getCell = (cell, rowOffset, columnOffset) => {\n",
998
+ " const row = Math.floor(cell / columns) + rowOffset;\n",
999
+ " const col = (cell % columns) + columnOffset;\n",
1000
+ " if (row < 0 || row >= rows || col < 0 || col >= columns) return -1;\n",
1001
+ " return col + row * columns;\n",
1002
+ " };\n",
1003
+ " const makeNode = cell => {\n",
1004
+ " const node = { cell, directions: [], value: board[cell] };\n",
1005
+ " for (let r = -1; r <= 1; r++) {\n",
1006
+ " for (let c = -1; c <= 1; c++) {\n",
1007
+ " if (r === 0 && c === 0) continue;\n",
1008
+ " node.directions.push(getCell(cell, r, c));\n",
1009
+ " }\n",
1010
+ " }\n",
1011
+ " return node;\n",
1012
+ " };\n",
1013
+ " const graph = board.map((_, i) => makeNode(i));\n",
1014
+ "\n",
1015
+ " // Check for any wins!\n",
1016
+ " const getSequence = (node, direction) => {\n",
1017
+ " const sequence = [node.cell];\n",
1018
+ " while (sequence.length < inarow) {\n",
1019
+ " const next = graph[node.directions[direction]];\n",
1020
+ " if (!next || node.value !== next.value || next.value === 0) return;\n",
1021
+ " node = next;\n",
1022
+ " sequence.push(node.cell);\n",
1023
+ " }\n",
1024
+ " return sequence;\n",
1025
+ " };\n",
1026
+ "\n",
1027
+ " // Check all nodes.\n",
1028
+ " for (let i = 0; i < board.length; i++) {\n",
1029
+ " // Check all directions (not the most efficient).\n",
1030
+ " for (let d = 0; d < 8; d++) {\n",
1031
+ " const seq = getSequence(graph[i], d);\n",
1032
+ " if (seq) {\n",
1033
+ " drawLine(seq[0], seq[3]);\n",
1034
+ " i = board.length;\n",
1035
+ " break;\n",
1036
+ " }\n",
1037
+ " }\n",
1038
+ " }\n",
1039
+ "\n",
1040
+ " // Upgrade the legend.\n",
1041
+ " if (agents.length && (!agents[0].color || !agents[0].image)) {\n",
1042
+ " const getPieceImage = mark => {\n",
1043
+ " const pieceCanvas = document.createElement(&quot;canvas&quot;);\n",
1044
+ " parent.appendChild(pieceCanvas);\n",
1045
+ " pieceCanvas.style.marginLeft = &quot;10000px&quot;;\n",
1046
+ " pieceCanvas.width = 100;\n",
1047
+ " pieceCanvas.height = 100;\n",
1048
+ " c = pieceCanvas.getContext(&quot;2d&quot;);\n",
1049
+ " c.translate(10, 10);\n",
1050
+ " c.scale(0.8, 0.8);\n",
1051
+ " drawPiece(mark);\n",
1052
+ " const dataUrl = pieceCanvas.toDataURL();\n",
1053
+ " parent.removeChild(pieceCanvas);\n",
1054
+ " return dataUrl;\n",
1055
+ " };\n",
1056
+ "\n",
1057
+ " agents.forEach(agent => {\n",
1058
+ " agent.color = getColor(agent.index + 1);\n",
1059
+ " agent.image = getPieceImage(agent.index + 1);\n",
1060
+ " });\n",
1061
+ " update({ agents });\n",
1062
+ " }\n",
1063
+ "};\n",
1064
+ "\n",
1065
+ "\n",
1066
+ " \n",
1067
+ " </script>\n",
1068
+ " <script>\n",
1069
+ " const h = htm.bind(preact.h);\n",
1070
+ " const { useContext, useEffect, useRef, useState } = preactHooks;\n",
1071
+ " const styled = window.styled.default;\n",
1072
+ "\n",
1073
+ " const Context = preact.createContext({});\n",
1074
+ "\n",
1075
+ " const Loading = styled.div`\n",
1076
+ " animation: rotate360 1.1s infinite linear;\n",
1077
+ " border: 8px solid rgba(255, 255, 255, 0.2);\n",
1078
+ " border-left-color: #0cb1ed;\n",
1079
+ " border-radius: 50%;\n",
1080
+ " height: 40px;\n",
1081
+ " position: relative;\n",
1082
+ " transform: translateZ(0);\n",
1083
+ " width: 40px;\n",
1084
+ "\n",
1085
+ " @keyframes rotate360 {\n",
1086
+ " 0% {\n",
1087
+ " transform: rotate(0deg);\n",
1088
+ " }\n",
1089
+ " 100% {\n",
1090
+ " transform: rotate(360deg);\n",
1091
+ " }\n",
1092
+ " }\n",
1093
+ " `;\n",
1094
+ "\n",
1095
+ " const Logo = styled(\n",
1096
+ " (props) => h`\n",
1097
+ " <a href=&quot;https://kaggle.com&quot; target=&quot;_blank&quot; className=${props.className}>\n",
1098
+ " <svg width=&quot;62px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 62 24&quot; version=&quot;1.1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;>\n",
1099
+ " <g fill=&quot;#1EBEFF&quot; fill-rule=&quot;nonzero&quot;>\n",
1100
+ " <path d=&quot;M10.2,17.8c0,0.1-0.1,0.1-0.2,0.1H7.7c-0.1,0-0.3-0.1-0.4-0.2l-3.8-4.9l-1.1,1v3.8 c0,0.2-0.1,0.3-0.3,0.3H0.3c-0.2,0-0.3-0.1-0.3-0.3V0.3C0.1,0.1,0.2,0,0.3,0h1.8c0.2,0,0.3,0.1,0.3,0.3V11L7,6.3 c0.1-0.1,0.2-0.2,0.4-0.2h2.4c0.1,0,0.2,0,0.2,0.1c0,0.1,0,0.2,0,0.2l-4.9,4.7l5.1,6.3C10.2,17.6,10.2,17.7,10.2,17.8z&quot;/>\n",
1101
+ " <path d=&quot;M19.6,17.9h-1.8c-0.2,0-0.3-0.1-0.3-0.3v-0.4c-0.8,0.6-1.8,0.9-3,0.9c-1.1,0-2-0.3-2.8-1 c-0.8-0.7-1.2-1.6-1.2-2.7c0-1.7,1.1-2.9,3.2-3.5c0.8-0.2,2.1-0.5,3.8-0.6c0.1-0.6-0.1-1.2-0.5-1.7c-0.4-0.5-1-0.7-1.7-0.7 c-1,0-2,0.4-3,1C12.2,9.1,12.1,9.1,12,9l-0.9-1.3C11,7.5,11,7.4,11.1,7.3c1.3-0.9,2.7-1.4,4.2-1.4c1.1,0,2.1,0.3,2.8,0.8 c1.1,0.8,1.7,2,1.7,3.7v7.3C19.9,17.8,19.8,17.9,19.6,17.9z M17.5,12.4c-1.7,0.2-2.9,0.4-3.5,0.7c-0.9,0.4-1.2,0.9-1.1,1.6 c0.1,0.4,0.2,0.7,0.6,0.9c0.3,0.2,0.7,0.4,1.1,0.4c1.2,0.1,2.2-0.2,2.9-1V12.4z&quot;/>\n",
1102
+ " <path d=&quot;M30.6,22.5c-0.9,1-2.3,1.5-4,1.5c-1,0-2-0.3-2.9-0.8c-0.2-0.1-0.4-0.3-0.7-0.5 c-0.3-0.2-0.6-0.5-0.9-0.7c-0.1-0.1-0.1-0.2,0-0.4l1.2-1.2c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1c1,1,1.9,1.5,2.8,1.5 c2.1,0,3.2-1.1,3.2-3.3v-1.4c-0.8,0.7-1.9,1-3.3,1c-1.7,0-3-0.6-4-1.9c-0.8-1.1-1.3-2.5-1.3-4.2c0-1.6,0.4-3,1.2-4.1 c0.9-1.3,2.3-2,4-2c1.3,0,2.4,0.3,3.3,1V6.4c0-0.2,0.1-0.3,0.3-0.3h1.8c0.2,0,0.3,0.1,0.3,0.3v11.7C32,20,31.5,21.5,30.6,22.5z M29.7,9.9c-0.4-1.1-1.4-1.7-3-1.7c-2,0-3.1,1.3-3.1,3.8c0,1.4,0.3,2.4,1,3.1c0.5,0.5,1.2,0.8,2,0.8c1.6,0,2.7-0.6,3.1-1.7V9.9z&quot;/>\n",
1103
+ " <path d=&quot;M42.9,22.5c-0.9,1-2.3,1.5-4,1.5c-1,0-2-0.3-2.9-0.8c-0.2-0.1-0.4-0.3-0.7-0.5 c-0.3-0.2-0.6-0.5-0.9-0.7c-0.1-0.1-0.1-0.2,0-0.4l1.2-1.2c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1c1,1,1.9,1.5,2.8,1.5 c2.1,0,3.2-1.1,3.2-3.3v-1.4c-0.8,0.7-1.9,1-3.3,1c-1.7,0-3-0.6-4-1.9c-0.8-1.1-1.3-2.5-1.3-4.2c0-1.6,0.4-3,1.2-4.1 c0.9-1.3,2.3-2,4-2c1.3,0,2.4,0.3,3.3,1V6.4c0-0.2,0.1-0.3,0.3-0.3H44c0.2,0,0.3,0.1,0.3,0.3v11.7C44.3,20,43.8,21.5,42.9,22.5z M42,9.9c-0.4-1.1-1.4-1.7-3-1.7c-2,0-3.1,1.3-3.1,3.8c0,1.4,0.3,2.4,1,3.1c0.5,0.5,1.2,0.8,2,0.8c1.6,0,2.7-0.6,3.1-1.7L42,9.9 L42,9.9z&quot;/>\n",
1104
+ " <path d=&quot;M48.3,17.9h-1.8c-0.2,0-0.3-0.1-0.3-0.3V0.3c0-0.2,0.1-0.3,0.3-0.3h1.8c0.2,0,0.3,0.1,0.3,0.3 v17.3C48.5,17.8,48.5,17.9,48.3,17.9z&quot;/>\n",
1105
+ " <path d=&quot;M61.4,12.6c0,0.2-0.1,0.3-0.3,0.3h-8.5c0.1,0.9,0.5,1.6,1.1,2.2c0.7,0.6,1.6,0.9,2.7,0.9 c1,0,1.8-0.3,2.6-0.8c0.2-0.1,0.3-0.1,0.4,0l1.2,1.3c0.1,0.1,0.1,0.3,0,0.4c-1.3,0.9-2.7,1.4-4.4,1.4c-1.8,0-3.3-0.6-4.4-1.8 c-1.1-1.2-1.7-2.7-1.7-4.5c0-1.7,0.6-3.2,1.7-4.4c1-1.1,2.4-1.6,4.1-1.6c1.6,0,2.9,0.6,4,1.7c1.1,1.2,1.6,2.6,1.5,4.4L61.4,12.6 z M58,8.7c-0.6-0.5-1.3-0.8-2.1-0.8c-0.8,0-1.5,0.3-2.1,0.8c-0.6,0.5-1,1.2-1.1,2H59C59,9.9,58.6,9.3,58,8.7z&quot;/>\n",
1106
+ " </g>\n",
1107
+ " </svg>\n",
1108
+ " </a>\n",
1109
+ " `\n",
1110
+ " )`\n",
1111
+ " display: inline-flex;\n",
1112
+ " `;\n",
1113
+ "\n",
1114
+ " const Header = styled((props) => {\n",
1115
+ " const { environment } = useContext(Context);\n",
1116
+ "\n",
1117
+ " return h`<div className=${props.className} >\n",
1118
+ " <${Logo} />\n",
1119
+ " ${environment.title}\n",
1120
+ " </div>`;\n",
1121
+ " })`\n",
1122
+ " align-items: center;\n",
1123
+ " border-bottom: 4px solid #212121;\n",
1124
+ " box-sizing: border-box;\n",
1125
+ " color: #fff;\n",
1126
+ " display: flex;\n",
1127
+ " flex: 0 0 36px;\n",
1128
+ " font-size: 14px;\n",
1129
+ " justify-content: space-between;\n",
1130
+ " padding: 0 8px;\n",
1131
+ " width: 100%;\n",
1132
+ " `;\n",
1133
+ "\n",
1134
+ " const Renderer = styled((props) => {\n",
1135
+ " const context = useContext(Context);\n",
1136
+ " const { animate, debug, playing, renderer, speed } = context;\n",
1137
+ " const ref = preact.createRef();\n",
1138
+ "\n",
1139
+ " useEffect(async () => {\n",
1140
+ " if (!ref.current) return;\n",
1141
+ "\n",
1142
+ " const renderFrame = async (start, step, lastFrame) => {\n",
1143
+ " if (step !== context.step) return;\n",
1144
+ " if (lastFrame === 1) {\n",
1145
+ " if (!animate) return;\n",
1146
+ " start = Date.now();\n",
1147
+ " }\n",
1148
+ " const frame =\n",
1149
+ " playing || animate\n",
1150
+ " ? Math.min((Date.now() - start) / speed, 1)\n",
1151
+ " : 1;\n",
1152
+ " try {\n",
1153
+ " if (debug) console.time(&quot;render&quot;);\n",
1154
+ " await renderer({\n",
1155
+ " ...context,\n",
1156
+ " frame,\n",
1157
+ " height: ref.current.clientHeight,\n",
1158
+ " hooks: preactHooks,\n",
1159
+ " parent: ref.current,\n",
1160
+ " preact,\n",
1161
+ " styled,\n",
1162
+ " width: ref.current.clientWidth,\n",
1163
+ " });\n",
1164
+ " } catch (error) {\n",
1165
+ " if (debug) console.error(error);\n",
1166
+ " console.log({ ...context, frame, error });\n",
1167
+ " } finally {\n",
1168
+ " if (debug) console.timeEnd(&quot;render&quot;);\n",
1169
+ " }\n",
1170
+ " window.requestAnimationFrame(() => renderFrame(start, step, frame));\n",
1171
+ " };\n",
1172
+ "\n",
1173
+ " await renderFrame(Date.now(), context.step);\n",
1174
+ " }, [ref.current, context.step, context.renderer]);\n",
1175
+ "\n",
1176
+ " return h`<div className=${props.className} ref=${ref} />`;\n",
1177
+ " })`\n",
1178
+ " align-items: center;\n",
1179
+ " box-sizing: border-box;\n",
1180
+ " display: flex;\n",
1181
+ " height: 100%;\n",
1182
+ " left: 0;\n",
1183
+ " justify-content: center;\n",
1184
+ " position: absolute;\n",
1185
+ " top: 0;\n",
1186
+ " width: 100%;\n",
1187
+ " `;\n",
1188
+ "\n",
1189
+ " const Processing = styled((props) => {\n",
1190
+ " const { processing } = useContext(Context);\n",
1191
+ " const text = processing === true ? &quot;Processing...&quot; : processing;\n",
1192
+ " return h`<div className=${props.className}>${text}</div>`;\n",
1193
+ " })`\n",
1194
+ " bottom: 0;\n",
1195
+ " color: #fff;\n",
1196
+ " font-size: 12px;\n",
1197
+ " left: 0;\n",
1198
+ " line-height: 24px;\n",
1199
+ " position: absolute;\n",
1200
+ " text-align: center;\n",
1201
+ " width: 100%;\n",
1202
+ " `;\n",
1203
+ "\n",
1204
+ " const Viewer = styled((props) => {\n",
1205
+ " const { processing } = useContext(Context);\n",
1206
+ " return h`<div className=${props.className}>\n",
1207
+ " <${Renderer} />\n",
1208
+ " ${processing && h`<${Processing} />`}\n",
1209
+ " </div>`;\n",
1210
+ " })`\n",
1211
+ " background-color: #000b2a;\n",
1212
+ " background-image: radial-gradient(\n",
1213
+ " circle closest-side,\n",
1214
+ " #000b49,\n",
1215
+ " #000b2a\n",
1216
+ " );\n",
1217
+ " display: flex;\n",
1218
+ " flex: 1;\n",
1219
+ " overflow: hidden;\n",
1220
+ " position: relative;\n",
1221
+ " width: 100%;\n",
1222
+ " `;\n",
1223
+ "\n",
1224
+ " const Legend = styled((props) => {\n",
1225
+ " const { agents, legend } = useContext(Context);\n",
1226
+ "\n",
1227
+ " return h`<div className=${props.className}>\n",
1228
+ " <ul>\n",
1229
+ " ${agents\n",
1230
+ " .sort((a, b) => a.index - b.index)\n",
1231
+ " .map(\n",
1232
+ " (a) =>\n",
1233
+ " h`<li key=${a.id} title=&quot;id: ${a.id}&quot; style=&quot;color:${\n",
1234
+ " a.color || &quot;#FFF&quot;\n",
1235
+ " }&quot;>${a.image && h`<img src=${a.image} />`}<span>${\n",
1236
+ " a.name\n",
1237
+ " }</span></li>`\n",
1238
+ " )}\n",
1239
+ " </ul>\n",
1240
+ " </div>`;\n",
1241
+ " })`\n",
1242
+ " background-color: #000b2a;\n",
1243
+ " font-family: sans-serif;\n",
1244
+ " font-size: 14px;\n",
1245
+ " width: 100%;\n",
1246
+ "\n",
1247
+ " ul {\n",
1248
+ " align-items: center;\n",
1249
+ " display: flex;\n",
1250
+ " flex-direction: row;\n",
1251
+ " justify-content: center;\n",
1252
+ " }\n",
1253
+ "\n",
1254
+ " li {\n",
1255
+ " align-items: center;\n",
1256
+ " display: inline-flex;\n",
1257
+ " padding: 8px;\n",
1258
+ " transition: color 1s;\n",
1259
+ " }\n",
1260
+ "\n",
1261
+ " span {\n",
1262
+ " max-width: 100px;\n",
1263
+ " overflow: hidden;\n",
1264
+ " text-overflow: ellipsis;\n",
1265
+ " white-space: nowrap;\n",
1266
+ " }\n",
1267
+ "\n",
1268
+ " img {\n",
1269
+ " height: 24px;\n",
1270
+ " margin-right: 4px;\n",
1271
+ " width: 24px;\n",
1272
+ " }\n",
1273
+ " `;\n",
1274
+ "\n",
1275
+ " const StepInput = styled.input.attrs({\n",
1276
+ " type: &quot;range&quot;,\n",
1277
+ " })`\n",
1278
+ " appearance: none;\n",
1279
+ " background: rgba(255, 255, 255, 0.15);\n",
1280
+ " border-radius: 2px;\n",
1281
+ " display: block;\n",
1282
+ " flex: 1;\n",
1283
+ " height: 4px;\n",
1284
+ " opacity: 0.8;\n",
1285
+ " outline: none;\n",
1286
+ " transition: opacity 0.2s;\n",
1287
+ " width: 100%;\n",
1288
+ "\n",
1289
+ " &:hover {\n",
1290
+ " opacity: 1;\n",
1291
+ " }\n",
1292
+ "\n",
1293
+ " &::-webkit-slider-thumb {\n",
1294
+ " appearance: none;\n",
1295
+ " background: #1ebeff;\n",
1296
+ " border-radius: 100%;\n",
1297
+ " cursor: pointer;\n",
1298
+ " height: 12px;\n",
1299
+ " margin: 0;\n",
1300
+ " position: relative;\n",
1301
+ " width: 12px;\n",
1302
+ "\n",
1303
+ " &::after {\n",
1304
+ " content: &quot;&quot;;\n",
1305
+ " position: absolute;\n",
1306
+ " top: 0px;\n",
1307
+ " left: 0px;\n",
1308
+ " width: 200px;\n",
1309
+ " height: 8px;\n",
1310
+ " background: green;\n",
1311
+ " }\n",
1312
+ " }\n",
1313
+ " `;\n",
1314
+ "\n",
1315
+ " const PlayButton = styled.button`\n",
1316
+ " align-items: center;\n",
1317
+ " background: none;\n",
1318
+ " border: none;\n",
1319
+ " color: white;\n",
1320
+ " cursor: pointer;\n",
1321
+ " display: flex;\n",
1322
+ " flex: 0 0 56px;\n",
1323
+ " font-size: 20px;\n",
1324
+ " height: 40px;\n",
1325
+ " justify-content: center;\n",
1326
+ " opacity: 0.8;\n",
1327
+ " outline: none;\n",
1328
+ " transition: opacity 0.2s;\n",
1329
+ "\n",
1330
+ " &:hover {\n",
1331
+ " opacity: 1;\n",
1332
+ " }\n",
1333
+ " `;\n",
1334
+ "\n",
1335
+ " const StepCount = styled.span`\n",
1336
+ " align-items: center;\n",
1337
+ " color: white;\n",
1338
+ " display: flex;\n",
1339
+ " font-size: 14px;\n",
1340
+ " justify-content: center;\n",
1341
+ " opacity: 0.8;\n",
1342
+ " padding: 0 16px;\n",
1343
+ " pointer-events: none;\n",
1344
+ " `;\n",
1345
+ "\n",
1346
+ " const Controls = styled((props) => {\n",
1347
+ " const { environment, pause, play, playing, setStep, step } = useContext(\n",
1348
+ " Context\n",
1349
+ " );\n",
1350
+ " const value = step + 1;\n",
1351
+ " const onClick = () => (playing ? pause() : play());\n",
1352
+ " const onInput = (e) => {\n",
1353
+ " pause();\n",
1354
+ " setStep(parseInt(e.target.value) - 1);\n",
1355
+ " };\n",
1356
+ "\n",
1357
+ " return h`\n",
1358
+ " <div className=${props.className}>\n",
1359
+ " <${PlayButton} onClick=${onClick}><svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24px&quot; height=&quot;24px&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;#FFFFFF&quot;>${\n",
1360
+ " playing\n",
1361
+ " ? h`<path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
1362
+ " : h`<path d=&quot;M8 5v14l11-7z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
1363
+ " }</svg><//>\n",
1364
+ " <${StepInput} min=&quot;1&quot; max=${\n",
1365
+ " environment.steps.length\n",
1366
+ " } value=&quot;${value}&quot; onInput=${onInput} />\n",
1367
+ " <${StepCount}>${value} / ${environment.steps.length}<//>\n",
1368
+ " </div>\n",
1369
+ " `;\n",
1370
+ " })`\n",
1371
+ " align-items: center;\n",
1372
+ " border-top: 4px solid #212121;\n",
1373
+ " display: flex;\n",
1374
+ " flex: 0 0 44px;\n",
1375
+ " width: 100%;\n",
1376
+ " `;\n",
1377
+ "\n",
1378
+ " const Info = styled((props) => {\n",
1379
+ " const {\n",
1380
+ " environment,\n",
1381
+ " playing,\n",
1382
+ " step,\n",
1383
+ " speed,\n",
1384
+ " animate,\n",
1385
+ " header,\n",
1386
+ " controls,\n",
1387
+ " settings,\n",
1388
+ " } = useContext(Context);\n",
1389
+ "\n",
1390
+ " return h`\n",
1391
+ " <div className=${props.className}>\n",
1392
+ " info:\n",
1393
+ " step(${step}),\n",
1394
+ " playing(${playing ? &quot;T&quot; : &quot;F&quot;}),\n",
1395
+ " speed(${speed}),\n",
1396
+ " animate(${animate ? &quot;T&quot; : &quot;F&quot;})\n",
1397
+ " </div>`;\n",
1398
+ " })`\n",
1399
+ " color: #888;\n",
1400
+ " font-family: monospace;\n",
1401
+ " font-size: 12px;\n",
1402
+ " `;\n",
1403
+ "\n",
1404
+ " const Settings = styled((props) => {\n",
1405
+ " const { environment, pause, play, playing, setStep, step } = useContext(\n",
1406
+ " Context\n",
1407
+ " );\n",
1408
+ "\n",
1409
+ " return h`\n",
1410
+ " <div className=${props.className}>\n",
1411
+ " <${Info} />\n",
1412
+ " </div>\n",
1413
+ " `;\n",
1414
+ " })`\n",
1415
+ " background: #fff;\n",
1416
+ " border-top: 4px solid #212121;\n",
1417
+ " box-sizing: border-box;\n",
1418
+ " padding: 20px;\n",
1419
+ " width: 100%;\n",
1420
+ "\n",
1421
+ " h1 {\n",
1422
+ " font-size: 20px;\n",
1423
+ " }\n",
1424
+ " `;\n",
1425
+ "\n",
1426
+ " const Player = styled((props) => {\n",
1427
+ " const context = useContext(Context);\n",
1428
+ " const { agents, controls, header, legend, loading, settings } = context;\n",
1429
+ " return h`\n",
1430
+ " <div className=${props.className}>\n",
1431
+ " ${loading && h`<${Loading} />`}\n",
1432
+ " ${!loading && header && h`<${Header} />`}\n",
1433
+ " ${!loading && h`<${Viewer} />`}\n",
1434
+ " ${!loading && agents.length > 0 && legend && h`<${Legend} />`}\n",
1435
+ " ${!loading && controls && h`<${Controls} />`}\n",
1436
+ " ${!loading && settings && h`<${Settings} />`}\n",
1437
+ " </div>`;\n",
1438
+ " })`\n",
1439
+ " align-items: center;\n",
1440
+ " background: #212121;\n",
1441
+ " border: 4px solid #212121;\n",
1442
+ " box-sizing: border-box;\n",
1443
+ " display: flex;\n",
1444
+ " flex-direction: column;\n",
1445
+ " height: 100%;\n",
1446
+ " justify-content: center;\n",
1447
+ " position: relative;\n",
1448
+ " width: 100%;\n",
1449
+ " `;\n",
1450
+ "\n",
1451
+ " const App = () => {\n",
1452
+ " const renderCountRef = useRef(0);\n",
1453
+ " const [_, setRenderCount] = useState(0);\n",
1454
+ "\n",
1455
+ " const contextRef = useRef({\n",
1456
+ " animate: false,\n",
1457
+ " agents: [],\n",
1458
+ " autoplay: false,\n",
1459
+ " controls: false,\n",
1460
+ " debug: false,\n",
1461
+ " environment: { steps: [] },\n",
1462
+ " header: window.innerHeight >= 600,\n",
1463
+ " interactive: false,\n",
1464
+ " legend: true,\n",
1465
+ " loading: false,\n",
1466
+ " playing: false,\n",
1467
+ " processing: false,\n",
1468
+ " renderer: () => &quot;DNE&quot;,\n",
1469
+ " settings: false,\n",
1470
+ " speed: 500,\n",
1471
+ " step: 0,\n",
1472
+ " });\n",
1473
+ "\n",
1474
+ " // Context helpers.\n",
1475
+ " const rerender = (contextRef.current.rerender = () =>\n",
1476
+ " setRenderCount((renderCountRef.current += 1)));\n",
1477
+ " const setStep = (contextRef.current.setStep = (newStep) => {\n",
1478
+ " contextRef.current.step = newStep;\n",
1479
+ " rerender();\n",
1480
+ " });\n",
1481
+ " const setPlaying = (contextRef.current.setPlaying = (playing) => {\n",
1482
+ " contextRef.current.playing = playing;\n",
1483
+ " rerender();\n",
1484
+ " });\n",
1485
+ " const pause = (contextRef.current.pause = () => setPlaying(false));\n",
1486
+ "\n",
1487
+ " const playNext = () => {\n",
1488
+ " const context = contextRef.current;\n",
1489
+ "\n",
1490
+ " if (\n",
1491
+ " context.playing &&\n",
1492
+ " context.step < context.environment.steps.length - 1\n",
1493
+ " ) {\n",
1494
+ " setStep(context.step + 1);\n",
1495
+ " play(true);\n",
1496
+ " } else {\n",
1497
+ " pause();\n",
1498
+ " }\n",
1499
+ " };\n",
1500
+ "\n",
1501
+ " const play = (contextRef.current.play = (continuing) => {\n",
1502
+ " const context = contextRef.current;\n",
1503
+ " if (context.playing && !continuing) return;\n",
1504
+ " if (!context.playing) setPlaying(true);\n",
1505
+ " if (\n",
1506
+ " !continuing &&\n",
1507
+ " context.step === context.environment.steps.length - 1\n",
1508
+ " ) {\n",
1509
+ " setStep(0);\n",
1510
+ " }\n",
1511
+ " setTimeout(playNext, context.speed);\n",
1512
+ " });\n",
1513
+ "\n",
1514
+ " const updateContext = (o) => {\n",
1515
+ " const context = contextRef.current;\n",
1516
+ " Object.assign(context, o, {\n",
1517
+ " environment: { ...context.environment, ...(o.environment || {}) },\n",
1518
+ " });\n",
1519
+ " rerender();\n",
1520
+ "\n",
1521
+ " // If autoplay, toggle to playing.\n",
1522
+ " if (context.autoplay) play();\n",
1523
+ " };\n",
1524
+ "\n",
1525
+ " // First time setup.\n",
1526
+ " useEffect(() => {\n",
1527
+ " // Timeout is used to ensure useEffect renders once.\n",
1528
+ " setTimeout(() => {\n",
1529
+ " // Initialize context with window.kaggle.\n",
1530
+ " updateContext(window.kaggle || {});\n",
1531
+ " // Listen for messages received to update the context.\n",
1532
+ " window.addEventListener(\n",
1533
+ " &quot;message&quot;,\n",
1534
+ " (event) => {\n",
1535
+ " // Ensure the environment names match before updating.\n",
1536
+ " try {\n",
1537
+ " if (\n",
1538
+ " event.data.environment.name ==\n",
1539
+ " contextRef.current.environment.name\n",
1540
+ " ) {\n",
1541
+ " updateContext(event.data);\n",
1542
+ " }\n",
1543
+ " } catch {}\n",
1544
+ " },\n",
1545
+ " false\n",
1546
+ " );\n",
1547
+ " // Listen for keyboard commands.\n",
1548
+ " window.addEventListener(\n",
1549
+ " &quot;keydown&quot;,\n",
1550
+ " (event) => {\n",
1551
+ " const {\n",
1552
+ " interactive,\n",
1553
+ " isInteractive,\n",
1554
+ " playing,\n",
1555
+ " step,\n",
1556
+ " environment,\n",
1557
+ " } = contextRef.current;\n",
1558
+ " const key = event.keyCode;\n",
1559
+ " if (\n",
1560
+ " interactive ||\n",
1561
+ " isInteractive() ||\n",
1562
+ " (key !== 32 && key !== 37 && key !== 39)\n",
1563
+ " )\n",
1564
+ " return;\n",
1565
+ "\n",
1566
+ " if (key === 32) {\n",
1567
+ " playing ? pause() : play();\n",
1568
+ " } else if (event.keyCode === 39) {\n",
1569
+ " contextRef.current.playing = false;\n",
1570
+ " if (step < environment.steps.length - 1) setStep(step + 1);\n",
1571
+ " rerender();\n",
1572
+ " } else if (event.keyCode === 37) {\n",
1573
+ " contextRef.current.playing = false;\n",
1574
+ " if (step > 0) setStep(step - 1);\n",
1575
+ " rerender();\n",
1576
+ " }\n",
1577
+ " event.preventDefault();\n",
1578
+ " return false;\n",
1579
+ " },\n",
1580
+ " false\n",
1581
+ " );\n",
1582
+ " }, 1);\n",
1583
+ " }, []);\n",
1584
+ "\n",
1585
+ " if (contextRef.current.debug) {\n",
1586
+ " console.log(&quot;context&quot;, contextRef.current);\n",
1587
+ " }\n",
1588
+ "\n",
1589
+ " // Ability to update context.\n",
1590
+ " contextRef.current.update = updateContext;\n",
1591
+ "\n",
1592
+ " // Ability to communicate with ipython.\n",
1593
+ " const execute = (contextRef.current.execute = (source) =>\n",
1594
+ " new Promise((resolve, reject) => {\n",
1595
+ " try {\n",
1596
+ " window.parent.IPython.notebook.kernel.execute(source, {\n",
1597
+ " iopub: {\n",
1598
+ " output: (resp) => {\n",
1599
+ " const type = resp.msg_type;\n",
1600
+ " if (type === &quot;stream&quot;) return resolve(resp.content.text);\n",
1601
+ " if (type === &quot;error&quot;) return reject(new Error(resp.evalue));\n",
1602
+ " return reject(new Error(&quot;Unknown message type: &quot; + type));\n",
1603
+ " },\n",
1604
+ " },\n",
1605
+ " });\n",
1606
+ " } catch (e) {\n",
1607
+ " reject(new Error(&quot;IPython Unavailable: &quot; + e));\n",
1608
+ " }\n",
1609
+ " }));\n",
1610
+ "\n",
1611
+ " // Ability to return an action from an interactive session.\n",
1612
+ " contextRef.current.act = (action) => {\n",
1613
+ " const id = contextRef.current.environment.id;\n",
1614
+ " updateContext({ processing: true });\n",
1615
+ " execute(`\n",
1616
+ " import json\n",
1617
+ " from kaggle_environments import interactives\n",
1618
+ " if &quot;${id}&quot; in interactives:\n",
1619
+ " action = json.loads('${JSON.stringify(action)}')\n",
1620
+ " env, trainer = interactives[&quot;${id}&quot;]\n",
1621
+ " trainer.step(action)\n",
1622
+ " print(json.dumps(env.steps))`)\n",
1623
+ " .then((resp) => {\n",
1624
+ " try {\n",
1625
+ " updateContext({\n",
1626
+ " processing: false,\n",
1627
+ " environment: { steps: JSON.parse(resp) },\n",
1628
+ " });\n",
1629
+ " play();\n",
1630
+ " } catch (e) {\n",
1631
+ " updateContext({ processing: resp.split(&quot;\\n&quot;)[0] });\n",
1632
+ " console.error(resp, e);\n",
1633
+ " }\n",
1634
+ " })\n",
1635
+ " .catch((e) => console.error(e));\n",
1636
+ " };\n",
1637
+ "\n",
1638
+ " // Check if currently interactive.\n",
1639
+ " contextRef.current.isInteractive = () => {\n",
1640
+ " const context = contextRef.current;\n",
1641
+ " const steps = context.environment.steps;\n",
1642
+ " return (\n",
1643
+ " context.interactive &&\n",
1644
+ " !context.processing &&\n",
1645
+ " context.step === steps.length - 1 &&\n",
1646
+ " steps[context.step].some((s) => s.status === &quot;ACTIVE&quot;)\n",
1647
+ " );\n",
1648
+ " };\n",
1649
+ "\n",
1650
+ " return h`\n",
1651
+ " <${Context.Provider} value=${contextRef.current}>\n",
1652
+ " <${Player} />\n",
1653
+ " <//>`;\n",
1654
+ " };\n",
1655
+ "\n",
1656
+ " preact.render(h`<${App} />`, document.body);\n",
1657
+ " </script>\n",
1658
+ " </body>\n",
1659
+ "</html>\n",
1660
+ "\" width=\"600\" height=\"500\" frameborder=\"0\"></iframe> "
1661
+ ],
1662
+ "text/plain": [
1663
+ "<IPython.core.display.HTML object>"
1664
+ ]
1665
+ },
1666
+ "metadata": {},
1667
+ "output_type": "display_data"
1668
+ }
1669
+ ],
1670
+ "source": [
1671
+ "def agent(observation, configuration):\n",
1672
+ " board = observation.board\n",
1673
+ " columns = configuration.columns\n",
1674
+ " return [c for c in range(columns) if board[c] == 0][0]\n",
1675
+ "\n",
1676
+ "env = make(\"connectx\", debug=True)\n",
1677
+ "# play agent above vs default random agent.\n",
1678
+ "env.run([agent, \"random\"])\n",
1679
+ "env.render(mode=\"ipython\", width=600, height=500, header=False)"
1680
+ ]
1681
+ },
1682
+ {
1683
+ "cell_type": "markdown",
1684
+ "metadata": {},
1685
+ "source": [
1686
+ "## Specification"
1687
+ ]
1688
+ },
1689
+ {
1690
+ "cell_type": "code",
1691
+ "execution_count": 3,
1692
+ "metadata": {},
1693
+ "outputs": [
1694
+ {
1695
+ "name": "stdout",
1696
+ "output_type": "stream",
1697
+ "text": [
1698
+ "Configuration: {\n",
1699
+ " \"actTimeout\": {\n",
1700
+ " \"default\": 2,\n",
1701
+ " \"description\": \"Maximum runtime (seconds) to obtain an action from an agent.\",\n",
1702
+ " \"minimum\": 1,\n",
1703
+ " \"type\": \"integer\"\n",
1704
+ " },\n",
1705
+ " \"agentExec\": {\n",
1706
+ " \"default\": \"PROCESS\",\n",
1707
+ " \"description\": \"How the agent is executed alongside the running envionment.\",\n",
1708
+ " \"enum\": [\n",
1709
+ " \"LOCAL\",\n",
1710
+ " \"PROCESS\"\n",
1711
+ " ],\n",
1712
+ " \"type\": \"string\"\n",
1713
+ " },\n",
1714
+ " \"agentTimeout\": {\n",
1715
+ " \"default\": 10,\n",
1716
+ " \"description\": \"Maximum runtime (seconds) to initialize an agent.\",\n",
1717
+ " \"minimum\": 1,\n",
1718
+ " \"type\": \"integer\"\n",
1719
+ " },\n",
1720
+ " \"columns\": {\n",
1721
+ " \"default\": 7,\n",
1722
+ " \"description\": \"The number of columns on the board\",\n",
1723
+ " \"minimum\": 1,\n",
1724
+ " \"type\": \"integer\"\n",
1725
+ " },\n",
1726
+ " \"episodeSteps\": {\n",
1727
+ " \"default\": 1000,\n",
1728
+ " \"description\": \"Maximum number of steps in the episode.\",\n",
1729
+ " \"minimum\": 1,\n",
1730
+ " \"type\": \"integer\"\n",
1731
+ " },\n",
1732
+ " \"inarow\": {\n",
1733
+ " \"default\": 4,\n",
1734
+ " \"description\": \"The number of checkers in a row required to win.\",\n",
1735
+ " \"minimum\": 1,\n",
1736
+ " \"type\": \"integer\"\n",
1737
+ " },\n",
1738
+ " \"rows\": {\n",
1739
+ " \"default\": 6,\n",
1740
+ " \"description\": \"The number of rows on the board\",\n",
1741
+ " \"minimum\": 1,\n",
1742
+ " \"type\": \"integer\"\n",
1743
+ " },\n",
1744
+ " \"runTimeout\": {\n",
1745
+ " \"default\": 600,\n",
1746
+ " \"description\": \"Maximum runtime (seconds) of an episode (not necessarily DONE).\",\n",
1747
+ " \"minimum\": 1,\n",
1748
+ " \"type\": \"integer\"\n",
1749
+ " }\n",
1750
+ "}\n",
1751
+ "Observation: {\n",
1752
+ " \"board\": {\n",
1753
+ " \"default\": [],\n",
1754
+ " \"description\": \"Serialized grid (rows x columns). 0 = Empty, 1 = P1, 2 = P2\",\n",
1755
+ " \"shared\": true,\n",
1756
+ " \"type\": \"array\"\n",
1757
+ " },\n",
1758
+ " \"mark\": {\n",
1759
+ " \"defaults\": [\n",
1760
+ " 1,\n",
1761
+ " 2\n",
1762
+ " ],\n",
1763
+ " \"description\": \"Which checkers are the agents.\",\n",
1764
+ " \"enum\": [\n",
1765
+ " 1,\n",
1766
+ " 2\n",
1767
+ " ]\n",
1768
+ " }\n",
1769
+ "}\n",
1770
+ "Action: {\n",
1771
+ " \"default\": 0,\n",
1772
+ " \"description\": \"Column to drop a checker onto the board.\",\n",
1773
+ " \"minimum\": 0,\n",
1774
+ " \"type\": \"integer\"\n",
1775
+ "}\n"
1776
+ ]
1777
+ }
1778
+ ],
1779
+ "source": [
1780
+ "import json\n",
1781
+ "print(\"Configuration:\", json.dumps(env.specification.configuration, indent=4, sort_keys=True))\n",
1782
+ "print(\"Observation:\", json.dumps(env.specification.observation, indent=4, sort_keys=True))\n",
1783
+ "print(\"Action:\", json.dumps(env.specification.action, indent=4, sort_keys=True))"
1784
+ ]
1785
+ },
1786
+ {
1787
+ "cell_type": "markdown",
1788
+ "metadata": {},
1789
+ "source": [
1790
+ "## Manual Play"
1791
+ ]
1792
+ },
1793
+ {
1794
+ "cell_type": "code",
1795
+ "execution_count": 4,
1796
+ "metadata": {},
1797
+ "outputs": [
1798
+ {
1799
+ "data": {
1800
+ "text/html": [
1801
+ "<iframe srcdoc=\"<!--\n",
1802
+ " Copyright 2020 Kaggle Inc\n",
1803
+ "\n",
1804
+ " Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
1805
+ " you may not use this file except in compliance with the License.\n",
1806
+ " You may obtain a copy of the License at\n",
1807
+ "\n",
1808
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
1809
+ "\n",
1810
+ " Unless required by applicable law or agreed to in writing, software\n",
1811
+ " distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
1812
+ " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
1813
+ " See the License for the specific language governing permissions and\n",
1814
+ " limitations under the License.\n",
1815
+ "-->\n",
1816
+ "<!DOCTYPE html>\n",
1817
+ "<html lang=&quot;en&quot;>\n",
1818
+ " <head>\n",
1819
+ " <title>Kaggle Simulation Player</title>\n",
1820
+ " <meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot; />\n",
1821
+ " <link\n",
1822
+ " rel=&quot;stylesheet&quot;\n",
1823
+ " href=&quot;https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css&quot;\n",
1824
+ " crossorigin=&quot;anonymous&quot;\n",
1825
+ " />\n",
1826
+ " <style type=&quot;text/css&quot;>\n",
1827
+ " html,\n",
1828
+ " body {\n",
1829
+ " height: 100%;\n",
1830
+ " font-family: sans-serif;\n",
1831
+ " }\n",
1832
+ " canvas {\n",
1833
+ " /* image-rendering: -moz-crisp-edges;\n",
1834
+ " image-rendering: -webkit-crisp-edges;\n",
1835
+ " image-rendering: pixelated;\n",
1836
+ " image-rendering: crisp-edges; */\n",
1837
+ " }\n",
1838
+ " </style>\n",
1839
+ " <script src=&quot;https://unpkg.com/preact@10.0.1/dist/preact.umd.js&quot;></script>\n",
1840
+ " <script src=&quot;https://unpkg.com/preact@10.0.1/hooks/dist/hooks.umd.js&quot;></script>\n",
1841
+ " <script src=&quot;https://unpkg.com/htm@2.2.1/dist/htm.umd.js&quot;></script>\n",
1842
+ " <script>\n",
1843
+ " // Polyfill for Styled Components\n",
1844
+ " window.React = {\n",
1845
+ " ...preact,\n",
1846
+ " createElement: preact.h,\n",
1847
+ " PropTypes: { func: {} },\n",
1848
+ " };\n",
1849
+ " </script>\n",
1850
+ " <script src=&quot;https://unpkg.com/styled-components@3.5.0-0/dist/styled-components.min.js&quot;></script>\n",
1851
+ " </head>\n",
1852
+ " <body>\n",
1853
+ " <script>\n",
1854
+ " \n",
1855
+ "window.kaggle = {\n",
1856
+ " &quot;debug&quot;: false,\n",
1857
+ " &quot;autoplay&quot;: false,\n",
1858
+ " &quot;step&quot;: 0,\n",
1859
+ " &quot;controls&quot;: false,\n",
1860
+ " &quot;environment&quot;: {\n",
1861
+ " &quot;id&quot;: &quot;4504cadc-8bfb-11ea-ad45-acde48001122&quot;,\n",
1862
+ " &quot;name&quot;: &quot;connectx&quot;,\n",
1863
+ " &quot;title&quot;: &quot;ConnectX&quot;,\n",
1864
+ " &quot;description&quot;: &quot;Classic Connect in a row but configurable.&quot;,\n",
1865
+ " &quot;version&quot;: &quot;1.0.1&quot;,\n",
1866
+ " &quot;configuration&quot;: {\n",
1867
+ " &quot;episodeSteps&quot;: 1000,\n",
1868
+ " &quot;agentExec&quot;: &quot;PROCESS&quot;,\n",
1869
+ " &quot;agentTimeout&quot;: 10,\n",
1870
+ " &quot;actTimeout&quot;: 2,\n",
1871
+ " &quot;runTimeout&quot;: 600,\n",
1872
+ " &quot;columns&quot;: 7,\n",
1873
+ " &quot;rows&quot;: 6,\n",
1874
+ " &quot;inarow&quot;: 4\n",
1875
+ " },\n",
1876
+ " &quot;specification&quot;: {\n",
1877
+ " &quot;action&quot;: {\n",
1878
+ " &quot;description&quot;: &quot;Column to drop a checker onto the board.&quot;,\n",
1879
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1880
+ " &quot;minimum&quot;: 0,\n",
1881
+ " &quot;default&quot;: 0\n",
1882
+ " },\n",
1883
+ " &quot;agents&quot;: [\n",
1884
+ " 2\n",
1885
+ " ],\n",
1886
+ " &quot;configuration&quot;: {\n",
1887
+ " &quot;episodeSteps&quot;: {\n",
1888
+ " &quot;description&quot;: &quot;Maximum number of steps in the episode.&quot;,\n",
1889
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1890
+ " &quot;minimum&quot;: 1,\n",
1891
+ " &quot;default&quot;: 1000\n",
1892
+ " },\n",
1893
+ " &quot;agentExec&quot;: {\n",
1894
+ " &quot;description&quot;: &quot;How the agent is executed alongside the running envionment.&quot;,\n",
1895
+ " &quot;type&quot;: &quot;string&quot;,\n",
1896
+ " &quot;default&quot;: &quot;PROCESS&quot;,\n",
1897
+ " &quot;enum&quot;: [\n",
1898
+ " &quot;LOCAL&quot;,\n",
1899
+ " &quot;PROCESS&quot;\n",
1900
+ " ]\n",
1901
+ " },\n",
1902
+ " &quot;agentTimeout&quot;: {\n",
1903
+ " &quot;description&quot;: &quot;Maximum runtime (seconds) to initialize an agent.&quot;,\n",
1904
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1905
+ " &quot;minimum&quot;: 1,\n",
1906
+ " &quot;default&quot;: 10\n",
1907
+ " },\n",
1908
+ " &quot;actTimeout&quot;: {\n",
1909
+ " &quot;description&quot;: &quot;Maximum runtime (seconds) to obtain an action from an agent.&quot;,\n",
1910
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1911
+ " &quot;minimum&quot;: 1,\n",
1912
+ " &quot;default&quot;: 2\n",
1913
+ " },\n",
1914
+ " &quot;runTimeout&quot;: {\n",
1915
+ " &quot;description&quot;: &quot;Maximum runtime (seconds) of an episode (not necessarily DONE).&quot;,\n",
1916
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1917
+ " &quot;minimum&quot;: 1,\n",
1918
+ " &quot;default&quot;: 600\n",
1919
+ " },\n",
1920
+ " &quot;columns&quot;: {\n",
1921
+ " &quot;description&quot;: &quot;The number of columns on the board&quot;,\n",
1922
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1923
+ " &quot;default&quot;: 7,\n",
1924
+ " &quot;minimum&quot;: 1\n",
1925
+ " },\n",
1926
+ " &quot;rows&quot;: {\n",
1927
+ " &quot;description&quot;: &quot;The number of rows on the board&quot;,\n",
1928
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1929
+ " &quot;default&quot;: 6,\n",
1930
+ " &quot;minimum&quot;: 1\n",
1931
+ " },\n",
1932
+ " &quot;inarow&quot;: {\n",
1933
+ " &quot;description&quot;: &quot;The number of checkers in a row required to win.&quot;,\n",
1934
+ " &quot;type&quot;: &quot;integer&quot;,\n",
1935
+ " &quot;default&quot;: 4,\n",
1936
+ " &quot;minimum&quot;: 1\n",
1937
+ " }\n",
1938
+ " },\n",
1939
+ " &quot;info&quot;: {},\n",
1940
+ " &quot;observation&quot;: {\n",
1941
+ " &quot;board&quot;: {\n",
1942
+ " &quot;description&quot;: &quot;Serialized grid (rows x columns). 0 = Empty, 1 = P1, 2 = P2&quot;,\n",
1943
+ " &quot;type&quot;: &quot;array&quot;,\n",
1944
+ " &quot;shared&quot;: true,\n",
1945
+ " &quot;default&quot;: []\n",
1946
+ " },\n",
1947
+ " &quot;mark&quot;: {\n",
1948
+ " &quot;defaults&quot;: [\n",
1949
+ " 1,\n",
1950
+ " 2\n",
1951
+ " ],\n",
1952
+ " &quot;description&quot;: &quot;Which checkers are the agents.&quot;,\n",
1953
+ " &quot;enum&quot;: [\n",
1954
+ " 1,\n",
1955
+ " 2\n",
1956
+ " ]\n",
1957
+ " }\n",
1958
+ " },\n",
1959
+ " &quot;reward&quot;: {\n",
1960
+ " &quot;description&quot;: &quot;-1 = Lost, 0 = Draw/Ongoing, 1 = Won&quot;,\n",
1961
+ " &quot;enum&quot;: [\n",
1962
+ " -1,\n",
1963
+ " 0,\n",
1964
+ " 1\n",
1965
+ " ],\n",
1966
+ " &quot;default&quot;: 0,\n",
1967
+ " &quot;type&quot;: [\n",
1968
+ " &quot;number&quot;,\n",
1969
+ " &quot;null&quot;\n",
1970
+ " ]\n",
1971
+ " }\n",
1972
+ " },\n",
1973
+ " &quot;steps&quot;: [\n",
1974
+ " [\n",
1975
+ " {\n",
1976
+ " &quot;action&quot;: 0,\n",
1977
+ " &quot;reward&quot;: 0,\n",
1978
+ " &quot;info&quot;: {},\n",
1979
+ " &quot;observation&quot;: {\n",
1980
+ " &quot;board&quot;: [\n",
1981
+ " 0,\n",
1982
+ " 0,\n",
1983
+ " 0,\n",
1984
+ " 0,\n",
1985
+ " 0,\n",
1986
+ " 0,\n",
1987
+ " 0,\n",
1988
+ " 0,\n",
1989
+ " 0,\n",
1990
+ " 0,\n",
1991
+ " 0,\n",
1992
+ " 0,\n",
1993
+ " 0,\n",
1994
+ " 0,\n",
1995
+ " 0,\n",
1996
+ " 0,\n",
1997
+ " 0,\n",
1998
+ " 0,\n",
1999
+ " 0,\n",
2000
+ " 0,\n",
2001
+ " 0,\n",
2002
+ " 0,\n",
2003
+ " 0,\n",
2004
+ " 0,\n",
2005
+ " 0,\n",
2006
+ " 0,\n",
2007
+ " 0,\n",
2008
+ " 0,\n",
2009
+ " 0,\n",
2010
+ " 0,\n",
2011
+ " 0,\n",
2012
+ " 0,\n",
2013
+ " 0,\n",
2014
+ " 0,\n",
2015
+ " 0,\n",
2016
+ " 0,\n",
2017
+ " 0,\n",
2018
+ " 0,\n",
2019
+ " 0,\n",
2020
+ " 0,\n",
2021
+ " 0,\n",
2022
+ " 0\n",
2023
+ " ],\n",
2024
+ " &quot;mark&quot;: 1\n",
2025
+ " },\n",
2026
+ " &quot;status&quot;: &quot;ACTIVE&quot;\n",
2027
+ " },\n",
2028
+ " {\n",
2029
+ " &quot;action&quot;: 0,\n",
2030
+ " &quot;reward&quot;: 0,\n",
2031
+ " &quot;info&quot;: {},\n",
2032
+ " &quot;observation&quot;: {\n",
2033
+ " &quot;mark&quot;: 2\n",
2034
+ " },\n",
2035
+ " &quot;status&quot;: &quot;INACTIVE&quot;\n",
2036
+ " }\n",
2037
+ " ]\n",
2038
+ " ],\n",
2039
+ " &quot;rewards&quot;: [\n",
2040
+ " 0,\n",
2041
+ " 0\n",
2042
+ " ],\n",
2043
+ " &quot;statuses&quot;: [\n",
2044
+ " &quot;ACTIVE&quot;,\n",
2045
+ " &quot;INACTIVE&quot;\n",
2046
+ " ],\n",
2047
+ " &quot;schema_version&quot;: 1\n",
2048
+ " },\n",
2049
+ " &quot;mode&quot;: &quot;ipython&quot;,\n",
2050
+ " &quot;interactive&quot;: true,\n",
2051
+ " &quot;width&quot;: 800,\n",
2052
+ " &quot;height&quot;: 600\n",
2053
+ "};\n",
2054
+ "\n",
2055
+ "\n",
2056
+ "window.kaggle.renderer = // Copyright 2020 Kaggle Inc\n",
2057
+ "//\n",
2058
+ "// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
2059
+ "// you may not use this file except in compliance with the License.\n",
2060
+ "// You may obtain a copy of the License at\n",
2061
+ "//\n",
2062
+ "// http://www.apache.org/licenses/LICENSE-2.0\n",
2063
+ "//\n",
2064
+ "// Unless required by applicable law or agreed to in writing, software\n",
2065
+ "// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
2066
+ "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
2067
+ "// See the License for the specific language governing permissions and\n",
2068
+ "// limitations under the License.\n",
2069
+ "\n",
2070
+ "function renderer({\n",
2071
+ " act,\n",
2072
+ " agents,\n",
2073
+ " environment,\n",
2074
+ " frame,\n",
2075
+ " height = 400,\n",
2076
+ " interactive,\n",
2077
+ " isInteractive,\n",
2078
+ " parent,\n",
2079
+ " step,\n",
2080
+ " update,\n",
2081
+ " width = 400,\n",
2082
+ "}) {\n",
2083
+ " // Configuration.\n",
2084
+ " const { rows, columns, inarow } = environment.configuration;\n",
2085
+ "\n",
2086
+ " // Common Dimensions.\n",
2087
+ " const unit = 8;\n",
2088
+ " const minCanvasSize = Math.min(height, width);\n",
2089
+ " const minOffset = minCanvasSize > 400 ? 30 : unit / 2;\n",
2090
+ " const cellSize = Math.min(\n",
2091
+ " (width - minOffset * 2) / columns,\n",
2092
+ " (height - minOffset * 2) / rows\n",
2093
+ " );\n",
2094
+ " const cellInset = 0.8;\n",
2095
+ " const pieceScale = cellSize / 100;\n",
2096
+ " const xOffset = Math.max(0, (width - cellSize * columns) / 2);\n",
2097
+ " const yOffset = Math.max(0, (height - cellSize * rows) / 2);\n",
2098
+ "\n",
2099
+ " // Canvas Setup.\n",
2100
+ " let canvas = parent.querySelector(&quot;canvas&quot;);\n",
2101
+ " if (!canvas) {\n",
2102
+ " canvas = document.createElement(&quot;canvas&quot;);\n",
2103
+ " parent.appendChild(canvas);\n",
2104
+ "\n",
2105
+ " if (interactive) {\n",
2106
+ " canvas.addEventListener(&quot;click&quot;, evt => {\n",
2107
+ " if (!isInteractive()) return;\n",
2108
+ " const rect = evt.target.getBoundingClientRect();\n",
2109
+ " const col = Math.floor((evt.clientX - rect.left - xOffset) / cellSize);\n",
2110
+ " if (col >= 0 && col < columns) act(col);\n",
2111
+ " });\n",
2112
+ " }\n",
2113
+ " }\n",
2114
+ " canvas.style.cursor = isInteractive() ? &quot;pointer&quot; : &quot;default&quot;;\n",
2115
+ "\n",
2116
+ " // Character Paths (based on 100x100 tiles).\n",
2117
+ " const kPath = new Path2D(\n",
2118
+ " `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`\n",
2119
+ " );\n",
2120
+ " const goose1Path = new Path2D(\n",
2121
+ " `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`\n",
2122
+ " );\n",
2123
+ " const goose2Path = new Path2D(\n",
2124
+ " `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`\n",
2125
+ " );\n",
2126
+ " const goose3Path = new Path2D(\n",
2127
+ " `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`\n",
2128
+ " );\n",
2129
+ "\n",
2130
+ " // Canvas setup and reset.\n",
2131
+ " let c = canvas.getContext(&quot;2d&quot;);\n",
2132
+ " canvas.width = width;\n",
2133
+ " canvas.height = height;\n",
2134
+ " c.fillStyle = &quot;#000B2A&quot;;\n",
2135
+ " c.fillRect(0, 0, canvas.width, canvas.height);\n",
2136
+ "\n",
2137
+ " const getRowCol = cell => [Math.floor(cell / columns), cell % columns];\n",
2138
+ "\n",
2139
+ " const getColor = (mark, opacity = 1) => {\n",
2140
+ " if (mark === 1) return `rgba(0,255,255,${opacity})`;\n",
2141
+ " if (mark === 2) return `rgba(255,255,255,${opacity})`;\n",
2142
+ " return &quot;#fff&quot;;\n",
2143
+ " };\n",
2144
+ "\n",
2145
+ " const drawCellCircle = (cell, xFrame = 1, yFrame = 1, radiusOffset = 0) => {\n",
2146
+ " const [row, col] = getRowCol(cell);\n",
2147
+ " c.arc(\n",
2148
+ " xOffset + xFrame * (col * cellSize + cellSize / 2),\n",
2149
+ " yOffset + yFrame * (row * cellSize + cellSize / 2),\n",
2150
+ " (cellInset * cellSize) / 2 - radiusOffset,\n",
2151
+ " 2 * Math.PI,\n",
2152
+ " false\n",
2153
+ " );\n",
2154
+ " };\n",
2155
+ "\n",
2156
+ " // Render the pieces.\n",
2157
+ " const board = environment.steps[step][0].observation.board;\n",
2158
+ "\n",
2159
+ " const drawPiece = mark => {\n",
2160
+ " // Base Styles.\n",
2161
+ " const opacity = minCanvasSize < 300 ? 0.6 - minCanvasSize / 1000 : 0.1;\n",
2162
+ " c.fillStyle = getColor(mark, opacity);\n",
2163
+ " c.strokeStyle = getColor(mark);\n",
2164
+ " c.shadowColor = getColor(mark);\n",
2165
+ " c.shadowBlur = 8 / cellInset;\n",
2166
+ " c.lineWidth = 1 / cellInset;\n",
2167
+ "\n",
2168
+ " // Outer circle.\n",
2169
+ " c.save();\n",
2170
+ " c.beginPath();\n",
2171
+ " c.arc(50, 50, 50, 2 * Math.PI, false);\n",
2172
+ " c.closePath();\n",
2173
+ " c.lineWidth *= 4;\n",
2174
+ " c.stroke();\n",
2175
+ " c.fill();\n",
2176
+ " c.restore();\n",
2177
+ "\n",
2178
+ " // Inner circle.\n",
2179
+ " c.beginPath();\n",
2180
+ " c.arc(50, 50, 40, 2 * Math.PI, false);\n",
2181
+ " c.closePath();\n",
2182
+ " c.stroke();\n",
2183
+ "\n",
2184
+ " // Kaggle &quot;K&quot;.\n",
2185
+ " if (mark === 1) {\n",
2186
+ " const scale = 0.54;\n",
2187
+ " c.save();\n",
2188
+ " c.translate(23, 23);\n",
2189
+ " c.scale(scale, scale);\n",
2190
+ " c.lineWidth /= scale;\n",
2191
+ " c.shadowBlur /= scale;\n",
2192
+ " c.stroke(kPath);\n",
2193
+ " c.restore();\n",
2194
+ " }\n",
2195
+ "\n",
2196
+ " // Kaggle &quot;Goose&quot;.\n",
2197
+ " if (mark === 2) {\n",
2198
+ " const scale = 0.6;\n",
2199
+ " c.save();\n",
2200
+ " c.translate(24, 28);\n",
2201
+ " c.scale(scale, scale);\n",
2202
+ " c.lineWidth /= scale;\n",
2203
+ " c.shadowBlur /= scale;\n",
2204
+ " c.stroke(goose1Path);\n",
2205
+ " c.stroke(goose2Path);\n",
2206
+ " c.stroke(goose3Path);\n",
2207
+ " c.beginPath();\n",
2208
+ " c.arc(38.5, 18.6, 2.7, 0, Math.PI * 2, false);\n",
2209
+ " c.closePath();\n",
2210
+ " c.fill();\n",
2211
+ " c.restore();\n",
2212
+ " }\n",
2213
+ " };\n",
2214
+ "\n",
2215
+ " for (let i = 0; i < board.length; i++) {\n",
2216
+ " const [row, col] = getRowCol(i);\n",
2217
+ " if (board[i] === 0) continue;\n",
2218
+ " // Easing In.\n",
2219
+ " let yFrame = Math.min(\n",
2220
+ " (columns * Math.pow(frame, 3)) / Math.floor(i / columns),\n",
2221
+ " 1\n",
2222
+ " );\n",
2223
+ "\n",
2224
+ " if (\n",
2225
+ " step > 1 &&\n",
2226
+ " environment.steps[step - 1][0].observation.board[i] === board[i]\n",
2227
+ " ) {\n",
2228
+ " yFrame = 1;\n",
2229
+ " }\n",
2230
+ "\n",
2231
+ " c.save();\n",
2232
+ " c.translate(\n",
2233
+ " xOffset + cellSize * col + (cellSize - cellSize * cellInset) / 2,\n",
2234
+ " yOffset +\n",
2235
+ " yFrame * (cellSize * row) +\n",
2236
+ " (cellSize - cellSize * cellInset) / 2\n",
2237
+ " );\n",
2238
+ " c.scale(pieceScale * cellInset, pieceScale * cellInset);\n",
2239
+ " drawPiece(board[i]);\n",
2240
+ " c.restore();\n",
2241
+ " }\n",
2242
+ "\n",
2243
+ " // Background Gradient.\n",
2244
+ " const bgRadius = (Math.min(rows, columns) * cellSize) / 2;\n",
2245
+ " const bgStyle = c.createRadialGradient(\n",
2246
+ " xOffset + (cellSize * columns) / 2,\n",
2247
+ " yOffset + (cellSize * rows) / 2,\n",
2248
+ " 0,\n",
2249
+ " xOffset + (cellSize * columns) / 2,\n",
2250
+ " yOffset + (cellSize * rows) / 2,\n",
2251
+ " bgRadius\n",
2252
+ " );\n",
2253
+ " bgStyle.addColorStop(0, &quot;#000B49&quot;);\n",
2254
+ " bgStyle.addColorStop(1, &quot;#000B2A&quot;);\n",
2255
+ "\n",
2256
+ " // Render the board overlay.\n",
2257
+ " c.beginPath();\n",
2258
+ " c.rect(0, 0, canvas.width, canvas.height);\n",
2259
+ " c.closePath();\n",
2260
+ " c.shadowBlur = 0;\n",
2261
+ " for (let i = 0; i < board.length; i++) {\n",
2262
+ " drawCellCircle(i);\n",
2263
+ " c.closePath();\n",
2264
+ " }\n",
2265
+ " c.fillStyle = bgStyle;\n",
2266
+ " c.fill(&quot;evenodd&quot;);\n",
2267
+ "\n",
2268
+ " // Render the board overlay cell outlines.\n",
2269
+ " for (let i = 0; i < board.length; i++) {\n",
2270
+ " c.beginPath();\n",
2271
+ " drawCellCircle(i);\n",
2272
+ " c.strokeStyle = &quot;#0361B2&quot;;\n",
2273
+ " c.lineWidth = 1;\n",
2274
+ " c.stroke();\n",
2275
+ " c.closePath();\n",
2276
+ " }\n",
2277
+ "\n",
2278
+ " const drawLine = (fromCell, toCell) => {\n",
2279
+ " if (frame < 0.5) return;\n",
2280
+ " const lineFrame = (frame - 0.5) / 0.5;\n",
2281
+ " const x1 = xOffset + (fromCell % columns) * cellSize + cellSize / 2;\n",
2282
+ " const x2 =\n",
2283
+ " x1 +\n",
2284
+ " lineFrame *\n",
2285
+ " (xOffset + ((toCell % columns) * cellSize + cellSize / 2) - x1);\n",
2286
+ " const y1 =\n",
2287
+ " yOffset + Math.floor(fromCell / columns) * cellSize + cellSize / 2;\n",
2288
+ " const y2 =\n",
2289
+ " y1 +\n",
2290
+ " lineFrame *\n",
2291
+ " (yOffset + Math.floor(toCell / columns) * cellSize + cellSize / 2 - y1);\n",
2292
+ " c.beginPath();\n",
2293
+ " c.lineCap = &quot;round&quot;;\n",
2294
+ " c.lineWidth = 4;\n",
2295
+ " c.strokeStyle = getColor(board[fromCell]);\n",
2296
+ " c.shadowBlur = 8;\n",
2297
+ " c.shadowColor = getColor(board[fromCell]);\n",
2298
+ " c.moveTo(x1, y1);\n",
2299
+ " c.lineTo(x2, y2);\n",
2300
+ " c.stroke();\n",
2301
+ " };\n",
2302
+ "\n",
2303
+ " // Generate a graph of the board.\n",
2304
+ " const getCell = (cell, rowOffset, columnOffset) => {\n",
2305
+ " const row = Math.floor(cell / columns) + rowOffset;\n",
2306
+ " const col = (cell % columns) + columnOffset;\n",
2307
+ " if (row < 0 || row >= rows || col < 0 || col >= columns) return -1;\n",
2308
+ " return col + row * columns;\n",
2309
+ " };\n",
2310
+ " const makeNode = cell => {\n",
2311
+ " const node = { cell, directions: [], value: board[cell] };\n",
2312
+ " for (let r = -1; r <= 1; r++) {\n",
2313
+ " for (let c = -1; c <= 1; c++) {\n",
2314
+ " if (r === 0 && c === 0) continue;\n",
2315
+ " node.directions.push(getCell(cell, r, c));\n",
2316
+ " }\n",
2317
+ " }\n",
2318
+ " return node;\n",
2319
+ " };\n",
2320
+ " const graph = board.map((_, i) => makeNode(i));\n",
2321
+ "\n",
2322
+ " // Check for any wins!\n",
2323
+ " const getSequence = (node, direction) => {\n",
2324
+ " const sequence = [node.cell];\n",
2325
+ " while (sequence.length < inarow) {\n",
2326
+ " const next = graph[node.directions[direction]];\n",
2327
+ " if (!next || node.value !== next.value || next.value === 0) return;\n",
2328
+ " node = next;\n",
2329
+ " sequence.push(node.cell);\n",
2330
+ " }\n",
2331
+ " return sequence;\n",
2332
+ " };\n",
2333
+ "\n",
2334
+ " // Check all nodes.\n",
2335
+ " for (let i = 0; i < board.length; i++) {\n",
2336
+ " // Check all directions (not the most efficient).\n",
2337
+ " for (let d = 0; d < 8; d++) {\n",
2338
+ " const seq = getSequence(graph[i], d);\n",
2339
+ " if (seq) {\n",
2340
+ " drawLine(seq[0], seq[3]);\n",
2341
+ " i = board.length;\n",
2342
+ " break;\n",
2343
+ " }\n",
2344
+ " }\n",
2345
+ " }\n",
2346
+ "\n",
2347
+ " // Upgrade the legend.\n",
2348
+ " if (agents.length && (!agents[0].color || !agents[0].image)) {\n",
2349
+ " const getPieceImage = mark => {\n",
2350
+ " const pieceCanvas = document.createElement(&quot;canvas&quot;);\n",
2351
+ " parent.appendChild(pieceCanvas);\n",
2352
+ " pieceCanvas.style.marginLeft = &quot;10000px&quot;;\n",
2353
+ " pieceCanvas.width = 100;\n",
2354
+ " pieceCanvas.height = 100;\n",
2355
+ " c = pieceCanvas.getContext(&quot;2d&quot;);\n",
2356
+ " c.translate(10, 10);\n",
2357
+ " c.scale(0.8, 0.8);\n",
2358
+ " drawPiece(mark);\n",
2359
+ " const dataUrl = pieceCanvas.toDataURL();\n",
2360
+ " parent.removeChild(pieceCanvas);\n",
2361
+ " return dataUrl;\n",
2362
+ " };\n",
2363
+ "\n",
2364
+ " agents.forEach(agent => {\n",
2365
+ " agent.color = getColor(agent.index + 1);\n",
2366
+ " agent.image = getPieceImage(agent.index + 1);\n",
2367
+ " });\n",
2368
+ " update({ agents });\n",
2369
+ " }\n",
2370
+ "};\n",
2371
+ "\n",
2372
+ "\n",
2373
+ " \n",
2374
+ " </script>\n",
2375
+ " <script>\n",
2376
+ " const h = htm.bind(preact.h);\n",
2377
+ " const { useContext, useEffect, useRef, useState } = preactHooks;\n",
2378
+ " const styled = window.styled.default;\n",
2379
+ "\n",
2380
+ " const Context = preact.createContext({});\n",
2381
+ "\n",
2382
+ " const Loading = styled.div`\n",
2383
+ " animation: rotate360 1.1s infinite linear;\n",
2384
+ " border: 8px solid rgba(255, 255, 255, 0.2);\n",
2385
+ " border-left-color: #0cb1ed;\n",
2386
+ " border-radius: 50%;\n",
2387
+ " height: 40px;\n",
2388
+ " position: relative;\n",
2389
+ " transform: translateZ(0);\n",
2390
+ " width: 40px;\n",
2391
+ "\n",
2392
+ " @keyframes rotate360 {\n",
2393
+ " 0% {\n",
2394
+ " transform: rotate(0deg);\n",
2395
+ " }\n",
2396
+ " 100% {\n",
2397
+ " transform: rotate(360deg);\n",
2398
+ " }\n",
2399
+ " }\n",
2400
+ " `;\n",
2401
+ "\n",
2402
+ " const Logo = styled(\n",
2403
+ " (props) => h`\n",
2404
+ " <a href=&quot;https://kaggle.com&quot; target=&quot;_blank&quot; className=${props.className}>\n",
2405
+ " <svg width=&quot;62px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 62 24&quot; version=&quot;1.1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;>\n",
2406
+ " <g fill=&quot;#1EBEFF&quot; fill-rule=&quot;nonzero&quot;>\n",
2407
+ " <path d=&quot;M10.2,17.8c0,0.1-0.1,0.1-0.2,0.1H7.7c-0.1,0-0.3-0.1-0.4-0.2l-3.8-4.9l-1.1,1v3.8 c0,0.2-0.1,0.3-0.3,0.3H0.3c-0.2,0-0.3-0.1-0.3-0.3V0.3C0.1,0.1,0.2,0,0.3,0h1.8c0.2,0,0.3,0.1,0.3,0.3V11L7,6.3 c0.1-0.1,0.2-0.2,0.4-0.2h2.4c0.1,0,0.2,0,0.2,0.1c0,0.1,0,0.2,0,0.2l-4.9,4.7l5.1,6.3C10.2,17.6,10.2,17.7,10.2,17.8z&quot;/>\n",
2408
+ " <path d=&quot;M19.6,17.9h-1.8c-0.2,0-0.3-0.1-0.3-0.3v-0.4c-0.8,0.6-1.8,0.9-3,0.9c-1.1,0-2-0.3-2.8-1 c-0.8-0.7-1.2-1.6-1.2-2.7c0-1.7,1.1-2.9,3.2-3.5c0.8-0.2,2.1-0.5,3.8-0.6c0.1-0.6-0.1-1.2-0.5-1.7c-0.4-0.5-1-0.7-1.7-0.7 c-1,0-2,0.4-3,1C12.2,9.1,12.1,9.1,12,9l-0.9-1.3C11,7.5,11,7.4,11.1,7.3c1.3-0.9,2.7-1.4,4.2-1.4c1.1,0,2.1,0.3,2.8,0.8 c1.1,0.8,1.7,2,1.7,3.7v7.3C19.9,17.8,19.8,17.9,19.6,17.9z M17.5,12.4c-1.7,0.2-2.9,0.4-3.5,0.7c-0.9,0.4-1.2,0.9-1.1,1.6 c0.1,0.4,0.2,0.7,0.6,0.9c0.3,0.2,0.7,0.4,1.1,0.4c1.2,0.1,2.2-0.2,2.9-1V12.4z&quot;/>\n",
2409
+ " <path d=&quot;M30.6,22.5c-0.9,1-2.3,1.5-4,1.5c-1,0-2-0.3-2.9-0.8c-0.2-0.1-0.4-0.3-0.7-0.5 c-0.3-0.2-0.6-0.5-0.9-0.7c-0.1-0.1-0.1-0.2,0-0.4l1.2-1.2c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1c1,1,1.9,1.5,2.8,1.5 c2.1,0,3.2-1.1,3.2-3.3v-1.4c-0.8,0.7-1.9,1-3.3,1c-1.7,0-3-0.6-4-1.9c-0.8-1.1-1.3-2.5-1.3-4.2c0-1.6,0.4-3,1.2-4.1 c0.9-1.3,2.3-2,4-2c1.3,0,2.4,0.3,3.3,1V6.4c0-0.2,0.1-0.3,0.3-0.3h1.8c0.2,0,0.3,0.1,0.3,0.3v11.7C32,20,31.5,21.5,30.6,22.5z M29.7,9.9c-0.4-1.1-1.4-1.7-3-1.7c-2,0-3.1,1.3-3.1,3.8c0,1.4,0.3,2.4,1,3.1c0.5,0.5,1.2,0.8,2,0.8c1.6,0,2.7-0.6,3.1-1.7V9.9z&quot;/>\n",
2410
+ " <path d=&quot;M42.9,22.5c-0.9,1-2.3,1.5-4,1.5c-1,0-2-0.3-2.9-0.8c-0.2-0.1-0.4-0.3-0.7-0.5 c-0.3-0.2-0.6-0.5-0.9-0.7c-0.1-0.1-0.1-0.2,0-0.4l1.2-1.2c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1c1,1,1.9,1.5,2.8,1.5 c2.1,0,3.2-1.1,3.2-3.3v-1.4c-0.8,0.7-1.9,1-3.3,1c-1.7,0-3-0.6-4-1.9c-0.8-1.1-1.3-2.5-1.3-4.2c0-1.6,0.4-3,1.2-4.1 c0.9-1.3,2.3-2,4-2c1.3,0,2.4,0.3,3.3,1V6.4c0-0.2,0.1-0.3,0.3-0.3H44c0.2,0,0.3,0.1,0.3,0.3v11.7C44.3,20,43.8,21.5,42.9,22.5z M42,9.9c-0.4-1.1-1.4-1.7-3-1.7c-2,0-3.1,1.3-3.1,3.8c0,1.4,0.3,2.4,1,3.1c0.5,0.5,1.2,0.8,2,0.8c1.6,0,2.7-0.6,3.1-1.7L42,9.9 L42,9.9z&quot;/>\n",
2411
+ " <path d=&quot;M48.3,17.9h-1.8c-0.2,0-0.3-0.1-0.3-0.3V0.3c0-0.2,0.1-0.3,0.3-0.3h1.8c0.2,0,0.3,0.1,0.3,0.3 v17.3C48.5,17.8,48.5,17.9,48.3,17.9z&quot;/>\n",
2412
+ " <path d=&quot;M61.4,12.6c0,0.2-0.1,0.3-0.3,0.3h-8.5c0.1,0.9,0.5,1.6,1.1,2.2c0.7,0.6,1.6,0.9,2.7,0.9 c1,0,1.8-0.3,2.6-0.8c0.2-0.1,0.3-0.1,0.4,0l1.2,1.3c0.1,0.1,0.1,0.3,0,0.4c-1.3,0.9-2.7,1.4-4.4,1.4c-1.8,0-3.3-0.6-4.4-1.8 c-1.1-1.2-1.7-2.7-1.7-4.5c0-1.7,0.6-3.2,1.7-4.4c1-1.1,2.4-1.6,4.1-1.6c1.6,0,2.9,0.6,4,1.7c1.1,1.2,1.6,2.6,1.5,4.4L61.4,12.6 z M58,8.7c-0.6-0.5-1.3-0.8-2.1-0.8c-0.8,0-1.5,0.3-2.1,0.8c-0.6,0.5-1,1.2-1.1,2H59C59,9.9,58.6,9.3,58,8.7z&quot;/>\n",
2413
+ " </g>\n",
2414
+ " </svg>\n",
2415
+ " </a>\n",
2416
+ " `\n",
2417
+ " )`\n",
2418
+ " display: inline-flex;\n",
2419
+ " `;\n",
2420
+ "\n",
2421
+ " const Header = styled((props) => {\n",
2422
+ " const { environment } = useContext(Context);\n",
2423
+ "\n",
2424
+ " return h`<div className=${props.className} >\n",
2425
+ " <${Logo} />\n",
2426
+ " ${environment.title}\n",
2427
+ " </div>`;\n",
2428
+ " })`\n",
2429
+ " align-items: center;\n",
2430
+ " border-bottom: 4px solid #212121;\n",
2431
+ " box-sizing: border-box;\n",
2432
+ " color: #fff;\n",
2433
+ " display: flex;\n",
2434
+ " flex: 0 0 36px;\n",
2435
+ " font-size: 14px;\n",
2436
+ " justify-content: space-between;\n",
2437
+ " padding: 0 8px;\n",
2438
+ " width: 100%;\n",
2439
+ " `;\n",
2440
+ "\n",
2441
+ " const Renderer = styled((props) => {\n",
2442
+ " const context = useContext(Context);\n",
2443
+ " const { animate, debug, playing, renderer, speed } = context;\n",
2444
+ " const ref = preact.createRef();\n",
2445
+ "\n",
2446
+ " useEffect(async () => {\n",
2447
+ " if (!ref.current) return;\n",
2448
+ "\n",
2449
+ " const renderFrame = async (start, step, lastFrame) => {\n",
2450
+ " if (step !== context.step) return;\n",
2451
+ " if (lastFrame === 1) {\n",
2452
+ " if (!animate) return;\n",
2453
+ " start = Date.now();\n",
2454
+ " }\n",
2455
+ " const frame =\n",
2456
+ " playing || animate\n",
2457
+ " ? Math.min((Date.now() - start) / speed, 1)\n",
2458
+ " : 1;\n",
2459
+ " try {\n",
2460
+ " if (debug) console.time(&quot;render&quot;);\n",
2461
+ " await renderer({\n",
2462
+ " ...context,\n",
2463
+ " frame,\n",
2464
+ " height: ref.current.clientHeight,\n",
2465
+ " hooks: preactHooks,\n",
2466
+ " parent: ref.current,\n",
2467
+ " preact,\n",
2468
+ " styled,\n",
2469
+ " width: ref.current.clientWidth,\n",
2470
+ " });\n",
2471
+ " } catch (error) {\n",
2472
+ " if (debug) console.error(error);\n",
2473
+ " console.log({ ...context, frame, error });\n",
2474
+ " } finally {\n",
2475
+ " if (debug) console.timeEnd(&quot;render&quot;);\n",
2476
+ " }\n",
2477
+ " window.requestAnimationFrame(() => renderFrame(start, step, frame));\n",
2478
+ " };\n",
2479
+ "\n",
2480
+ " await renderFrame(Date.now(), context.step);\n",
2481
+ " }, [ref.current, context.step, context.renderer]);\n",
2482
+ "\n",
2483
+ " return h`<div className=${props.className} ref=${ref} />`;\n",
2484
+ " })`\n",
2485
+ " align-items: center;\n",
2486
+ " box-sizing: border-box;\n",
2487
+ " display: flex;\n",
2488
+ " height: 100%;\n",
2489
+ " left: 0;\n",
2490
+ " justify-content: center;\n",
2491
+ " position: absolute;\n",
2492
+ " top: 0;\n",
2493
+ " width: 100%;\n",
2494
+ " `;\n",
2495
+ "\n",
2496
+ " const Processing = styled((props) => {\n",
2497
+ " const { processing } = useContext(Context);\n",
2498
+ " const text = processing === true ? &quot;Processing...&quot; : processing;\n",
2499
+ " return h`<div className=${props.className}>${text}</div>`;\n",
2500
+ " })`\n",
2501
+ " bottom: 0;\n",
2502
+ " color: #fff;\n",
2503
+ " font-size: 12px;\n",
2504
+ " left: 0;\n",
2505
+ " line-height: 24px;\n",
2506
+ " position: absolute;\n",
2507
+ " text-align: center;\n",
2508
+ " width: 100%;\n",
2509
+ " `;\n",
2510
+ "\n",
2511
+ " const Viewer = styled((props) => {\n",
2512
+ " const { processing } = useContext(Context);\n",
2513
+ " return h`<div className=${props.className}>\n",
2514
+ " <${Renderer} />\n",
2515
+ " ${processing && h`<${Processing} />`}\n",
2516
+ " </div>`;\n",
2517
+ " })`\n",
2518
+ " background-color: #000b2a;\n",
2519
+ " background-image: radial-gradient(\n",
2520
+ " circle closest-side,\n",
2521
+ " #000b49,\n",
2522
+ " #000b2a\n",
2523
+ " );\n",
2524
+ " display: flex;\n",
2525
+ " flex: 1;\n",
2526
+ " overflow: hidden;\n",
2527
+ " position: relative;\n",
2528
+ " width: 100%;\n",
2529
+ " `;\n",
2530
+ "\n",
2531
+ " const Legend = styled((props) => {\n",
2532
+ " const { agents, legend } = useContext(Context);\n",
2533
+ "\n",
2534
+ " return h`<div className=${props.className}>\n",
2535
+ " <ul>\n",
2536
+ " ${agents\n",
2537
+ " .sort((a, b) => a.index - b.index)\n",
2538
+ " .map(\n",
2539
+ " (a) =>\n",
2540
+ " h`<li key=${a.id} title=&quot;id: ${a.id}&quot; style=&quot;color:${\n",
2541
+ " a.color || &quot;#FFF&quot;\n",
2542
+ " }&quot;>${a.image && h`<img src=${a.image} />`}<span>${\n",
2543
+ " a.name\n",
2544
+ " }</span></li>`\n",
2545
+ " )}\n",
2546
+ " </ul>\n",
2547
+ " </div>`;\n",
2548
+ " })`\n",
2549
+ " background-color: #000b2a;\n",
2550
+ " font-family: sans-serif;\n",
2551
+ " font-size: 14px;\n",
2552
+ " width: 100%;\n",
2553
+ "\n",
2554
+ " ul {\n",
2555
+ " align-items: center;\n",
2556
+ " display: flex;\n",
2557
+ " flex-direction: row;\n",
2558
+ " justify-content: center;\n",
2559
+ " }\n",
2560
+ "\n",
2561
+ " li {\n",
2562
+ " align-items: center;\n",
2563
+ " display: inline-flex;\n",
2564
+ " padding: 8px;\n",
2565
+ " transition: color 1s;\n",
2566
+ " }\n",
2567
+ "\n",
2568
+ " span {\n",
2569
+ " max-width: 100px;\n",
2570
+ " overflow: hidden;\n",
2571
+ " text-overflow: ellipsis;\n",
2572
+ " white-space: nowrap;\n",
2573
+ " }\n",
2574
+ "\n",
2575
+ " img {\n",
2576
+ " height: 24px;\n",
2577
+ " margin-right: 4px;\n",
2578
+ " width: 24px;\n",
2579
+ " }\n",
2580
+ " `;\n",
2581
+ "\n",
2582
+ " const StepInput = styled.input.attrs({\n",
2583
+ " type: &quot;range&quot;,\n",
2584
+ " })`\n",
2585
+ " appearance: none;\n",
2586
+ " background: rgba(255, 255, 255, 0.15);\n",
2587
+ " border-radius: 2px;\n",
2588
+ " display: block;\n",
2589
+ " flex: 1;\n",
2590
+ " height: 4px;\n",
2591
+ " opacity: 0.8;\n",
2592
+ " outline: none;\n",
2593
+ " transition: opacity 0.2s;\n",
2594
+ " width: 100%;\n",
2595
+ "\n",
2596
+ " &:hover {\n",
2597
+ " opacity: 1;\n",
2598
+ " }\n",
2599
+ "\n",
2600
+ " &::-webkit-slider-thumb {\n",
2601
+ " appearance: none;\n",
2602
+ " background: #1ebeff;\n",
2603
+ " border-radius: 100%;\n",
2604
+ " cursor: pointer;\n",
2605
+ " height: 12px;\n",
2606
+ " margin: 0;\n",
2607
+ " position: relative;\n",
2608
+ " width: 12px;\n",
2609
+ "\n",
2610
+ " &::after {\n",
2611
+ " content: &quot;&quot;;\n",
2612
+ " position: absolute;\n",
2613
+ " top: 0px;\n",
2614
+ " left: 0px;\n",
2615
+ " width: 200px;\n",
2616
+ " height: 8px;\n",
2617
+ " background: green;\n",
2618
+ " }\n",
2619
+ " }\n",
2620
+ " `;\n",
2621
+ "\n",
2622
+ " const PlayButton = styled.button`\n",
2623
+ " align-items: center;\n",
2624
+ " background: none;\n",
2625
+ " border: none;\n",
2626
+ " color: white;\n",
2627
+ " cursor: pointer;\n",
2628
+ " display: flex;\n",
2629
+ " flex: 0 0 56px;\n",
2630
+ " font-size: 20px;\n",
2631
+ " height: 40px;\n",
2632
+ " justify-content: center;\n",
2633
+ " opacity: 0.8;\n",
2634
+ " outline: none;\n",
2635
+ " transition: opacity 0.2s;\n",
2636
+ "\n",
2637
+ " &:hover {\n",
2638
+ " opacity: 1;\n",
2639
+ " }\n",
2640
+ " `;\n",
2641
+ "\n",
2642
+ " const StepCount = styled.span`\n",
2643
+ " align-items: center;\n",
2644
+ " color: white;\n",
2645
+ " display: flex;\n",
2646
+ " font-size: 14px;\n",
2647
+ " justify-content: center;\n",
2648
+ " opacity: 0.8;\n",
2649
+ " padding: 0 16px;\n",
2650
+ " pointer-events: none;\n",
2651
+ " `;\n",
2652
+ "\n",
2653
+ " const Controls = styled((props) => {\n",
2654
+ " const { environment, pause, play, playing, setStep, step } = useContext(\n",
2655
+ " Context\n",
2656
+ " );\n",
2657
+ " const value = step + 1;\n",
2658
+ " const onClick = () => (playing ? pause() : play());\n",
2659
+ " const onInput = (e) => {\n",
2660
+ " pause();\n",
2661
+ " setStep(parseInt(e.target.value) - 1);\n",
2662
+ " };\n",
2663
+ "\n",
2664
+ " return h`\n",
2665
+ " <div className=${props.className}>\n",
2666
+ " <${PlayButton} onClick=${onClick}><svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24px&quot; height=&quot;24px&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;#FFFFFF&quot;>${\n",
2667
+ " playing\n",
2668
+ " ? h`<path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
2669
+ " : h`<path d=&quot;M8 5v14l11-7z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
2670
+ " }</svg><//>\n",
2671
+ " <${StepInput} min=&quot;1&quot; max=${\n",
2672
+ " environment.steps.length\n",
2673
+ " } value=&quot;${value}&quot; onInput=${onInput} />\n",
2674
+ " <${StepCount}>${value} / ${environment.steps.length}<//>\n",
2675
+ " </div>\n",
2676
+ " `;\n",
2677
+ " })`\n",
2678
+ " align-items: center;\n",
2679
+ " border-top: 4px solid #212121;\n",
2680
+ " display: flex;\n",
2681
+ " flex: 0 0 44px;\n",
2682
+ " width: 100%;\n",
2683
+ " `;\n",
2684
+ "\n",
2685
+ " const Info = styled((props) => {\n",
2686
+ " const {\n",
2687
+ " environment,\n",
2688
+ " playing,\n",
2689
+ " step,\n",
2690
+ " speed,\n",
2691
+ " animate,\n",
2692
+ " header,\n",
2693
+ " controls,\n",
2694
+ " settings,\n",
2695
+ " } = useContext(Context);\n",
2696
+ "\n",
2697
+ " return h`\n",
2698
+ " <div className=${props.className}>\n",
2699
+ " info:\n",
2700
+ " step(${step}),\n",
2701
+ " playing(${playing ? &quot;T&quot; : &quot;F&quot;}),\n",
2702
+ " speed(${speed}),\n",
2703
+ " animate(${animate ? &quot;T&quot; : &quot;F&quot;})\n",
2704
+ " </div>`;\n",
2705
+ " })`\n",
2706
+ " color: #888;\n",
2707
+ " font-family: monospace;\n",
2708
+ " font-size: 12px;\n",
2709
+ " `;\n",
2710
+ "\n",
2711
+ " const Settings = styled((props) => {\n",
2712
+ " const { environment, pause, play, playing, setStep, step } = useContext(\n",
2713
+ " Context\n",
2714
+ " );\n",
2715
+ "\n",
2716
+ " return h`\n",
2717
+ " <div className=${props.className}>\n",
2718
+ " <${Info} />\n",
2719
+ " </div>\n",
2720
+ " `;\n",
2721
+ " })`\n",
2722
+ " background: #fff;\n",
2723
+ " border-top: 4px solid #212121;\n",
2724
+ " box-sizing: border-box;\n",
2725
+ " padding: 20px;\n",
2726
+ " width: 100%;\n",
2727
+ "\n",
2728
+ " h1 {\n",
2729
+ " font-size: 20px;\n",
2730
+ " }\n",
2731
+ " `;\n",
2732
+ "\n",
2733
+ " const Player = styled((props) => {\n",
2734
+ " const context = useContext(Context);\n",
2735
+ " const { agents, controls, header, legend, loading, settings } = context;\n",
2736
+ " return h`\n",
2737
+ " <div className=${props.className}>\n",
2738
+ " ${loading && h`<${Loading} />`}\n",
2739
+ " ${!loading && header && h`<${Header} />`}\n",
2740
+ " ${!loading && h`<${Viewer} />`}\n",
2741
+ " ${!loading && agents.length > 0 && legend && h`<${Legend} />`}\n",
2742
+ " ${!loading && controls && h`<${Controls} />`}\n",
2743
+ " ${!loading && settings && h`<${Settings} />`}\n",
2744
+ " </div>`;\n",
2745
+ " })`\n",
2746
+ " align-items: center;\n",
2747
+ " background: #212121;\n",
2748
+ " border: 4px solid #212121;\n",
2749
+ " box-sizing: border-box;\n",
2750
+ " display: flex;\n",
2751
+ " flex-direction: column;\n",
2752
+ " height: 100%;\n",
2753
+ " justify-content: center;\n",
2754
+ " position: relative;\n",
2755
+ " width: 100%;\n",
2756
+ " `;\n",
2757
+ "\n",
2758
+ " const App = () => {\n",
2759
+ " const renderCountRef = useRef(0);\n",
2760
+ " const [_, setRenderCount] = useState(0);\n",
2761
+ "\n",
2762
+ " const contextRef = useRef({\n",
2763
+ " animate: false,\n",
2764
+ " agents: [],\n",
2765
+ " autoplay: false,\n",
2766
+ " controls: false,\n",
2767
+ " debug: false,\n",
2768
+ " environment: { steps: [] },\n",
2769
+ " header: window.innerHeight >= 600,\n",
2770
+ " interactive: false,\n",
2771
+ " legend: true,\n",
2772
+ " loading: false,\n",
2773
+ " playing: false,\n",
2774
+ " processing: false,\n",
2775
+ " renderer: () => &quot;DNE&quot;,\n",
2776
+ " settings: false,\n",
2777
+ " speed: 500,\n",
2778
+ " step: 0,\n",
2779
+ " });\n",
2780
+ "\n",
2781
+ " // Context helpers.\n",
2782
+ " const rerender = (contextRef.current.rerender = () =>\n",
2783
+ " setRenderCount((renderCountRef.current += 1)));\n",
2784
+ " const setStep = (contextRef.current.setStep = (newStep) => {\n",
2785
+ " contextRef.current.step = newStep;\n",
2786
+ " rerender();\n",
2787
+ " });\n",
2788
+ " const setPlaying = (contextRef.current.setPlaying = (playing) => {\n",
2789
+ " contextRef.current.playing = playing;\n",
2790
+ " rerender();\n",
2791
+ " });\n",
2792
+ " const pause = (contextRef.current.pause = () => setPlaying(false));\n",
2793
+ "\n",
2794
+ " const playNext = () => {\n",
2795
+ " const context = contextRef.current;\n",
2796
+ "\n",
2797
+ " if (\n",
2798
+ " context.playing &&\n",
2799
+ " context.step < context.environment.steps.length - 1\n",
2800
+ " ) {\n",
2801
+ " setStep(context.step + 1);\n",
2802
+ " play(true);\n",
2803
+ " } else {\n",
2804
+ " pause();\n",
2805
+ " }\n",
2806
+ " };\n",
2807
+ "\n",
2808
+ " const play = (contextRef.current.play = (continuing) => {\n",
2809
+ " const context = contextRef.current;\n",
2810
+ " if (context.playing && !continuing) return;\n",
2811
+ " if (!context.playing) setPlaying(true);\n",
2812
+ " if (\n",
2813
+ " !continuing &&\n",
2814
+ " context.step === context.environment.steps.length - 1\n",
2815
+ " ) {\n",
2816
+ " setStep(0);\n",
2817
+ " }\n",
2818
+ " setTimeout(playNext, context.speed);\n",
2819
+ " });\n",
2820
+ "\n",
2821
+ " const updateContext = (o) => {\n",
2822
+ " const context = contextRef.current;\n",
2823
+ " Object.assign(context, o, {\n",
2824
+ " environment: { ...context.environment, ...(o.environment || {}) },\n",
2825
+ " });\n",
2826
+ " rerender();\n",
2827
+ "\n",
2828
+ " // If autoplay, toggle to playing.\n",
2829
+ " if (context.autoplay) play();\n",
2830
+ " };\n",
2831
+ "\n",
2832
+ " // First time setup.\n",
2833
+ " useEffect(() => {\n",
2834
+ " // Timeout is used to ensure useEffect renders once.\n",
2835
+ " setTimeout(() => {\n",
2836
+ " // Initialize context with window.kaggle.\n",
2837
+ " updateContext(window.kaggle || {});\n",
2838
+ " // Listen for messages received to update the context.\n",
2839
+ " window.addEventListener(\n",
2840
+ " &quot;message&quot;,\n",
2841
+ " (event) => {\n",
2842
+ " // Ensure the environment names match before updating.\n",
2843
+ " try {\n",
2844
+ " if (\n",
2845
+ " event.data.environment.name ==\n",
2846
+ " contextRef.current.environment.name\n",
2847
+ " ) {\n",
2848
+ " updateContext(event.data);\n",
2849
+ " }\n",
2850
+ " } catch {}\n",
2851
+ " },\n",
2852
+ " false\n",
2853
+ " );\n",
2854
+ " // Listen for keyboard commands.\n",
2855
+ " window.addEventListener(\n",
2856
+ " &quot;keydown&quot;,\n",
2857
+ " (event) => {\n",
2858
+ " const {\n",
2859
+ " interactive,\n",
2860
+ " isInteractive,\n",
2861
+ " playing,\n",
2862
+ " step,\n",
2863
+ " environment,\n",
2864
+ " } = contextRef.current;\n",
2865
+ " const key = event.keyCode;\n",
2866
+ " if (\n",
2867
+ " interactive ||\n",
2868
+ " isInteractive() ||\n",
2869
+ " (key !== 32 && key !== 37 && key !== 39)\n",
2870
+ " )\n",
2871
+ " return;\n",
2872
+ "\n",
2873
+ " if (key === 32) {\n",
2874
+ " playing ? pause() : play();\n",
2875
+ " } else if (event.keyCode === 39) {\n",
2876
+ " contextRef.current.playing = false;\n",
2877
+ " if (step < environment.steps.length - 1) setStep(step + 1);\n",
2878
+ " rerender();\n",
2879
+ " } else if (event.keyCode === 37) {\n",
2880
+ " contextRef.current.playing = false;\n",
2881
+ " if (step > 0) setStep(step - 1);\n",
2882
+ " rerender();\n",
2883
+ " }\n",
2884
+ " event.preventDefault();\n",
2885
+ " return false;\n",
2886
+ " },\n",
2887
+ " false\n",
2888
+ " );\n",
2889
+ " }, 1);\n",
2890
+ " }, []);\n",
2891
+ "\n",
2892
+ " if (contextRef.current.debug) {\n",
2893
+ " console.log(&quot;context&quot;, contextRef.current);\n",
2894
+ " }\n",
2895
+ "\n",
2896
+ " // Ability to update context.\n",
2897
+ " contextRef.current.update = updateContext;\n",
2898
+ "\n",
2899
+ " // Ability to communicate with ipython.\n",
2900
+ " const execute = (contextRef.current.execute = (source) =>\n",
2901
+ " new Promise((resolve, reject) => {\n",
2902
+ " try {\n",
2903
+ " window.parent.IPython.notebook.kernel.execute(source, {\n",
2904
+ " iopub: {\n",
2905
+ " output: (resp) => {\n",
2906
+ " const type = resp.msg_type;\n",
2907
+ " if (type === &quot;stream&quot;) return resolve(resp.content.text);\n",
2908
+ " if (type === &quot;error&quot;) return reject(new Error(resp.evalue));\n",
2909
+ " return reject(new Error(&quot;Unknown message type: &quot; + type));\n",
2910
+ " },\n",
2911
+ " },\n",
2912
+ " });\n",
2913
+ " } catch (e) {\n",
2914
+ " reject(new Error(&quot;IPython Unavailable: &quot; + e));\n",
2915
+ " }\n",
2916
+ " }));\n",
2917
+ "\n",
2918
+ " // Ability to return an action from an interactive session.\n",
2919
+ " contextRef.current.act = (action) => {\n",
2920
+ " const id = contextRef.current.environment.id;\n",
2921
+ " updateContext({ processing: true });\n",
2922
+ " execute(`\n",
2923
+ " import json\n",
2924
+ " from kaggle_environments import interactives\n",
2925
+ " if &quot;${id}&quot; in interactives:\n",
2926
+ " action = json.loads('${JSON.stringify(action)}')\n",
2927
+ " env, trainer = interactives[&quot;${id}&quot;]\n",
2928
+ " trainer.step(action)\n",
2929
+ " print(json.dumps(env.steps))`)\n",
2930
+ " .then((resp) => {\n",
2931
+ " try {\n",
2932
+ " updateContext({\n",
2933
+ " processing: false,\n",
2934
+ " environment: { steps: JSON.parse(resp) },\n",
2935
+ " });\n",
2936
+ " play();\n",
2937
+ " } catch (e) {\n",
2938
+ " updateContext({ processing: resp.split(&quot;\\n&quot;)[0] });\n",
2939
+ " console.error(resp, e);\n",
2940
+ " }\n",
2941
+ " })\n",
2942
+ " .catch((e) => console.error(e));\n",
2943
+ " };\n",
2944
+ "\n",
2945
+ " // Check if currently interactive.\n",
2946
+ " contextRef.current.isInteractive = () => {\n",
2947
+ " const context = contextRef.current;\n",
2948
+ " const steps = context.environment.steps;\n",
2949
+ " return (\n",
2950
+ " context.interactive &&\n",
2951
+ " !context.processing &&\n",
2952
+ " context.step === steps.length - 1 &&\n",
2953
+ " steps[context.step].some((s) => s.status === &quot;ACTIVE&quot;)\n",
2954
+ " );\n",
2955
+ " };\n",
2956
+ "\n",
2957
+ " return h`\n",
2958
+ " <${Context.Provider} value=${contextRef.current}>\n",
2959
+ " <${Player} />\n",
2960
+ " <//>`;\n",
2961
+ " };\n",
2962
+ "\n",
2963
+ " preact.render(h`<${App} />`, document.body);\n",
2964
+ " </script>\n",
2965
+ " </body>\n",
2966
+ "</html>\n",
2967
+ "\" width=\"800\" height=\"600\" frameborder=\"0\"></iframe> "
2968
+ ],
2969
+ "text/plain": [
2970
+ "<IPython.core.display.HTML object>"
2971
+ ]
2972
+ },
2973
+ "metadata": {},
2974
+ "output_type": "display_data"
2975
+ }
2976
+ ],
2977
+ "source": [
2978
+ "env = make(\"connectx\")\n",
2979
+ "# Play against 3 default shortest agents.\n",
2980
+ "env.play([None, \"negamax\"], width=800, height=600)"
2981
+ ]
2982
+ },
2983
+ {
2984
+ "cell_type": "markdown",
2985
+ "metadata": {},
2986
+ "source": [
2987
+ "## Training using Gym"
2988
+ ]
2989
+ },
2990
+ {
2991
+ "cell_type": "code",
2992
+ "execution_count": 5,
2993
+ "metadata": {
2994
+ "scrolled": false
2995
+ },
2996
+ "outputs": [
2997
+ {
2998
+ "name": "stdout",
2999
+ "output_type": "stream",
3000
+ "text": [
3001
+ "+---+---+---+---+---+---+---+\n",
3002
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3003
+ "+---+---+---+---+---+---+---+\n",
3004
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3005
+ "+---+---+---+---+---+---+---+\n",
3006
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3007
+ "+---+---+---+---+---+---+---+\n",
3008
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3009
+ "+---+---+---+---+---+---+---+\n",
3010
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3011
+ "+---+---+---+---+---+---+---+\n",
3012
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3013
+ "+---+---+---+---+---+---+---+\n",
3014
+ "\n",
3015
+ "+---+---+---+---+---+---+---+\n",
3016
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3017
+ "+---+---+---+---+---+---+---+\n",
3018
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3019
+ "+---+---+---+---+---+---+---+\n",
3020
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3021
+ "+---+---+---+---+---+---+---+\n",
3022
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3023
+ "+---+---+---+---+---+---+---+\n",
3024
+ "| 2 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3025
+ "+---+---+---+---+---+---+---+\n",
3026
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3027
+ "+---+---+---+---+---+---+---+\n",
3028
+ "\n",
3029
+ "+---+---+---+---+---+---+---+\n",
3030
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3031
+ "+---+---+---+---+---+---+---+\n",
3032
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3033
+ "+---+---+---+---+---+---+---+\n",
3034
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3035
+ "+---+---+---+---+---+---+---+\n",
3036
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3037
+ "+---+---+---+---+---+---+---+\n",
3038
+ "| 2 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3039
+ "+---+---+---+---+---+---+---+\n",
3040
+ "| 1 | 0 | 0 | 0 | 2 | 0 | 0 |\n",
3041
+ "+---+---+---+---+---+---+---+\n",
3042
+ "\n",
3043
+ "+---+---+---+---+---+---+---+\n",
3044
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3045
+ "+---+---+---+---+---+---+---+\n",
3046
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3047
+ "+---+---+---+---+---+---+---+\n",
3048
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3049
+ "+---+---+---+---+---+---+---+\n",
3050
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3051
+ "+---+---+---+---+---+---+---+\n",
3052
+ "| 2 | 0 | 0 | 0 | 2 | 0 | 0 |\n",
3053
+ "+---+---+---+---+---+---+---+\n",
3054
+ "| 1 | 0 | 0 | 0 | 2 | 0 | 0 |\n",
3055
+ "+---+---+---+---+---+---+---+\n",
3056
+ "\n",
3057
+ "+---+---+---+---+---+---+---+\n",
3058
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3059
+ "+---+---+---+---+---+---+---+\n",
3060
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3061
+ "+---+---+---+---+---+---+---+\n",
3062
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3063
+ "+---+---+---+---+---+---+---+\n",
3064
+ "| 1 | 0 | 0 | 0 | 2 | 0 | 0 |\n",
3065
+ "+---+---+---+---+---+---+---+\n",
3066
+ "| 2 | 0 | 0 | 0 | 2 | 0 | 0 |\n",
3067
+ "+---+---+---+---+---+---+---+\n",
3068
+ "| 1 | 0 | 0 | 0 | 2 | 0 | 0 |\n",
3069
+ "+---+---+---+---+---+---+---+\n",
3070
+ "\n",
3071
+ "+---+---+---+---+---+---+---+\n",
3072
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3073
+ "+---+---+---+---+---+---+---+\n",
3074
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3075
+ "+---+---+---+---+---+---+---+\n",
3076
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3077
+ "+---+---+---+---+---+---+---+\n",
3078
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3079
+ "+---+---+---+---+---+---+---+\n",
3080
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3081
+ "+---+---+---+---+---+---+---+\n",
3082
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3083
+ "+---+---+---+---+---+---+---+\n",
3084
+ "\n",
3085
+ "+---+---+---+---+---+---+---+\n",
3086
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3087
+ "+---+---+---+---+---+---+---+\n",
3088
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3089
+ "+---+---+---+---+---+---+---+\n",
3090
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3091
+ "+---+---+---+---+---+---+---+\n",
3092
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3093
+ "+---+---+---+---+---+---+---+\n",
3094
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3095
+ "+---+---+---+---+---+---+---+\n",
3096
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 2 |\n",
3097
+ "+---+---+---+---+---+---+---+\n",
3098
+ "\n",
3099
+ "+---+---+---+---+---+---+---+\n",
3100
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3101
+ "+---+---+---+---+---+---+---+\n",
3102
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3103
+ "+---+---+---+---+---+---+---+\n",
3104
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3105
+ "+---+---+---+---+---+---+---+\n",
3106
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3107
+ "+---+---+---+---+---+---+---+\n",
3108
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3109
+ "+---+---+---+---+---+---+---+\n",
3110
+ "| 1 | 0 | 0 | 0 | 2 | 0 | 2 |\n",
3111
+ "+---+---+---+---+---+---+---+\n",
3112
+ "\n",
3113
+ "+---+---+---+---+---+---+---+\n",
3114
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3115
+ "+---+---+---+---+---+---+---+\n",
3116
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3117
+ "+---+---+---+---+---+---+---+\n",
3118
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3119
+ "+---+---+---+---+---+---+---+\n",
3120
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3121
+ "+---+---+---+---+---+---+---+\n",
3122
+ "| 1 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3123
+ "+---+---+---+---+---+---+---+\n",
3124
+ "| 1 | 0 | 2 | 0 | 2 | 0 | 2 |\n",
3125
+ "+---+---+---+---+---+---+---+\n",
3126
+ "\n",
3127
+ "+---+---+---+---+---+---+---+\n",
3128
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3129
+ "+---+---+---+---+---+---+---+\n",
3130
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3131
+ "+---+---+---+---+---+---+---+\n",
3132
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3133
+ "+---+---+---+---+---+---+---+\n",
3134
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3135
+ "+---+---+---+---+---+---+---+\n",
3136
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3137
+ "+---+---+---+---+---+---+---+\n",
3138
+ "| 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n",
3139
+ "+---+---+---+---+---+---+---+\n",
3140
+ "\n"
3141
+ ]
3142
+ }
3143
+ ],
3144
+ "source": [
3145
+ "from kaggle_environments import make\n",
3146
+ "\n",
3147
+ "env = make(\"connectx\", debug=True)\n",
3148
+ "\n",
3149
+ "# Training agent in first position (player 1) against the default random agent.\n",
3150
+ "trainer = env.train([None, \"random\"])\n",
3151
+ "\n",
3152
+ "obs = trainer.reset()\n",
3153
+ "for _ in range(10):\n",
3154
+ " env.render()\n",
3155
+ " action = 0 # Action for the agent being trained.\n",
3156
+ " obs, reward, done, info = trainer.step(action)\n",
3157
+ " if done:\n",
3158
+ " obs = trainer.reset()"
3159
+ ]
3160
+ }
3161
+ ],
3162
+ "metadata": {
3163
+ "kernelspec": {
3164
+ "display_name": "Python 3",
3165
+ "language": "python",
3166
+ "name": "python3"
3167
+ },
3168
+ "language_info": {
3169
+ "codemirror_mode": {
3170
+ "name": "ipython",
3171
+ "version": 3
3172
+ },
3173
+ "file_extension": ".py",
3174
+ "mimetype": "text/x-python",
3175
+ "name": "python",
3176
+ "nbconvert_exporter": "python",
3177
+ "pygments_lexer": "ipython3",
3178
+ "version": "3.6.6"
3179
+ }
3180
+ },
3181
+ "nbformat": 4,
3182
+ "nbformat_minor": 2
3183
+ }