kaggle-ConnectX/connectx-josh-is-getting-st...

4335 lines
167 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Install kaggle-environments"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
"_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: kaggle-environments in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (1.7.6)\n",
"Requirement already satisfied: jsonschema>=3.0.1 in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from kaggle-environments) (3.2.0)\n",
"Requirement already satisfied: six>=1.11.0 in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from jsonschema>=3.0.1->kaggle-environments) (1.15.0)\n",
"Requirement already satisfied: setuptools in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from jsonschema>=3.0.1->kaggle-environments) (51.0.0.post20201207)\n",
"Requirement already satisfied: attrs>=17.4.0 in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from jsonschema>=3.0.1->kaggle-environments) (20.3.0)\n",
"Requirement already satisfied: pyrsistent>=0.14.0 in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from jsonschema>=3.0.1->kaggle-environments) (0.17.3)\n",
"Collecting gfootball\n",
" Downloading gfootball-2.8.tar.gz (8.7 MB)\n",
"\u001b[K |████████████████████████████████| 8.7 MB 1.5 MB/s eta 0:00:01 |████████████████████████▏ | 6.6 MB 1.9 MB/s eta 0:00:02\n",
"\u001b[?25hRequirement already satisfied: scipy in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from gfootball) (1.5.4)\n",
"Requirement already satisfied: gym>=0.11.0 in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from gfootball) (0.18.0)\n",
"Requirement already satisfied: absl-py in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from gfootball) (0.11.0)\n",
"Requirement already satisfied: wheel in /home/josh/anaconda3/envs/muzero-general/lib/python3.8/site-packages (from gfootball) (0.36.2)\n",
"Collecting pygame==1.9.6\n",
" Downloading pygame-1.9.6.tar.gz (3.2 MB)\n",
"\u001b[K |████████████████████████████████| 3.2 MB 852 kB/s eta 0:00:01\n",
"\u001b[31m ERROR: Command errored out with exit status 1:\n",
" command: /home/josh/anaconda3/envs/muzero-general/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '\"'\"'/tmp/pip-install-z_nwsjyx/pygame_d54f0305be8f4d84bc572907b4852505/setup.py'\"'\"'; __file__='\"'\"'/tmp/pip-install-z_nwsjyx/pygame_d54f0305be8f4d84bc572907b4852505/setup.py'\"'\"';f=getattr(tokenize, '\"'\"'open'\"'\"', open)(__file__);code=f.read().replace('\"'\"'\\r\\n'\"'\"', '\"'\"'\\n'\"'\"');f.close();exec(compile(code, __file__, '\"'\"'exec'\"'\"'))' egg_info --egg-base /tmp/pip-pip-egg-info-2d2vpvhf\n",
" cwd: /tmp/pip-install-z_nwsjyx/pygame_d54f0305be8f4d84bc572907b4852505/\n",
" Complete output (25 lines):\n",
" \n",
" \n",
" WARNING, No \"Setup\" File Exists, Running \"buildconfig/config.py\"\n",
" Using UNIX configuration...\n",
" \n",
" /bin/sh: 1: sdl-config: not found\n",
" /bin/sh: 1: sdl-config: not found\n",
" /bin/sh: 1: sdl-config: not found\n",
" Package freetype2 was not found in the pkg-config search path.\n",
" Perhaps you should add the directory containing `freetype2.pc'\n",
" to the PKG_CONFIG_PATH environment variable\n",
" No package 'freetype2' found\n",
" Package freetype2 was not found in the pkg-config search path.\n",
" Perhaps you should add the directory containing `freetype2.pc'\n",
" to the PKG_CONFIG_PATH environment variable\n",
" No package 'freetype2' found\n",
" Package freetype2 was not found in the pkg-config search path.\n",
" Perhaps you should add the directory containing `freetype2.pc'\n",
" to the PKG_CONFIG_PATH environment variable\n",
" No package 'freetype2' found\n",
" \n",
" Hunting dependencies...\n",
" WARNING: \"sdl-config\" failed!\n",
" WARNING: \"pkg-config freetype2\" failed!\n",
" Unable to run \"sdl-config\". Please make sure a development version of SDL is installed.\n",
" ----------------------------------------\u001b[0m\n",
"\u001b[31mERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.\u001b[0m\n",
"\u001b[?25h"
]
}
],
"source": [
"# 1. Enable Internet in the Kernel (Settings side pane)\n",
"\n",
"# 2. Curl cache may need purged if v0.1.4 cannot be found (uncomment if needed). \n",
"# !curl -X PURGE https://pypi.org/simple/kaggle-environments\n",
"\n",
"# ConnectX environment was defined in v0.1.4\n",
"#!pip install 'kaggle-environments>=0.1.4'\n",
"!pip install 'kaggle-environments'\n",
"#!pip install 'gfootball'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Create ConnectX Environment"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"_cell_guid": "79c7e3d0-c299-4dcb-8224-4455121ee9b0",
"_uuid": "d629ff2d2480ee46fbb7e2d37f6b5fab8052498a"
},
"outputs": [],
"source": [
"from kaggle_environments import evaluate, make\n",
"\n",
"env = make(\"connectx\", debug=True)\n",
"env.render()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading environment football failed: No module named 'gfootball'\n"
]
}
],
"source": [
"import kaggle_environments\n",
"\n",
"env = kaggle_environments.make(\"connectx\", debug=True)\n",
"env.render()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<iframe srcdoc=\"<!--\n",
" Copyright 2020 Kaggle Inc\n",
"\n",
" Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
" you may not use this file except in compliance with the License.\n",
" You may obtain a copy of the License at\n",
"\n",
" http://www.apache.org/licenses/LICENSE-2.0\n",
"\n",
" Unless required by applicable law or agreed to in writing, software\n",
" distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
" See the License for the specific language governing permissions and\n",
" limitations under the License.\n",
"-->\n",
"<!DOCTYPE html>\n",
"<html lang=&quot;en&quot;>\n",
" <head>\n",
" <title>Kaggle Simulation Player</title>\n",
" <meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot; />\n",
" <link\n",
" rel=&quot;stylesheet&quot;\n",
" href=&quot;https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css&quot;\n",
" crossorigin=&quot;anonymous&quot;\n",
" />\n",
" <style type=&quot;text/css&quot;>\n",
" html,\n",
" body {\n",
" height: 100%;\n",
" font-family: sans-serif;\n",
" margin: 0px;\n",
" }\n",
" canvas {\n",
" /* image-rendering: -moz-crisp-edges;\n",
" image-rendering: -webkit-crisp-edges;\n",
" image-rendering: pixelated;\n",
" image-rendering: crisp-edges; */\n",
" }\n",
" </style>\n",
" <script src=&quot;https://unpkg.com/preact@10.0.1/dist/preact.umd.js&quot;></script>\n",
" <script src=&quot;https://unpkg.com/preact@10.0.1/hooks/dist/hooks.umd.js&quot;></script>\n",
" <script src=&quot;https://unpkg.com/htm@2.2.1/dist/htm.umd.js&quot;></script>\n",
" <script>\n",
" // Polyfill for Styled Components\n",
" window.React = {\n",
" ...preact,\n",
" createElement: preact.h,\n",
" PropTypes: { func: {} },\n",
" };\n",
" </script>\n",
" <script src=&quot;https://unpkg.com/styled-components@3.5.0-0/dist/styled-components.min.js&quot;></script>\n",
" </head>\n",
" <body>\n",
" <script>\n",
" \n",
"window.kaggle = {\n",
" &quot;debug&quot;: false,\n",
" &quot;autoplay&quot;: true,\n",
" &quot;step&quot;: 0,\n",
" &quot;controls&quot;: true,\n",
" &quot;environment&quot;: {\n",
" &quot;id&quot;: &quot;e466c0e6-7fe1-11eb-8edb-4f088413800f&quot;,\n",
" &quot;name&quot;: &quot;tictactoe&quot;,\n",
" &quot;title&quot;: &quot;Tic Tac Toe&quot;,\n",
" &quot;description&quot;: &quot;Classic Tic Tac Toe&quot;,\n",
" &quot;version&quot;: &quot;1.0.0&quot;,\n",
" &quot;configuration&quot;: {\n",
" &quot;episodeSteps&quot;: 10,\n",
" &quot;actTimeout&quot;: 1,\n",
" &quot;runTimeout&quot;: 1200,\n",
" &quot;agentTimeout&quot;: 2\n",
" },\n",
" &quot;specification&quot;: {\n",
" &quot;action&quot;: {\n",
" &quot;description&quot;: &quot;Position to place a mark on the board.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;maximum&quot;: 8,\n",
" &quot;default&quot;: 0\n",
" },\n",
" &quot;agents&quot;: [\n",
" 2\n",
" ],\n",
" &quot;configuration&quot;: {\n",
" &quot;episodeSteps&quot;: {\n",
" &quot;description&quot;: &quot;Maximum number of steps in the episode.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;minimum&quot;: 1,\n",
" &quot;default&quot;: 10\n",
" },\n",
" &quot;actTimeout&quot;: {\n",
" &quot;description&quot;: &quot;Maximum runtime (seconds) to obtain an action from an agent.&quot;,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 1\n",
" },\n",
" &quot;runTimeout&quot;: {\n",
" &quot;description&quot;: &quot;Maximum runtime (seconds) of an episode (not necessarily DONE).&quot;,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 1200\n",
" },\n",
" &quot;agentTimeout&quot;: {\n",
" &quot;description&quot;: &quot;Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.&quot;,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 2\n",
" }\n",
" },\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: {\n",
" &quot;description&quot;: &quot;Total remaining banked time (seconds) that can be used in excess of per-step actTimeouts -- agent is disqualified with TIMEOUT status when this drops below 0.&quot;,\n",
" &quot;shared&quot;: false,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 2\n",
" },\n",
" &quot;step&quot;: {\n",
" &quot;description&quot;: &quot;Current step within the episode.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;shared&quot;: true,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 0\n",
" },\n",
" &quot;board&quot;: {\n",
" &quot;description&quot;: &quot;Serialized 3x3 grid. 0 = Empty, 1 = X, 2 = O&quot;,\n",
" &quot;type&quot;: &quot;array&quot;,\n",
" &quot;shared&quot;: true,\n",
" &quot;default&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;minItems&quot;: 9,\n",
" &quot;maxItems&quot;: 9\n",
" },\n",
" &quot;mark&quot;: {\n",
" &quot;description&quot;: &quot;Mark for the agent to use&quot;,\n",
" &quot;defaults&quot;: [\n",
" 1,\n",
" 2\n",
" ],\n",
" &quot;enum&quot;: [\n",
" 1,\n",
" 2\n",
" ]\n",
" }\n",
" },\n",
" &quot;reward&quot;: {\n",
" &quot;description&quot;: &quot;-1 = Lost, 0 = Draw/Ongoing, 1 = Won&quot;,\n",
" &quot;enum&quot;: [\n",
" -1,\n",
" 0,\n",
" 1\n",
" ],\n",
" &quot;default&quot;: 0,\n",
" &quot;type&quot;: [\n",
" &quot;number&quot;,\n",
" &quot;null&quot;\n",
" ]\n",
" }\n",
" },\n",
" &quot;steps&quot;: [\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 0,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 1,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 2,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 1,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 2,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 3,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 4,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 8,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 3,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 5,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 6,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 1,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 2\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 5,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 4,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 7,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 1,\n",
" 1,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 2\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 8,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 1,\n",
" 1,\n",
" 2,\n",
" 0,\n",
" 2,\n",
" 2\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 7,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 6,\n",
" &quot;reward&quot;: 1,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;step&quot;: 9,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 1,\n",
" 1,\n",
" 2,\n",
" 1,\n",
" 2,\n",
" 2\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;DONE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: -1,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 2,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;DONE&quot;\n",
" }\n",
" ]\n",
" ],\n",
" &quot;rewards&quot;: [\n",
" 1,\n",
" -1\n",
" ],\n",
" &quot;statuses&quot;: [\n",
" &quot;DONE&quot;,\n",
" &quot;DONE&quot;\n",
" ],\n",
" &quot;schema_version&quot;: 1,\n",
" &quot;info&quot;: {}\n",
" },\n",
" &quot;logs&quot;: [\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 2e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 1.5e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 1.6e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 1.3e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ]\n",
" ],\n",
" &quot;mode&quot;: &quot;ipython&quot;\n",
"};\n",
"\n",
"\n",
"window.kaggle.renderer = // Copyright 2020 Kaggle Inc\n",
"//\n",
"// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
"// you may not use this file except in compliance with the License.\n",
"// You may obtain a copy of the License at\n",
"//\n",
"// http://www.apache.org/licenses/LICENSE-2.0\n",
"//\n",
"// Unless required by applicable law or agreed to in writing, software\n",
"// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"// See the License for the specific language governing permissions and\n",
"// limitations under the License.\n",
"\n",
"async function renderer(context) {\n",
" const {\n",
" act,\n",
" agents,\n",
" environment,\n",
" frame,\n",
" height = 400,\n",
" interactive,\n",
" isInteractive,\n",
" parent,\n",
" step,\n",
" update,\n",
" width = 400,\n",
" } = context;\n",
"\n",
" // Common Dimensions.\n",
" const canvasSize = Math.min(height, width);\n",
" const unit = 8;\n",
" const offset = canvasSize > 400 ? canvasSize * 0.1 : unit / 2;\n",
" const cellSize = (canvasSize - offset * 2) / 3;\n",
"\n",
" // Canvas Setup.\n",
" let canvas = parent.querySelector(&quot;canvas&quot;);\n",
" if (!canvas) {\n",
" canvas = document.createElement(&quot;canvas&quot;);\n",
" parent.appendChild(canvas);\n",
"\n",
" if (interactive) {\n",
" canvas.addEventListener(&quot;click&quot;, evt => {\n",
" if (!isInteractive()) return;\n",
" const rect = evt.target.getBoundingClientRect();\n",
" const x = evt.clientX - rect.left - offset;\n",
" const y = evt.clientY - rect.top - offset;\n",
" act(Math.floor(x / cellSize) + Math.floor(y / cellSize) * 3);\n",
" });\n",
" }\n",
" }\n",
" canvas.style.cursor = isInteractive() ? &quot;pointer&quot; : &quot;default&quot;;\n",
"\n",
" // Canvas setup and reset.\n",
" let c = canvas.getContext(&quot;2d&quot;);\n",
" canvas.width = canvasSize;\n",
" canvas.height = canvasSize;\n",
" c.clearRect(0, 0, canvas.width, canvas.height);\n",
"\n",
" const drawStyle = ({\n",
" lineWidth = 1,\n",
" lineCap,\n",
" strokeStyle = &quot;#FFF&quot;,\n",
" shadow,\n",
" }) => {\n",
" c.lineWidth = lineWidth;\n",
" c.strokeStyle = strokeStyle;\n",
" if (lineCap) c.lineCap = lineCap;\n",
" if (shadow) {\n",
" c.shadowOffsetX = shadow.offsetX || 0;\n",
" c.shadowOffsetY = shadow.offsetY || 0;\n",
" c.shadowColor = shadow.color || strokeStyle;\n",
" c.shadowBlur = shadow.blur || 0;\n",
" }\n",
" };\n",
"\n",
" const drawLine = ({ x1, y1, x2, y2, style }) => {\n",
" c.beginPath();\n",
" drawStyle(style || {});\n",
" c.moveTo((x1 || 0) + offset, (y1 || 0) + offset);\n",
" c.lineTo((x2 || x1) + offset, (y2 || y1) + offset);\n",
" c.stroke();\n",
" };\n",
"\n",
" const drawArc = ({ x, y, radius, sAngle, eAngle, style }) => {\n",
" drawStyle(style || {});\n",
" c.beginPath();\n",
" c.arc(x, y, radius, sAngle, eAngle);\n",
" c.stroke();\n",
" };\n",
"\n",
" // Draw the Grid.\n",
" const gridFrame = step === 0 ? frame : 1;\n",
" const drawGridLine = ({\n",
" x1s = 0,\n",
" y1s = 0,\n",
" x2s,\n",
" y2s,\n",
" x1o = 0,\n",
" x2o = 0,\n",
" y1o = 0,\n",
" y2o = 0,\n",
" }) =>\n",
" drawLine({\n",
" x1: x1s * cellSize + x1o * unit,\n",
" x2: (x2s || x1s) * cellSize + x2o * unit,\n",
" y1: y1s * cellSize + y1o * unit,\n",
" y2: (y2s || y1s) * cellSize + y2o * unit,\n",
" style: { strokeStyle: &quot;#046BBF&quot; },\n",
" });\n",
"\n",
" // Vertical.\n",
" drawGridLine({ x1s: 1, y1s: 0, y2s: gridFrame, y2o: -1 });\n",
" drawGridLine({ x1s: 2, y1s: 0, y2s: gridFrame, y2o: -1 });\n",
" drawGridLine({ x1s: 1, y1s: 1, y2s: 1 + gridFrame, y1o: 1, y2o: -1 });\n",
" drawGridLine({ x1s: 2, y1s: 1, y2s: 1 + gridFrame, y1o: 1, y2o: -1 });\n",
" drawGridLine({ x1s: 1, y1s: 2, y2s: 2 + gridFrame, y1o: 1 });\n",
" drawGridLine({ x1s: 2, y1s: 2, y2s: 2 + gridFrame, y1o: 1 });\n",
"\n",
" // Horizontal.\n",
" drawGridLine({ x1s: 0, y1s: 1, x2s: gridFrame, x2o: -1 });\n",
" drawGridLine({ x1s: 1, y1s: 1, x2s: 1 + gridFrame, x1o: 1, x2o: -1 });\n",
" drawGridLine({ x1s: 2, y1s: 1, x2s: 2 + gridFrame, x1o: 1 });\n",
" drawGridLine({ x1s: 0, y1s: 2, x2s: gridFrame, x2o: -1 });\n",
" drawGridLine({ x1s: 1, y1s: 2, x2s: 1 + gridFrame, x1o: 1, x2o: -1 });\n",
" drawGridLine({ x1s: 2, y1s: 2, x2s: 2 + gridFrame, x1o: 1 });\n",
"\n",
" // Draw the Pieces.\n",
" const drawX = (cell, cellFrame) => {\n",
" const part = cellSize / 4;\n",
" const gap = Math.min(Math.sqrt((unit * unit) / 2), canvasSize / 50);\n",
" const row = Math.floor(cell / 3);\n",
" const col = cell % 3;\n",
"\n",
" const drawXLine = ({ x1, y1, x2, y2 }) =>\n",
" drawLine({\n",
" x1: col * cellSize + x1,\n",
" y1: row * cellSize + y1,\n",
" x2: col * cellSize + x2,\n",
" y2: row * cellSize + y2,\n",
" style: {\n",
" strokeStyle: &quot;#00FFFF&quot;,\n",
" lineWidth: 2,\n",
" lineCap: &quot;round&quot;,\n",
" shadow: { blur: 8 },\n",
" },\n",
" });\n",
"\n",
" drawXLine({\n",
" x1: part,\n",
" y1: part,\n",
" x2: part + part * 2 * cellFrame,\n",
" y2: part + part * 2 * cellFrame,\n",
" });\n",
" if (Math.round(cellFrame) === 1) {\n",
" drawXLine({\n",
" x1: part,\n",
" y1: part * 3,\n",
" x2: part * 2 - gap,\n",
" y2: part * 2 + gap,\n",
" });\n",
" drawXLine({\n",
" x1: part * 2 + gap,\n",
" y1: part * 2 - gap,\n",
" x2: part * 3,\n",
" y2: part,\n",
" });\n",
" }\n",
" };\n",
" const drawO = (cell, cellFrame) => {\n",
" const row = Math.floor(cell / 3);\n",
" const col = cell % 3;\n",
" const radius = cellSize / 4 + 1; // +1 is for optical illusion.\n",
" const gap =\n",
" (Math.acos((2 * (radius ^ 2) - (unit ^ 2)) / (2 * radius * radius)) /\n",
" 180) *\n",
" Math.PI *\n",
" unit;\n",
" const x = cellSize * col + cellSize / 2 + offset;\n",
" const y = cellSize * row + cellSize / 2 + offset;\n",
"\n",
" const drawOArc = (sAngle, eAngle) =>\n",
" drawArc({\n",
" x,\n",
" y,\n",
" radius,\n",
" sAngle,\n",
" eAngle,\n",
" style: {\n",
" lineWidth: 2,\n",
" strokeStyle: &quot;#FFF&quot;,\n",
" shadow: { blur: 8 },\n",
" },\n",
" });\n",
"\n",
" drawOArc(\n",
" -Math.PI / 2 + gap,\n",
" -Math.PI / 2 + gap + (Math.PI - gap * 2) * cellFrame\n",
" );\n",
" drawOArc(\n",
" Math.PI / 2 + gap,\n",
" Math.PI / 2 + gap + (Math.PI - gap * 2) * cellFrame\n",
" );\n",
" };\n",
"\n",
" const board = environment.steps[step][0].observation.board;\n",
"\n",
" board.forEach((value, cell) => {\n",
" const cellFrame =\n",
" step <= 1 ||\n",
" environment.steps[step - 1][0].observation.board[cell] !== value\n",
" ? frame\n",
" : 1;\n",
" if (value === 1) drawX(cell, cellFrame);\n",
" if (value === 2) drawO(cell, cellFrame);\n",
" });\n",
"\n",
" // Draw the winning line.\n",
" // [cell1, cell2, cell3, x1, y1, x2, y2]\n",
" const checks = [\n",
" [0, 1, 2, 1 / 19, 1 / 6, 18 / 19, 1 / 6],\n",
" [3, 4, 5, 1 / 19, 1 / 2, 18 / 19, 1 / 2],\n",
" [6, 7, 8, 1 / 19, 5 / 6, 18 / 19, 5 / 6],\n",
" [0, 3, 6, 1 / 6, 1 / 19, 1 / 6, 18 / 19],\n",
" [1, 4, 7, 1 / 2, 1 / 19, 1 / 2, 18 / 19],\n",
" [2, 5, 8, 5 / 6, 1 / 19, 5 / 6, 18 / 19],\n",
" [0, 4, 8, 1 / 19, 1 / 19, 18 / 19, 18 / 19],\n",
" [2, 4, 6, 18 / 19, 1 / 19, 1 / 19, 18 / 19],\n",
" ];\n",
" for (const check of checks) {\n",
" if (\n",
" board[check[0]] !== 0 &&\n",
" board[check[0]] === board[check[1]] &&\n",
" board[check[0]] === board[check[2]]\n",
" ) {\n",
" const x1 = check[3] * (cellSize * 3);\n",
" const y1 = check[4] * (cellSize * 3);\n",
" const winFrame = frame < 0.5 ? 0 : (frame - 0.5) / 0.5;\n",
" if (winFrame > 0) {\n",
" drawLine({\n",
" x1,\n",
" y1,\n",
" x2: x1 + (check[5] * (cellSize * 3) - x1) * winFrame,\n",
" y2: y1 + (check[6] * (cellSize * 3) - y1) * winFrame,\n",
" style: {\n",
" strokeStyle: &quot;#FFF&quot;,\n",
" lineWidth: 3 * winFrame,\n",
" shadow: { blur: 8 * winFrame },\n",
" },\n",
" });\n",
" }\n",
" break;\n",
" }\n",
" }\n",
"\n",
" // Upgrade the legend.\n",
" if (agents.length && (!agents[0].color || !agents[0].image)) {\n",
" const getPieceImage = drawFn => {\n",
" const pieceCanvas = document.createElement(&quot;canvas&quot;);\n",
" parent.appendChild(pieceCanvas);\n",
" pieceCanvas.style.marginLeft = &quot;10000px&quot;;\n",
" pieceCanvas.width = cellSize + offset * 2;\n",
" pieceCanvas.height = cellSize + offset * 2;\n",
" c = pieceCanvas.getContext(&quot;2d&quot;);\n",
" drawFn(0, 1);\n",
" const dataUrl = pieceCanvas.toDataURL();\n",
" parent.removeChild(pieceCanvas);\n",
" return dataUrl;\n",
" };\n",
"\n",
" agents.forEach(agent => {\n",
" agent.color = agent.index === 0 ? &quot;#0FF&quot; : &quot;#FFF&quot;;\n",
" agent.image = getPieceImage(agent.index === 0 ? drawX : drawO);\n",
" });\n",
" update({ agents });\n",
" }\n",
"};\n",
"\n",
"\n",
" \n",
" </script>\n",
" <script>\n",
" const h = htm.bind(preact.h);\n",
" const { useContext, useEffect, useRef, useState } = preactHooks;\n",
" const styled = window.styled.default;\n",
"\n",
" const Context = preact.createContext({});\n",
"\n",
" const Loading = styled.div`\n",
" animation: rotate360 1.1s infinite linear;\n",
" border: 8px solid rgba(255, 255, 255, 0.2);\n",
" border-left-color: #0cb1ed;\n",
" border-radius: 50%;\n",
" height: 40px;\n",
" position: relative;\n",
" transform: translateZ(0);\n",
" width: 40px;\n",
"\n",
" @keyframes rotate360 {\n",
" 0% {\n",
" transform: rotate(0deg);\n",
" }\n",
" 100% {\n",
" transform: rotate(360deg);\n",
" }\n",
" }\n",
" `;\n",
"\n",
" const Logo = styled(\n",
" (props) => h`\n",
" <a href=&quot;https://kaggle.com&quot; target=&quot;_blank&quot; className=${props.className}>\n",
" <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",
" <g fill=&quot;#1EBEFF&quot; fill-rule=&quot;nonzero&quot;>\n",
" <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",
" <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",
" <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",
" <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",
" <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",
" <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",
" </g>\n",
" </svg>\n",
" </a>\n",
" `\n",
" )`\n",
" display: inline-flex;\n",
" `;\n",
"\n",
" const Header = styled((props) => {\n",
" const { environment } = useContext(Context);\n",
"\n",
" return h`<div className=${props.className} >\n",
" <${Logo} />\n",
" <span><b>Left / Right Arrow:</b> Increase / Decrease Step</span><span><b>0-9 Row Keys:</b> Playback Speed</span><span><b>Space:</b> Pause / Play</span>\n",
" ${environment.title}\n",
" </div>`;\n",
" })`\n",
" align-items: center;\n",
" border-bottom: 4px solid #212121;\n",
" box-sizing: border-box;\n",
" color: #fff;\n",
" display: flex;\n",
" flex: 0 0 36px;\n",
" font-size: 14px;\n",
" justify-content: space-between;\n",
" padding: 0 8px;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Renderer = styled((props) => {\n",
" const context = useContext(Context);\n",
" const { animate, debug, playing, renderer, speed } = context;\n",
" const ref = preact.createRef();\n",
"\n",
" useEffect(async () => {\n",
" if (!ref.current) return;\n",
"\n",
" const renderFrame = async (start, step, lastFrame) => {\n",
" if (step !== context.step) return;\n",
" if (lastFrame === 1) {\n",
" if (!animate) return;\n",
" start = Date.now();\n",
" }\n",
" const frame =\n",
" playing || animate\n",
" ? Math.min((Date.now() - start) / speed, 1)\n",
" : 1;\n",
" try {\n",
" if (debug) console.time(&quot;render&quot;);\n",
" await renderer({\n",
" ...context,\n",
" frame,\n",
" height: ref.current.clientHeight,\n",
" hooks: preactHooks,\n",
" parent: ref.current,\n",
" preact,\n",
" styled,\n",
" width: ref.current.clientWidth,\n",
" });\n",
" } catch (error) {\n",
" if (debug) console.error(error);\n",
" console.log({ ...context, frame, error });\n",
" } finally {\n",
" if (debug) console.timeEnd(&quot;render&quot;);\n",
" }\n",
" window.requestAnimationFrame(() => renderFrame(start, step, frame));\n",
" };\n",
"\n",
" await renderFrame(Date.now(), context.step);\n",
" }, [ref.current, context.step, context.renderer]);\n",
"\n",
" return h`<div className=${props.className} ref=${ref} />`;\n",
" })`\n",
" align-items: center;\n",
" box-sizing: border-box;\n",
" display: flex;\n",
" height: 100%;\n",
" left: 0;\n",
" justify-content: center;\n",
" position: absolute;\n",
" top: 0;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Processing = styled((props) => {\n",
" const { processing } = useContext(Context);\n",
" const text = processing === true ? &quot;Processing...&quot; : processing;\n",
" return h`<div className=${props.className}>${text}</div>`;\n",
" })`\n",
" bottom: 0;\n",
" color: #fff;\n",
" font-size: 12px;\n",
" left: 0;\n",
" line-height: 24px;\n",
" position: absolute;\n",
" text-align: center;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Viewer = styled((props) => {\n",
" const { processing } = useContext(Context);\n",
" return h`<div className=${props.className}>\n",
" <${Renderer} />\n",
" ${processing && h`<${Processing} />`}\n",
" </div>`;\n",
" })`\n",
" background-color: #000b2a;\n",
" background-image: radial-gradient(\n",
" circle closest-side,\n",
" #000b49,\n",
" #000b2a\n",
" );\n",
" display: flex;\n",
" flex: 1;\n",
" overflow: hidden;\n",
" position: relative;\n",
" width: 100%;\n",
" `;\n",
"\n",
" // Partitions the elements of arr into subarrays of max length num.\n",
" const groupIntoSets = (arr, num) => {\n",
" const sets = [];\n",
" arr.forEach(a => {\n",
" if (sets.length === 0 || sets[sets.length - 1].length === num) {\n",
" sets.push([]);\n",
" }\n",
" sets[sets.length - 1].push(a);\n",
" });\n",
" return sets;\n",
" }\n",
"\n",
" // Expects `width` input prop to set proper max-width for agent name span.\n",
" const Legend = styled((props) => {\n",
" const { agents, legend } = useContext(Context);\n",
"\n",
" const agentPairs = groupIntoSets(agents.sort((a, b) => a.index - b.index), 2);\n",
"\n",
" return h`<div className=${props.className}>\n",
" ${agentPairs.map(agentList =>\n",
" h`<ul>\n",
" ${agentList.map(a =>\n",
" h`<li key=${a.id} title=&quot;id: ${a.id}&quot; style=&quot;color:${a.color || &quot;#FFF&quot;}&quot;>\n",
" ${a.image && h`<img src=${a.image} />`}\n",
" <span>${a.name}</span>\n",
" </li>`\n",
" )}\n",
" </ul>`)}\n",
" </div>`;\n",
" })`\n",
" background-color: #000b2a;\n",
" font-family: sans-serif;\n",
" font-size: 14px;\n",
" width: 100%;\n",
"\n",
" ul {\n",
" align-items: center;\n",
" display: flex;\n",
" flex-direction: row;\n",
" justify-content: center;\n",
" }\n",
"\n",
" li {\n",
" align-items: center;\n",
" display: inline-flex;\n",
" transition: color 1s;\n",
" }\n",
"\n",
" span {\n",
" max-width: ${p => (p.width || 400) * 0.5 - 36}px;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" white-space: nowrap;\n",
" }\n",
"\n",
" img {\n",
" height: 24px;\n",
" margin-left: 4px;\n",
" margin-right: 4px;\n",
" width: 24px;\n",
" }\n",
" `;\n",
"\n",
" const StepInput = styled.input.attrs({\n",
" type: &quot;range&quot;,\n",
" })`\n",
" appearance: none;\n",
" background: rgba(255, 255, 255, 0.15);\n",
" border-radius: 2px;\n",
" display: block;\n",
" flex: 1;\n",
" height: 4px;\n",
" opacity: 0.8;\n",
" outline: none;\n",
" transition: opacity 0.2s;\n",
" width: 100%;\n",
"\n",
" &:hover {\n",
" opacity: 1;\n",
" }\n",
"\n",
" &::-webkit-slider-thumb {\n",
" appearance: none;\n",
" background: #1ebeff;\n",
" border-radius: 100%;\n",
" cursor: pointer;\n",
" height: 12px;\n",
" margin: 0;\n",
" position: relative;\n",
" width: 12px;\n",
"\n",
" &::after {\n",
" content: &quot;&quot;;\n",
" position: absolute;\n",
" top: 0px;\n",
" left: 0px;\n",
" width: 200px;\n",
" height: 8px;\n",
" background: green;\n",
" }\n",
" }\n",
" `;\n",
"\n",
" const PlayButton = styled.button`\n",
" align-items: center;\n",
" background: none;\n",
" border: none;\n",
" color: white;\n",
" cursor: pointer;\n",
" display: flex;\n",
" flex: 0 0 56px;\n",
" font-size: 20px;\n",
" height: 40px;\n",
" justify-content: center;\n",
" opacity: 0.8;\n",
" outline: none;\n",
" transition: opacity 0.2s;\n",
"\n",
" &:hover {\n",
" opacity: 1;\n",
" }\n",
" `;\n",
"\n",
" const StepCount = styled.span`\n",
" align-items: center;\n",
" color: white;\n",
" display: flex;\n",
" font-size: 14px;\n",
" justify-content: center;\n",
" opacity: 0.8;\n",
" padding: 0 16px;\n",
" pointer-events: none;\n",
" `;\n",
"\n",
" const Controls = styled((props) => {\n",
" const { environment, pause, play, playing, setStep, step } = useContext(\n",
" Context\n",
" );\n",
" const value = step + 1;\n",
" const onClick = () => (playing ? pause() : play());\n",
" const onInput = (e) => {\n",
" pause();\n",
" setStep(parseInt(e.target.value) - 1);\n",
" };\n",
"\n",
" return h`\n",
" <div className=${props.className}>\n",
" <${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",
" playing\n",
" ? h`<path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
" : h`<path d=&quot;M8 5v14l11-7z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
" }</svg><//>\n",
" <${StepInput} min=&quot;1&quot; max=${\n",
" environment.steps.length\n",
" } value=&quot;${value}&quot; onInput=${onInput} />\n",
" <${StepCount}>${value} / ${environment.steps.length}<//>\n",
" </div>\n",
" `;\n",
" })`\n",
" align-items: center;\n",
" border-top: 4px solid #212121;\n",
" display: flex;\n",
" flex: 0 0 44px;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Info = styled((props) => {\n",
" const {\n",
" environment,\n",
" playing,\n",
" step,\n",
" speed,\n",
" animate,\n",
" header,\n",
" controls,\n",
" settings,\n",
" } = useContext(Context);\n",
"\n",
" return h`\n",
" <div className=${props.className}>\n",
" info:\n",
" step(${step}),\n",
" playing(${playing ? &quot;T&quot; : &quot;F&quot;}),\n",
" speed(${speed}),\n",
" animate(${animate ? &quot;T&quot; : &quot;F&quot;})\n",
" </div>`;\n",
" })`\n",
" color: #888;\n",
" font-family: monospace;\n",
" font-size: 12px;\n",
" `;\n",
"\n",
" const Settings = styled((props) => {\n",
" const { environment, pause, play, playing, setStep, step } = useContext(\n",
" Context\n",
" );\n",
"\n",
" return h`\n",
" <div className=${props.className}>\n",
" <${Info} />\n",
" </div>\n",
" `;\n",
" })`\n",
" background: #fff;\n",
" border-top: 4px solid #212121;\n",
" box-sizing: border-box;\n",
" padding: 20px;\n",
" width: 100%;\n",
"\n",
" h1 {\n",
" font-size: 20px;\n",
" }\n",
" `;\n",
"\n",
" const Player = styled((props) => {\n",
" const context = useContext(Context);\n",
" const { agents, controls, header, legend, loading, settings, width } = context;\n",
" return h`\n",
" <div className=${props.className}>\n",
" ${loading && h`<${Loading} />`}\n",
" ${!loading && header && h`<${Header} />`}\n",
" ${!loading && h`<${Viewer} />`}\n",
" ${!loading && agents.length > 0 && legend && h`<${Legend} width=${width}/>`}\n",
" ${!loading && controls && h`<${Controls} />`}\n",
" ${!loading && settings && h`<${Settings} />`}\n",
" </div>`;\n",
" })`\n",
" align-items: center;\n",
" background: #212121;\n",
" border: 4px solid #212121;\n",
" box-sizing: border-box;\n",
" display: flex;\n",
" flex-direction: column;\n",
" height: 100%;\n",
" justify-content: center;\n",
" position: relative;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const App = () => {\n",
" const renderCountRef = useRef(0);\n",
" const [_, setRenderCount] = useState(0);\n",
"\n",
" // These are bindings to the 0-9 keys and are milliseconds of timeout per step\n",
" const speeds = [\n",
" 0,\n",
" 3000,\n",
" 1000,\n",
" 500,\n",
" 333, // Default\n",
" 200,\n",
" 100,\n",
" 50,\n",
" 25,\n",
" 10,\n",
" ];\n",
"\n",
" const contextRef = useRef({\n",
" animate: false,\n",
" agents: [],\n",
" autoplay: false,\n",
" controls: false,\n",
" debug: false,\n",
" environment: { steps: [], info: {} },\n",
" header: window.innerHeight >= 600,\n",
" height: window.innerHeight,\n",
" interactive: false,\n",
" legend: true,\n",
" loading: false,\n",
" playing: false,\n",
" processing: false,\n",
" renderer: () => &quot;DNE&quot;,\n",
" settings: false,\n",
" speed: speeds[4],\n",
" step: 0,\n",
" width: window.innerWidth,\n",
" });\n",
"\n",
" // Context helpers.\n",
" const rerender = (contextRef.current.rerender = () =>\n",
" setRenderCount((renderCountRef.current += 1)));\n",
" const setStep = (contextRef.current.setStep = (newStep) => {\n",
" contextRef.current.step = newStep;\n",
" rerender();\n",
" });\n",
" const setPlaying = (contextRef.current.setPlaying = (playing) => {\n",
" contextRef.current.playing = playing;\n",
" rerender();\n",
" });\n",
" const pause = (contextRef.current.pause = () => setPlaying(false));\n",
"\n",
" const playNext = () => {\n",
" const context = contextRef.current;\n",
"\n",
" if (\n",
" context.playing &&\n",
" context.step < context.environment.steps.length - 1\n",
" ) {\n",
" setStep(context.step + 1);\n",
" play(true);\n",
" } else {\n",
" pause();\n",
" }\n",
" };\n",
"\n",
" const play = (contextRef.current.play = (continuing) => {\n",
" const context = contextRef.current;\n",
" if (context.playing && !continuing) return;\n",
" if (!context.playing) setPlaying(true);\n",
" if (\n",
" !continuing &&\n",
" context.step === context.environment.steps.length - 1\n",
" ) {\n",
" setStep(0);\n",
" }\n",
" setTimeout(playNext, context.speed);\n",
" });\n",
"\n",
" const updateContext = (o) => {\n",
" const context = contextRef.current;\n",
" Object.assign(context, o, {\n",
" environment: { ...context.environment, ...(o.environment || {}) },\n",
" });\n",
" rerender();\n",
"\n",
" // If autoplay, toggle to playing.\n",
" if (context.autoplay) play();\n",
" };\n",
"\n",
" // First time setup.\n",
" useEffect(() => {\n",
" // Timeout is used to ensure useEffect renders once.\n",
" setTimeout(() => {\n",
" // Initialize context with window.kaggle.\n",
" updateContext(window.kaggle || {});\n",
" // Listen for messages received to update the context.\n",
" window.addEventListener(\n",
" &quot;message&quot;,\n",
" (event) => {\n",
" // Ensure the environment names match before updating.\n",
" try {\n",
" if (\n",
" event.data.environment.name ==\n",
" contextRef.current.environment.name\n",
" ) {\n",
" updateContext(event.data);\n",
" }\n",
" } catch {}\n",
" },\n",
" false\n",
" );\n",
" // Listen for keyboard commands.\n",
" window.addEventListener(\n",
" &quot;keydown&quot;,\n",
" (event) => {\n",
" const {\n",
" interactive,\n",
" isInteractive,\n",
" playing,\n",
" step,\n",
" environment,\n",
" } = contextRef.current;\n",
" const key = event.keyCode;\n",
" const zero_key = 48\n",
" const nine_key = 57\n",
" if (\n",
" interactive ||\n",
" isInteractive() ||\n",
" (key !== 32 && key !== 37 && key !== 39 && !(key >= zero_key && key <= nine_key))\n",
" )\n",
" return;\n",
"\n",
" if (key === 32) {\n",
" playing ? pause() : play();\n",
" } else if (key === 39) {\n",
" contextRef.current.playing = false;\n",
" if (step < environment.steps.length - 1) setStep(step + 1);\n",
" rerender();\n",
" } else if (key === 37) {\n",
" contextRef.current.playing = false;\n",
" if (step > 0) setStep(step - 1);\n",
" rerender();\n",
" } else if (key >= zero_key && key <= nine_key) {\n",
" contextRef.current.speed = speeds[key - zero_key];\n",
" }\n",
" event.preventDefault();\n",
" return false;\n",
" },\n",
" false\n",
" );\n",
" }, 1);\n",
" }, []);\n",
"\n",
" if (contextRef.current.debug) {\n",
" console.log(&quot;context&quot;, contextRef.current);\n",
" }\n",
"\n",
" // Ability to update context.\n",
" contextRef.current.update = updateContext;\n",
"\n",
" // Ability to communicate with ipython.\n",
" const execute = (contextRef.current.execute = (source) =>\n",
" new Promise((resolve, reject) => {\n",
" try {\n",
" window.parent.IPython.notebook.kernel.execute(source, {\n",
" iopub: {\n",
" output: (resp) => {\n",
" const type = resp.msg_type;\n",
" if (type === &quot;stream&quot;) return resolve(resp.content.text);\n",
" if (type === &quot;error&quot;) return reject(new Error(resp.evalue));\n",
" return reject(new Error(&quot;Unknown message type: &quot; + type));\n",
" },\n",
" },\n",
" });\n",
" } catch (e) {\n",
" reject(new Error(&quot;IPython Unavailable: &quot; + e));\n",
" }\n",
" }));\n",
"\n",
" // Ability to return an action from an interactive session.\n",
" contextRef.current.act = (action) => {\n",
" const id = contextRef.current.environment.id;\n",
" updateContext({ processing: true });\n",
" execute(`\n",
" import json\n",
" from kaggle_environments import interactives\n",
" if &quot;${id}&quot; in interactives:\n",
" action = json.loads('${JSON.stringify(action)}')\n",
" env, trainer = interactives[&quot;${id}&quot;]\n",
" trainer.step(action)\n",
" print(json.dumps(env.steps))`)\n",
" .then((resp) => {\n",
" try {\n",
" updateContext({\n",
" processing: false,\n",
" environment: { steps: JSON.parse(resp) },\n",
" });\n",
" play();\n",
" } catch (e) {\n",
" updateContext({ processing: resp.split(&quot;\\n&quot;)[0] });\n",
" console.error(resp, e);\n",
" }\n",
" })\n",
" .catch((e) => console.error(e));\n",
" };\n",
"\n",
" // Check if currently interactive.\n",
" contextRef.current.isInteractive = () => {\n",
" const context = contextRef.current;\n",
" const steps = context.environment.steps;\n",
" return (\n",
" context.interactive &&\n",
" !context.processing &&\n",
" context.step === steps.length - 1 &&\n",
" steps[context.step].some((s) => s.status === &quot;ACTIVE&quot;)\n",
" );\n",
" };\n",
"\n",
" return h`\n",
" <${Context.Provider} value=${contextRef.current}>\n",
" <${Player} />\n",
" <//>`;\n",
" };\n",
"\n",
" preact.render(h`<${App} />`, document.body);\n",
" </script>\n",
" </body>\n",
"</html>\n",
"\" width=\"300\" height=\"300\" frameborder=\"0\"></iframe> "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from kaggle_environments import make\n",
"\n",
"# Setup a tictactoe environment.\n",
"env = make(\"tictactoe\")\n",
"\n",
"# Basic agent which marks the first available cell.\n",
"def my_agent(obs):\n",
" return [c for c in range(len(obs.board)) if obs.board[c] == 0][0]\n",
"\n",
"# Run the basic agent against a default agent which chooses a \"random\" move.\n",
"env.run([my_agent, \"random\"])\n",
"\n",
"# Render an html ipython replay of the tictactoe game.\n",
"env.render(mode=\"ipython\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<iframe srcdoc=\"<!--\n",
" Copyright 2020 Kaggle Inc\n",
"\n",
" Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
" you may not use this file except in compliance with the License.\n",
" You may obtain a copy of the License at\n",
"\n",
" http://www.apache.org/licenses/LICENSE-2.0\n",
"\n",
" Unless required by applicable law or agreed to in writing, software\n",
" distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
" See the License for the specific language governing permissions and\n",
" limitations under the License.\n",
"-->\n",
"<!DOCTYPE html>\n",
"<html lang=&quot;en&quot;>\n",
" <head>\n",
" <title>Kaggle Simulation Player</title>\n",
" <meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot; />\n",
" <link\n",
" rel=&quot;stylesheet&quot;\n",
" href=&quot;https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css&quot;\n",
" crossorigin=&quot;anonymous&quot;\n",
" />\n",
" <style type=&quot;text/css&quot;>\n",
" html,\n",
" body {\n",
" height: 100%;\n",
" font-family: sans-serif;\n",
" margin: 0px;\n",
" }\n",
" canvas {\n",
" /* image-rendering: -moz-crisp-edges;\n",
" image-rendering: -webkit-crisp-edges;\n",
" image-rendering: pixelated;\n",
" image-rendering: crisp-edges; */\n",
" }\n",
" </style>\n",
" <script src=&quot;https://unpkg.com/preact@10.0.1/dist/preact.umd.js&quot;></script>\n",
" <script src=&quot;https://unpkg.com/preact@10.0.1/hooks/dist/hooks.umd.js&quot;></script>\n",
" <script src=&quot;https://unpkg.com/htm@2.2.1/dist/htm.umd.js&quot;></script>\n",
" <script>\n",
" // Polyfill for Styled Components\n",
" window.React = {\n",
" ...preact,\n",
" createElement: preact.h,\n",
" PropTypes: { func: {} },\n",
" };\n",
" </script>\n",
" <script src=&quot;https://unpkg.com/styled-components@3.5.0-0/dist/styled-components.min.js&quot;></script>\n",
" </head>\n",
" <body>\n",
" <script>\n",
" \n",
"window.kaggle = {\n",
" &quot;debug&quot;: false,\n",
" &quot;autoplay&quot;: true,\n",
" &quot;step&quot;: 0,\n",
" &quot;controls&quot;: true,\n",
" &quot;environment&quot;: {\n",
" &quot;id&quot;: &quot;1e718e24-8055-11eb-8edb-4f088413800f&quot;,\n",
" &quot;name&quot;: &quot;connectx&quot;,\n",
" &quot;title&quot;: &quot;ConnectX&quot;,\n",
" &quot;description&quot;: &quot;Classic Connect in a row but configurable.&quot;,\n",
" &quot;version&quot;: &quot;1.0.1&quot;,\n",
" &quot;configuration&quot;: {\n",
" &quot;episodeSteps&quot;: 1000,\n",
" &quot;actTimeout&quot;: 2,\n",
" &quot;runTimeout&quot;: 1200,\n",
" &quot;columns&quot;: 7,\n",
" &quot;rows&quot;: 6,\n",
" &quot;inarow&quot;: 4,\n",
" &quot;agentTimeout&quot;: 60,\n",
" &quot;timeout&quot;: 2\n",
" },\n",
" &quot;specification&quot;: {\n",
" &quot;action&quot;: {\n",
" &quot;description&quot;: &quot;Column to drop a checker onto the board.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 0\n",
" },\n",
" &quot;agents&quot;: [\n",
" 2\n",
" ],\n",
" &quot;configuration&quot;: {\n",
" &quot;episodeSteps&quot;: {\n",
" &quot;description&quot;: &quot;Maximum number of steps in the episode.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;minimum&quot;: 1,\n",
" &quot;default&quot;: 1000\n",
" },\n",
" &quot;actTimeout&quot;: {\n",
" &quot;description&quot;: &quot;Maximum runtime (seconds) to obtain an action from an agent.&quot;,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 2\n",
" },\n",
" &quot;runTimeout&quot;: {\n",
" &quot;description&quot;: &quot;Maximum runtime (seconds) of an episode (not necessarily DONE).&quot;,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 1200\n",
" },\n",
" &quot;columns&quot;: {\n",
" &quot;description&quot;: &quot;The number of columns on the board&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;default&quot;: 7,\n",
" &quot;minimum&quot;: 1\n",
" },\n",
" &quot;rows&quot;: {\n",
" &quot;description&quot;: &quot;The number of rows on the board&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;default&quot;: 6,\n",
" &quot;minimum&quot;: 1\n",
" },\n",
" &quot;inarow&quot;: {\n",
" &quot;description&quot;: &quot;The number of checkers in a row required to win.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;default&quot;: 4,\n",
" &quot;minimum&quot;: 1\n",
" },\n",
" &quot;agentTimeout&quot;: {\n",
" &quot;description&quot;: &quot;Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.&quot;,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 60\n",
" },\n",
" &quot;timeout&quot;: {\n",
" &quot;description&quot;: &quot;Obsolete copy of actTimeout maintained for backwards compatibility. May be removed in the future.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;default&quot;: 2,\n",
" &quot;minimum&quot;: 0\n",
" }\n",
" },\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: {\n",
" &quot;description&quot;: &quot;Total remaining banked time (seconds) that can be used in excess of per-step actTimeouts -- agent is disqualified with TIMEOUT status when this drops below 0.&quot;,\n",
" &quot;shared&quot;: false,\n",
" &quot;type&quot;: &quot;number&quot;,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 60\n",
" },\n",
" &quot;step&quot;: {\n",
" &quot;description&quot;: &quot;Current step within the episode.&quot;,\n",
" &quot;type&quot;: &quot;integer&quot;,\n",
" &quot;shared&quot;: true,\n",
" &quot;minimum&quot;: 0,\n",
" &quot;default&quot;: 0\n",
" },\n",
" &quot;board&quot;: {\n",
" &quot;description&quot;: &quot;Serialized grid (rows x columns). 0 = Empty, 1 = P1, 2 = P2&quot;,\n",
" &quot;type&quot;: &quot;array&quot;,\n",
" &quot;shared&quot;: true,\n",
" &quot;default&quot;: []\n",
" },\n",
" &quot;mark&quot;: {\n",
" &quot;defaults&quot;: [\n",
" 1,\n",
" 2\n",
" ],\n",
" &quot;description&quot;: &quot;Which checkers are the agents.&quot;,\n",
" &quot;enum&quot;: [\n",
" 1,\n",
" 2\n",
" ]\n",
" }\n",
" },\n",
" &quot;reward&quot;: {\n",
" &quot;description&quot;: &quot;-1 = Lost, 0 = Draw/Ongoing, 1 = Won&quot;,\n",
" &quot;enum&quot;: [\n",
" -1,\n",
" 0,\n",
" 1\n",
" ],\n",
" &quot;default&quot;: 0,\n",
" &quot;type&quot;: [\n",
" &quot;number&quot;,\n",
" &quot;null&quot;\n",
" ]\n",
" }\n",
" },\n",
" &quot;steps&quot;: [\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 0,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 1,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 2,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 3,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 4,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 5,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 5,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 6,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 2,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 4,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 7,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 2,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 8,\n",
" &quot;board&quot;: [\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 2,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;ACTIVE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 4,\n",
" &quot;reward&quot;: 0,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;INACTIVE&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: 1,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;step&quot;: 9,\n",
" &quot;board&quot;: [\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 0,\n",
" 0,\n",
" 1,\n",
" 0,\n",
" 0,\n",
" 0,\n",
" 2,\n",
" 2,\n",
" 0\n",
" ],\n",
" &quot;mark&quot;: 1\n",
" },\n",
" &quot;status&quot;: &quot;DONE&quot;\n",
" },\n",
" {\n",
" &quot;action&quot;: 0,\n",
" &quot;reward&quot;: -1,\n",
" &quot;info&quot;: {},\n",
" &quot;observation&quot;: {\n",
" &quot;remainingOverageTime&quot;: 60,\n",
" &quot;mark&quot;: 2\n",
" },\n",
" &quot;status&quot;: &quot;DONE&quot;\n",
" }\n",
" ]\n",
" ],\n",
" &quot;rewards&quot;: [\n",
" 1,\n",
" -1\n",
" ],\n",
" &quot;statuses&quot;: [\n",
" &quot;DONE&quot;,\n",
" &quot;DONE&quot;\n",
" ],\n",
" &quot;schema_version&quot;: 1,\n",
" &quot;info&quot;: {}\n",
" },\n",
" &quot;logs&quot;: [\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 2e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 1.5e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 1.6e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 1.3e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 8e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 4e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 1.5e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 1.2e-05,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [],\n",
" [],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 9e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 7e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ],\n",
" [\n",
" {},\n",
" {\n",
" &quot;duration&quot;: 5e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" }\n",
" ],\n",
" [\n",
" {\n",
" &quot;duration&quot;: 6e-06,\n",
" &quot;stdout&quot;: &quot;&quot;,\n",
" &quot;stderr&quot;: &quot;&quot;\n",
" },\n",
" {}\n",
" ]\n",
" ],\n",
" &quot;mode&quot;: &quot;ipython&quot;\n",
"};\n",
"\n",
"\n",
"window.kaggle.renderer = // Copyright 2020 Kaggle Inc\n",
"//\n",
"// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
"// you may not use this file except in compliance with the License.\n",
"// You may obtain a copy of the License at\n",
"//\n",
"// http://www.apache.org/licenses/LICENSE-2.0\n",
"//\n",
"// Unless required by applicable law or agreed to in writing, software\n",
"// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"// See the License for the specific language governing permissions and\n",
"// limitations under the License.\n",
"\n",
"function renderer({\n",
" act,\n",
" agents,\n",
" environment,\n",
" frame,\n",
" height = 400,\n",
" interactive,\n",
" isInteractive,\n",
" parent,\n",
" step,\n",
" update,\n",
" width = 400,\n",
"}) {\n",
" // Configuration.\n",
" const { rows, columns, inarow } = environment.configuration;\n",
"\n",
" // Common Dimensions.\n",
" const unit = 8;\n",
" const minCanvasSize = Math.min(height, width);\n",
" const minOffset = minCanvasSize > 400 ? 30 : unit / 2;\n",
" const cellSize = Math.min(\n",
" (width - minOffset * 2) / columns,\n",
" (height - minOffset * 2) / rows\n",
" );\n",
" const cellInset = 0.8;\n",
" const pieceScale = cellSize / 100;\n",
" const xOffset = Math.max(0, (width - cellSize * columns) / 2);\n",
" const yOffset = Math.max(0, (height - cellSize * rows) / 2);\n",
"\n",
" // Canvas Setup.\n",
" let canvas = parent.querySelector(&quot;canvas&quot;);\n",
" if (!canvas) {\n",
" canvas = document.createElement(&quot;canvas&quot;);\n",
" parent.appendChild(canvas);\n",
"\n",
" if (interactive) {\n",
" canvas.addEventListener(&quot;click&quot;, evt => {\n",
" if (!isInteractive()) return;\n",
" const rect = evt.target.getBoundingClientRect();\n",
" const col = Math.floor((evt.clientX - rect.left - xOffset) / cellSize);\n",
" if (col >= 0 && col < columns) act(col);\n",
" });\n",
" }\n",
" }\n",
" canvas.style.cursor = isInteractive() ? &quot;pointer&quot; : &quot;default&quot;;\n",
"\n",
" // Character Paths (based on 100x100 tiles).\n",
" const kPath = new Path2D(\n",
" `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",
" );\n",
" const goose1Path = new Path2D(\n",
" `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",
" );\n",
" const goose2Path = new Path2D(\n",
" `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",
" );\n",
" const goose3Path = new Path2D(\n",
" `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",
" );\n",
"\n",
" // Canvas setup and reset.\n",
" let c = canvas.getContext(&quot;2d&quot;);\n",
" canvas.width = width;\n",
" canvas.height = height;\n",
" c.fillStyle = &quot;#000B2A&quot;;\n",
" c.fillRect(0, 0, canvas.width, canvas.height);\n",
"\n",
" const getRowCol = cell => [Math.floor(cell / columns), cell % columns];\n",
"\n",
" const getColor = (mark, opacity = 1) => {\n",
" if (mark === 1) return `rgba(0,255,255,${opacity})`;\n",
" if (mark === 2) return `rgba(255,255,255,${opacity})`;\n",
" return &quot;#fff&quot;;\n",
" };\n",
"\n",
" const drawCellCircle = (cell, xFrame = 1, yFrame = 1, radiusOffset = 0) => {\n",
" const [row, col] = getRowCol(cell);\n",
" c.arc(\n",
" xOffset + xFrame * (col * cellSize + cellSize / 2),\n",
" yOffset + yFrame * (row * cellSize + cellSize / 2),\n",
" (cellInset * cellSize) / 2 - radiusOffset,\n",
" 2 * Math.PI,\n",
" false\n",
" );\n",
" };\n",
"\n",
" // Render the pieces.\n",
" const board = environment.steps[step][0].observation.board;\n",
"\n",
" const drawPiece = mark => {\n",
" // Base Styles.\n",
" const opacity = minCanvasSize < 300 ? 0.6 - minCanvasSize / 1000 : 0.1;\n",
" c.fillStyle = getColor(mark, opacity);\n",
" c.strokeStyle = getColor(mark);\n",
" c.shadowColor = getColor(mark);\n",
" c.shadowBlur = 8 / cellInset;\n",
" c.lineWidth = 1 / cellInset;\n",
"\n",
" // Outer circle.\n",
" c.save();\n",
" c.beginPath();\n",
" c.arc(50, 50, 50, 2 * Math.PI, false);\n",
" c.closePath();\n",
" c.lineWidth *= 4;\n",
" c.stroke();\n",
" c.fill();\n",
" c.restore();\n",
"\n",
" // Inner circle.\n",
" c.beginPath();\n",
" c.arc(50, 50, 40, 2 * Math.PI, false);\n",
" c.closePath();\n",
" c.stroke();\n",
"\n",
" // Kaggle &quot;K&quot;.\n",
" if (mark === 1) {\n",
" const scale = 0.54;\n",
" c.save();\n",
" c.translate(23, 23);\n",
" c.scale(scale, scale);\n",
" c.lineWidth /= scale;\n",
" c.shadowBlur /= scale;\n",
" c.stroke(kPath);\n",
" c.restore();\n",
" }\n",
"\n",
" // Kaggle &quot;Goose&quot;.\n",
" if (mark === 2) {\n",
" const scale = 0.6;\n",
" c.save();\n",
" c.translate(24, 28);\n",
" c.scale(scale, scale);\n",
" c.lineWidth /= scale;\n",
" c.shadowBlur /= scale;\n",
" c.stroke(goose1Path);\n",
" c.stroke(goose2Path);\n",
" c.stroke(goose3Path);\n",
" c.beginPath();\n",
" c.arc(38.5, 18.6, 2.7, 0, Math.PI * 2, false);\n",
" c.closePath();\n",
" c.fill();\n",
" c.restore();\n",
" }\n",
" };\n",
"\n",
" for (let i = 0; i < board.length; i++) {\n",
" const [row, col] = getRowCol(i);\n",
" if (board[i] === 0) continue;\n",
" // Easing In.\n",
" let yFrame = Math.min(\n",
" (columns * Math.pow(frame, 3)) / Math.floor(i / columns),\n",
" 1\n",
" );\n",
"\n",
" if (\n",
" step > 1 &&\n",
" environment.steps[step - 1][0].observation.board[i] === board[i]\n",
" ) {\n",
" yFrame = 1;\n",
" }\n",
"\n",
" c.save();\n",
" c.translate(\n",
" xOffset + cellSize * col + (cellSize - cellSize * cellInset) / 2,\n",
" yOffset +\n",
" yFrame * (cellSize * row) +\n",
" (cellSize - cellSize * cellInset) / 2\n",
" );\n",
" c.scale(pieceScale * cellInset, pieceScale * cellInset);\n",
" drawPiece(board[i]);\n",
" c.restore();\n",
" }\n",
"\n",
" // Background Gradient.\n",
" const bgRadius = (Math.min(rows, columns) * cellSize) / 2;\n",
" const bgStyle = c.createRadialGradient(\n",
" xOffset + (cellSize * columns) / 2,\n",
" yOffset + (cellSize * rows) / 2,\n",
" 0,\n",
" xOffset + (cellSize * columns) / 2,\n",
" yOffset + (cellSize * rows) / 2,\n",
" bgRadius\n",
" );\n",
" bgStyle.addColorStop(0, &quot;#000B49&quot;);\n",
" bgStyle.addColorStop(1, &quot;#000B2A&quot;);\n",
"\n",
" // Render the board overlay.\n",
" c.beginPath();\n",
" c.rect(0, 0, canvas.width, canvas.height);\n",
" c.closePath();\n",
" c.shadowBlur = 0;\n",
" for (let i = 0; i < board.length; i++) {\n",
" drawCellCircle(i);\n",
" c.closePath();\n",
" }\n",
" c.fillStyle = bgStyle;\n",
" c.fill(&quot;evenodd&quot;);\n",
"\n",
" // Render the board overlay cell outlines.\n",
" for (let i = 0; i < board.length; i++) {\n",
" c.beginPath();\n",
" drawCellCircle(i);\n",
" c.strokeStyle = &quot;#0361B2&quot;;\n",
" c.lineWidth = 1;\n",
" c.stroke();\n",
" c.closePath();\n",
" }\n",
"\n",
" const drawLine = (fromCell, toCell) => {\n",
" if (frame < 0.5) return;\n",
" const lineFrame = (frame - 0.5) / 0.5;\n",
" const x1 = xOffset + (fromCell % columns) * cellSize + cellSize / 2;\n",
" const x2 =\n",
" x1 +\n",
" lineFrame *\n",
" (xOffset + ((toCell % columns) * cellSize + cellSize / 2) - x1);\n",
" const y1 =\n",
" yOffset + Math.floor(fromCell / columns) * cellSize + cellSize / 2;\n",
" const y2 =\n",
" y1 +\n",
" lineFrame *\n",
" (yOffset + Math.floor(toCell / columns) * cellSize + cellSize / 2 - y1);\n",
" c.beginPath();\n",
" c.lineCap = &quot;round&quot;;\n",
" c.lineWidth = 4;\n",
" c.strokeStyle = getColor(board[fromCell]);\n",
" c.shadowBlur = 8;\n",
" c.shadowColor = getColor(board[fromCell]);\n",
" c.moveTo(x1, y1);\n",
" c.lineTo(x2, y2);\n",
" c.stroke();\n",
" };\n",
"\n",
" // Generate a graph of the board.\n",
" const getCell = (cell, rowOffset, columnOffset) => {\n",
" const row = Math.floor(cell / columns) + rowOffset;\n",
" const col = (cell % columns) + columnOffset;\n",
" if (row < 0 || row >= rows || col < 0 || col >= columns) return -1;\n",
" return col + row * columns;\n",
" };\n",
" const makeNode = cell => {\n",
" const node = { cell, directions: [], value: board[cell] };\n",
" for (let r = -1; r <= 1; r++) {\n",
" for (let c = -1; c <= 1; c++) {\n",
" if (r === 0 && c === 0) continue;\n",
" node.directions.push(getCell(cell, r, c));\n",
" }\n",
" }\n",
" return node;\n",
" };\n",
" const graph = board.map((_, i) => makeNode(i));\n",
"\n",
" // Check for any wins!\n",
" const getSequence = (node, direction) => {\n",
" const sequence = [node.cell];\n",
" while (sequence.length < inarow) {\n",
" const next = graph[node.directions[direction]];\n",
" if (!next || node.value !== next.value || next.value === 0) return;\n",
" node = next;\n",
" sequence.push(node.cell);\n",
" }\n",
" return sequence;\n",
" };\n",
"\n",
" // Check all nodes.\n",
" for (let i = 0; i < board.length; i++) {\n",
" // Check all directions (not the most efficient).\n",
" for (let d = 0; d < 8; d++) {\n",
" const seq = getSequence(graph[i], d);\n",
" if (seq) {\n",
" drawLine(seq[0], seq[inarow - 1]);\n",
" i = board.length;\n",
" break;\n",
" }\n",
" }\n",
" }\n",
"\n",
" // Upgrade the legend.\n",
" if (agents.length && (!agents[0].color || !agents[0].image)) {\n",
" const getPieceImage = mark => {\n",
" const pieceCanvas = document.createElement(&quot;canvas&quot;);\n",
" parent.appendChild(pieceCanvas);\n",
" pieceCanvas.style.marginLeft = &quot;10000px&quot;;\n",
" pieceCanvas.width = 100;\n",
" pieceCanvas.height = 100;\n",
" c = pieceCanvas.getContext(&quot;2d&quot;);\n",
" c.translate(10, 10);\n",
" c.scale(0.8, 0.8);\n",
" drawPiece(mark);\n",
" const dataUrl = pieceCanvas.toDataURL();\n",
" parent.removeChild(pieceCanvas);\n",
" return dataUrl;\n",
" };\n",
"\n",
" agents.forEach(agent => {\n",
" agent.color = getColor(agent.index + 1);\n",
" agent.image = getPieceImage(agent.index + 1);\n",
" });\n",
" update({ agents });\n",
" }\n",
"};\n",
"\n",
"\n",
" \n",
" </script>\n",
" <script>\n",
" const h = htm.bind(preact.h);\n",
" const { useContext, useEffect, useRef, useState } = preactHooks;\n",
" const styled = window.styled.default;\n",
"\n",
" const Context = preact.createContext({});\n",
"\n",
" const Loading = styled.div`\n",
" animation: rotate360 1.1s infinite linear;\n",
" border: 8px solid rgba(255, 255, 255, 0.2);\n",
" border-left-color: #0cb1ed;\n",
" border-radius: 50%;\n",
" height: 40px;\n",
" position: relative;\n",
" transform: translateZ(0);\n",
" width: 40px;\n",
"\n",
" @keyframes rotate360 {\n",
" 0% {\n",
" transform: rotate(0deg);\n",
" }\n",
" 100% {\n",
" transform: rotate(360deg);\n",
" }\n",
" }\n",
" `;\n",
"\n",
" const Logo = styled(\n",
" (props) => h`\n",
" <a href=&quot;https://kaggle.com&quot; target=&quot;_blank&quot; className=${props.className}>\n",
" <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",
" <g fill=&quot;#1EBEFF&quot; fill-rule=&quot;nonzero&quot;>\n",
" <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",
" <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",
" <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",
" <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",
" <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",
" <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",
" </g>\n",
" </svg>\n",
" </a>\n",
" `\n",
" )`\n",
" display: inline-flex;\n",
" `;\n",
"\n",
" const Header = styled((props) => {\n",
" const { environment } = useContext(Context);\n",
"\n",
" return h`<div className=${props.className} >\n",
" <${Logo} />\n",
" <span><b>Left / Right Arrow:</b> Increase / Decrease Step</span><span><b>0-9 Row Keys:</b> Playback Speed</span><span><b>Space:</b> Pause / Play</span>\n",
" ${environment.title}\n",
" </div>`;\n",
" })`\n",
" align-items: center;\n",
" border-bottom: 4px solid #212121;\n",
" box-sizing: border-box;\n",
" color: #fff;\n",
" display: flex;\n",
" flex: 0 0 36px;\n",
" font-size: 14px;\n",
" justify-content: space-between;\n",
" padding: 0 8px;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Renderer = styled((props) => {\n",
" const context = useContext(Context);\n",
" const { animate, debug, playing, renderer, speed } = context;\n",
" const ref = preact.createRef();\n",
"\n",
" useEffect(async () => {\n",
" if (!ref.current) return;\n",
"\n",
" const renderFrame = async (start, step, lastFrame) => {\n",
" if (step !== context.step) return;\n",
" if (lastFrame === 1) {\n",
" if (!animate) return;\n",
" start = Date.now();\n",
" }\n",
" const frame =\n",
" playing || animate\n",
" ? Math.min((Date.now() - start) / speed, 1)\n",
" : 1;\n",
" try {\n",
" if (debug) console.time(&quot;render&quot;);\n",
" await renderer({\n",
" ...context,\n",
" frame,\n",
" height: ref.current.clientHeight,\n",
" hooks: preactHooks,\n",
" parent: ref.current,\n",
" preact,\n",
" styled,\n",
" width: ref.current.clientWidth,\n",
" });\n",
" } catch (error) {\n",
" if (debug) console.error(error);\n",
" console.log({ ...context, frame, error });\n",
" } finally {\n",
" if (debug) console.timeEnd(&quot;render&quot;);\n",
" }\n",
" window.requestAnimationFrame(() => renderFrame(start, step, frame));\n",
" };\n",
"\n",
" await renderFrame(Date.now(), context.step);\n",
" }, [ref.current, context.step, context.renderer]);\n",
"\n",
" return h`<div className=${props.className} ref=${ref} />`;\n",
" })`\n",
" align-items: center;\n",
" box-sizing: border-box;\n",
" display: flex;\n",
" height: 100%;\n",
" left: 0;\n",
" justify-content: center;\n",
" position: absolute;\n",
" top: 0;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Processing = styled((props) => {\n",
" const { processing } = useContext(Context);\n",
" const text = processing === true ? &quot;Processing...&quot; : processing;\n",
" return h`<div className=${props.className}>${text}</div>`;\n",
" })`\n",
" bottom: 0;\n",
" color: #fff;\n",
" font-size: 12px;\n",
" left: 0;\n",
" line-height: 24px;\n",
" position: absolute;\n",
" text-align: center;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Viewer = styled((props) => {\n",
" const { processing } = useContext(Context);\n",
" return h`<div className=${props.className}>\n",
" <${Renderer} />\n",
" ${processing && h`<${Processing} />`}\n",
" </div>`;\n",
" })`\n",
" background-color: #000b2a;\n",
" background-image: radial-gradient(\n",
" circle closest-side,\n",
" #000b49,\n",
" #000b2a\n",
" );\n",
" display: flex;\n",
" flex: 1;\n",
" overflow: hidden;\n",
" position: relative;\n",
" width: 100%;\n",
" `;\n",
"\n",
" // Partitions the elements of arr into subarrays of max length num.\n",
" const groupIntoSets = (arr, num) => {\n",
" const sets = [];\n",
" arr.forEach(a => {\n",
" if (sets.length === 0 || sets[sets.length - 1].length === num) {\n",
" sets.push([]);\n",
" }\n",
" sets[sets.length - 1].push(a);\n",
" });\n",
" return sets;\n",
" }\n",
"\n",
" // Expects `width` input prop to set proper max-width for agent name span.\n",
" const Legend = styled((props) => {\n",
" const { agents, legend } = useContext(Context);\n",
"\n",
" const agentPairs = groupIntoSets(agents.sort((a, b) => a.index - b.index), 2);\n",
"\n",
" return h`<div className=${props.className}>\n",
" ${agentPairs.map(agentList =>\n",
" h`<ul>\n",
" ${agentList.map(a =>\n",
" h`<li key=${a.id} title=&quot;id: ${a.id}&quot; style=&quot;color:${a.color || &quot;#FFF&quot;}&quot;>\n",
" ${a.image && h`<img src=${a.image} />`}\n",
" <span>${a.name}</span>\n",
" </li>`\n",
" )}\n",
" </ul>`)}\n",
" </div>`;\n",
" })`\n",
" background-color: #000b2a;\n",
" font-family: sans-serif;\n",
" font-size: 14px;\n",
" width: 100%;\n",
"\n",
" ul {\n",
" align-items: center;\n",
" display: flex;\n",
" flex-direction: row;\n",
" justify-content: center;\n",
" }\n",
"\n",
" li {\n",
" align-items: center;\n",
" display: inline-flex;\n",
" transition: color 1s;\n",
" }\n",
"\n",
" span {\n",
" max-width: ${p => (p.width || 400) * 0.5 - 36}px;\n",
" overflow: hidden;\n",
" text-overflow: ellipsis;\n",
" white-space: nowrap;\n",
" }\n",
"\n",
" img {\n",
" height: 24px;\n",
" margin-left: 4px;\n",
" margin-right: 4px;\n",
" width: 24px;\n",
" }\n",
" `;\n",
"\n",
" const StepInput = styled.input.attrs({\n",
" type: &quot;range&quot;,\n",
" })`\n",
" appearance: none;\n",
" background: rgba(255, 255, 255, 0.15);\n",
" border-radius: 2px;\n",
" display: block;\n",
" flex: 1;\n",
" height: 4px;\n",
" opacity: 0.8;\n",
" outline: none;\n",
" transition: opacity 0.2s;\n",
" width: 100%;\n",
"\n",
" &:hover {\n",
" opacity: 1;\n",
" }\n",
"\n",
" &::-webkit-slider-thumb {\n",
" appearance: none;\n",
" background: #1ebeff;\n",
" border-radius: 100%;\n",
" cursor: pointer;\n",
" height: 12px;\n",
" margin: 0;\n",
" position: relative;\n",
" width: 12px;\n",
"\n",
" &::after {\n",
" content: &quot;&quot;;\n",
" position: absolute;\n",
" top: 0px;\n",
" left: 0px;\n",
" width: 200px;\n",
" height: 8px;\n",
" background: green;\n",
" }\n",
" }\n",
" `;\n",
"\n",
" const PlayButton = styled.button`\n",
" align-items: center;\n",
" background: none;\n",
" border: none;\n",
" color: white;\n",
" cursor: pointer;\n",
" display: flex;\n",
" flex: 0 0 56px;\n",
" font-size: 20px;\n",
" height: 40px;\n",
" justify-content: center;\n",
" opacity: 0.8;\n",
" outline: none;\n",
" transition: opacity 0.2s;\n",
"\n",
" &:hover {\n",
" opacity: 1;\n",
" }\n",
" `;\n",
"\n",
" const StepCount = styled.span`\n",
" align-items: center;\n",
" color: white;\n",
" display: flex;\n",
" font-size: 14px;\n",
" justify-content: center;\n",
" opacity: 0.8;\n",
" padding: 0 16px;\n",
" pointer-events: none;\n",
" `;\n",
"\n",
" const Controls = styled((props) => {\n",
" const { environment, pause, play, playing, setStep, step } = useContext(\n",
" Context\n",
" );\n",
" const value = step + 1;\n",
" const onClick = () => (playing ? pause() : play());\n",
" const onInput = (e) => {\n",
" pause();\n",
" setStep(parseInt(e.target.value) - 1);\n",
" };\n",
"\n",
" return h`\n",
" <div className=${props.className}>\n",
" <${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",
" playing\n",
" ? h`<path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
" : h`<path d=&quot;M8 5v14l11-7z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
" }</svg><//>\n",
" <${StepInput} min=&quot;1&quot; max=${\n",
" environment.steps.length\n",
" } value=&quot;${value}&quot; onInput=${onInput} />\n",
" <${StepCount}>${value} / ${environment.steps.length}<//>\n",
" </div>\n",
" `;\n",
" })`\n",
" align-items: center;\n",
" border-top: 4px solid #212121;\n",
" display: flex;\n",
" flex: 0 0 44px;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const Info = styled((props) => {\n",
" const {\n",
" environment,\n",
" playing,\n",
" step,\n",
" speed,\n",
" animate,\n",
" header,\n",
" controls,\n",
" settings,\n",
" } = useContext(Context);\n",
"\n",
" return h`\n",
" <div className=${props.className}>\n",
" info:\n",
" step(${step}),\n",
" playing(${playing ? &quot;T&quot; : &quot;F&quot;}),\n",
" speed(${speed}),\n",
" animate(${animate ? &quot;T&quot; : &quot;F&quot;})\n",
" </div>`;\n",
" })`\n",
" color: #888;\n",
" font-family: monospace;\n",
" font-size: 12px;\n",
" `;\n",
"\n",
" const Settings = styled((props) => {\n",
" const { environment, pause, play, playing, setStep, step } = useContext(\n",
" Context\n",
" );\n",
"\n",
" return h`\n",
" <div className=${props.className}>\n",
" <${Info} />\n",
" </div>\n",
" `;\n",
" })`\n",
" background: #fff;\n",
" border-top: 4px solid #212121;\n",
" box-sizing: border-box;\n",
" padding: 20px;\n",
" width: 100%;\n",
"\n",
" h1 {\n",
" font-size: 20px;\n",
" }\n",
" `;\n",
"\n",
" const Player = styled((props) => {\n",
" const context = useContext(Context);\n",
" const { agents, controls, header, legend, loading, settings, width } = context;\n",
" return h`\n",
" <div className=${props.className}>\n",
" ${loading && h`<${Loading} />`}\n",
" ${!loading && header && h`<${Header} />`}\n",
" ${!loading && h`<${Viewer} />`}\n",
" ${!loading && agents.length > 0 && legend && h`<${Legend} width=${width}/>`}\n",
" ${!loading && controls && h`<${Controls} />`}\n",
" ${!loading && settings && h`<${Settings} />`}\n",
" </div>`;\n",
" })`\n",
" align-items: center;\n",
" background: #212121;\n",
" border: 4px solid #212121;\n",
" box-sizing: border-box;\n",
" display: flex;\n",
" flex-direction: column;\n",
" height: 100%;\n",
" justify-content: center;\n",
" position: relative;\n",
" width: 100%;\n",
" `;\n",
"\n",
" const App = () => {\n",
" const renderCountRef = useRef(0);\n",
" const [_, setRenderCount] = useState(0);\n",
"\n",
" // These are bindings to the 0-9 keys and are milliseconds of timeout per step\n",
" const speeds = [\n",
" 0,\n",
" 3000,\n",
" 1000,\n",
" 500,\n",
" 333, // Default\n",
" 200,\n",
" 100,\n",
" 50,\n",
" 25,\n",
" 10,\n",
" ];\n",
"\n",
" const contextRef = useRef({\n",
" animate: false,\n",
" agents: [],\n",
" autoplay: false,\n",
" controls: false,\n",
" debug: false,\n",
" environment: { steps: [], info: {} },\n",
" header: window.innerHeight >= 600,\n",
" height: window.innerHeight,\n",
" interactive: false,\n",
" legend: true,\n",
" loading: false,\n",
" playing: false,\n",
" processing: false,\n",
" renderer: () => &quot;DNE&quot;,\n",
" settings: false,\n",
" speed: speeds[4],\n",
" step: 0,\n",
" width: window.innerWidth,\n",
" });\n",
"\n",
" // Context helpers.\n",
" const rerender = (contextRef.current.rerender = () =>\n",
" setRenderCount((renderCountRef.current += 1)));\n",
" const setStep = (contextRef.current.setStep = (newStep) => {\n",
" contextRef.current.step = newStep;\n",
" rerender();\n",
" });\n",
" const setPlaying = (contextRef.current.setPlaying = (playing) => {\n",
" contextRef.current.playing = playing;\n",
" rerender();\n",
" });\n",
" const pause = (contextRef.current.pause = () => setPlaying(false));\n",
"\n",
" const playNext = () => {\n",
" const context = contextRef.current;\n",
"\n",
" if (\n",
" context.playing &&\n",
" context.step < context.environment.steps.length - 1\n",
" ) {\n",
" setStep(context.step + 1);\n",
" play(true);\n",
" } else {\n",
" pause();\n",
" }\n",
" };\n",
"\n",
" const play = (contextRef.current.play = (continuing) => {\n",
" const context = contextRef.current;\n",
" if (context.playing && !continuing) return;\n",
" if (!context.playing) setPlaying(true);\n",
" if (\n",
" !continuing &&\n",
" context.step === context.environment.steps.length - 1\n",
" ) {\n",
" setStep(0);\n",
" }\n",
" setTimeout(playNext, context.speed);\n",
" });\n",
"\n",
" const updateContext = (o) => {\n",
" const context = contextRef.current;\n",
" Object.assign(context, o, {\n",
" environment: { ...context.environment, ...(o.environment || {}) },\n",
" });\n",
" rerender();\n",
"\n",
" // If autoplay, toggle to playing.\n",
" if (context.autoplay) play();\n",
" };\n",
"\n",
" // First time setup.\n",
" useEffect(() => {\n",
" // Timeout is used to ensure useEffect renders once.\n",
" setTimeout(() => {\n",
" // Initialize context with window.kaggle.\n",
" updateContext(window.kaggle || {});\n",
" // Listen for messages received to update the context.\n",
" window.addEventListener(\n",
" &quot;message&quot;,\n",
" (event) => {\n",
" // Ensure the environment names match before updating.\n",
" try {\n",
" if (\n",
" event.data.environment.name ==\n",
" contextRef.current.environment.name\n",
" ) {\n",
" updateContext(event.data);\n",
" }\n",
" } catch {}\n",
" },\n",
" false\n",
" );\n",
" // Listen for keyboard commands.\n",
" window.addEventListener(\n",
" &quot;keydown&quot;,\n",
" (event) => {\n",
" const {\n",
" interactive,\n",
" isInteractive,\n",
" playing,\n",
" step,\n",
" environment,\n",
" } = contextRef.current;\n",
" const key = event.keyCode;\n",
" const zero_key = 48\n",
" const nine_key = 57\n",
" if (\n",
" interactive ||\n",
" isInteractive() ||\n",
" (key !== 32 && key !== 37 && key !== 39 && !(key >= zero_key && key <= nine_key))\n",
" )\n",
" return;\n",
"\n",
" if (key === 32) {\n",
" playing ? pause() : play();\n",
" } else if (key === 39) {\n",
" contextRef.current.playing = false;\n",
" if (step < environment.steps.length - 1) setStep(step + 1);\n",
" rerender();\n",
" } else if (key === 37) {\n",
" contextRef.current.playing = false;\n",
" if (step > 0) setStep(step - 1);\n",
" rerender();\n",
" } else if (key >= zero_key && key <= nine_key) {\n",
" contextRef.current.speed = speeds[key - zero_key];\n",
" }\n",
" event.preventDefault();\n",
" return false;\n",
" },\n",
" false\n",
" );\n",
" }, 1);\n",
" }, []);\n",
"\n",
" if (contextRef.current.debug) {\n",
" console.log(&quot;context&quot;, contextRef.current);\n",
" }\n",
"\n",
" // Ability to update context.\n",
" contextRef.current.update = updateContext;\n",
"\n",
" // Ability to communicate with ipython.\n",
" const execute = (contextRef.current.execute = (source) =>\n",
" new Promise((resolve, reject) => {\n",
" try {\n",
" window.parent.IPython.notebook.kernel.execute(source, {\n",
" iopub: {\n",
" output: (resp) => {\n",
" const type = resp.msg_type;\n",
" if (type === &quot;stream&quot;) return resolve(resp.content.text);\n",
" if (type === &quot;error&quot;) return reject(new Error(resp.evalue));\n",
" return reject(new Error(&quot;Unknown message type: &quot; + type));\n",
" },\n",
" },\n",
" });\n",
" } catch (e) {\n",
" reject(new Error(&quot;IPython Unavailable: &quot; + e));\n",
" }\n",
" }));\n",
"\n",
" // Ability to return an action from an interactive session.\n",
" contextRef.current.act = (action) => {\n",
" const id = contextRef.current.environment.id;\n",
" updateContext({ processing: true });\n",
" execute(`\n",
" import json\n",
" from kaggle_environments import interactives\n",
" if &quot;${id}&quot; in interactives:\n",
" action = json.loads('${JSON.stringify(action)}')\n",
" env, trainer = interactives[&quot;${id}&quot;]\n",
" trainer.step(action)\n",
" print(json.dumps(env.steps))`)\n",
" .then((resp) => {\n",
" try {\n",
" updateContext({\n",
" processing: false,\n",
" environment: { steps: JSON.parse(resp) },\n",
" });\n",
" play();\n",
" } catch (e) {\n",
" updateContext({ processing: resp.split(&quot;\\n&quot;)[0] });\n",
" console.error(resp, e);\n",
" }\n",
" })\n",
" .catch((e) => console.error(e));\n",
" };\n",
"\n",
" // Check if currently interactive.\n",
" contextRef.current.isInteractive = () => {\n",
" const context = contextRef.current;\n",
" const steps = context.environment.steps;\n",
" return (\n",
" context.interactive &&\n",
" !context.processing &&\n",
" context.step === steps.length - 1 &&\n",
" steps[context.step].some((s) => s.status === &quot;ACTIVE&quot;)\n",
" );\n",
" };\n",
"\n",
" return h`\n",
" <${Context.Provider} value=${contextRef.current}>\n",
" <${Player} />\n",
" <//>`;\n",
" };\n",
"\n",
" preact.render(h`<${App} />`, document.body);\n",
" </script>\n",
" </body>\n",
"</html>\n",
"\" width=\"300\" height=\"300\" frameborder=\"0\"></iframe> "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import kaggle_environments\n",
"\n",
"env = kaggle_environments.make(\"connectx\")\n",
"\n",
"# Basic agent which marks the first available cell.\n",
"def my_agent(obs):\n",
" return [c for c in range(len(obs.board)) if obs.board[c] == 0][0]\n",
"\n",
"# Run the basic agent against a default agent which chooses a \"random\" move.\n",
"env.run([my_agent, \"random\"])\n",
"\n",
"\n",
"env.render(mode=\"ipython\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import kaggle_environments\n",
"\n",
"env = kaggle_environments.make(\"connectx\")\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Create an Agent\n",
"\n",
"To create the submission, an agent function should be fully encapsulated (no external dependencies). \n",
"\n",
"When your agent is being evaluated against others, it will not have access to the Kaggle docker image. Only the following can be imported: Python Standard Library Modules, gym, numpy, scipy (more may be added later). "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# This agent random chooses a non-empty column.\n",
"def my_agent(observation, configuration):\n",
" from random import choice\n",
" return choice([c for c in range(configuration.columns) if observation.board[c] == 0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def random_agent(observation, configuration):\n",
" from random import choice\n",
" return choice([c for c in range(configuration.columns) if observation.board[c] == 0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Test your Agent"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset()\n",
"# Play as the first agent against default \"random\" agent.\n",
"env.run([my_agent, \"random\"])\n",
"env.render(mode=\"ipython\", width=500, height=450)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Debug/Train your Agent"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Play as first position against random agent.\n",
"trainer = env.train([None, \"random\"])\n",
"\n",
"observation = trainer.reset()\n",
"\n",
"while not env.done:\n",
" my_action = my_agent(observation, env.configuration)\n",
" print(\"My Action\", my_action)\n",
" observation, reward, done, info = trainer.step(my_action)\n",
" # env.render(mode=\"ipython\", width=100, height=90, header=False, controls=False)\n",
"env.render()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Evaluate your Agent"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def mean_reward(rewards):\n",
" return sum(r[0] for r in rewards) / sum(r[0] + r[1] for r in rewards)\n",
"\n",
"# Run multiple episodes to estimate it's performance.\n",
"print(\"My Agent vs Random Agent:\", mean_reward(evaluate(\"connectx\", [my_agent, \"random\"], num_episodes=10)))\n",
"print(\"My Agent vs Negamax Agent:\", mean_reward(evaluate(\"connectx\", [my_agent, \"negamax\"], num_episodes=10)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Write Submission File\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import inspect\n",
"import os\n",
"\n",
"def write_agent_to_file(function, file):\n",
" with open(file, \"a\" if os.path.exists(file) else \"w\") as f:\n",
" f.write(inspect.getsource(function))\n",
" print(function, \"written to\", file)\n",
"\n",
"write_agent_to_file(my_agent, \"submission.py\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Submit to Competition\n",
"\n",
"1. Commit this kernel.\n",
"2. View the commited version.\n",
"3. Go to \"Data\" section and find submission.py file.\n",
"4. Click \"Submit to Competition\"\n",
"5. Go to [My Submissions](https://kaggle.com/c/connectx/submissions) to view your score and episodes being played."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}