├── .gcloudignore
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── docker
├── README.md
├── bash.sh
├── bashsc.sh
├── build.sh
├── build_cpu.sh
├── build_gpu.sh
├── cloudbuild.yaml
├── cpu.Dockerfile
├── gpu.Dockerfile
├── nodesource_setup_14.x.sh
├── open_spiel.Dockerfile
├── run.sh
├── runsc.sh
└── test.sh
├── kaggle_environments
├── __init__.py
├── agent.py
├── api.py
├── core.py
├── envs
│ ├── chess
│ │ ├── chess.js
│ │ ├── chess.json
│ │ ├── chess.py
│ │ └── test_chess.py
│ ├── connectx
│ │ ├── connectx.ipynb
│ │ ├── connectx.js
│ │ ├── connectx.json
│ │ ├── connectx.py
│ │ └── test_connectx.py
│ ├── football
│ │ ├── football.ipynb
│ │ ├── football.json
│ │ ├── football.py
│ │ ├── helpers.py
│ │ └── test_football.py
│ ├── halite
│ │ ├── __init__.py
│ │ ├── halite.ipynb
│ │ ├── halite.js
│ │ ├── halite.json
│ │ ├── halite.py
│ │ ├── helpers.py
│ │ └── test_halite.py
│ ├── hungry_geese
│ │ ├── __init__.py
│ │ ├── hungry_geese.js
│ │ ├── hungry_geese.json
│ │ ├── hungry_geese.py
│ │ └── test_hungry_geese.py
│ ├── identity
│ │ ├── identity.json
│ │ └── identity.py
│ ├── kore_fleets
│ │ ├── __init__.py
│ │ ├── helpers.py
│ │ ├── kore_fleets.ipynb
│ │ ├── kore_fleets.js
│ │ ├── kore_fleets.json
│ │ ├── kore_fleets.py
│ │ ├── starter_bots
│ │ │ ├── java
│ │ │ │ ├── Bot.java
│ │ │ │ ├── README.md
│ │ │ │ ├── jars
│ │ │ │ │ ├── hamcrest-core-1.3.jar
│ │ │ │ │ └── junit-4.13.2.jar
│ │ │ │ ├── kore
│ │ │ │ │ ├── Board.java
│ │ │ │ │ ├── Cell.java
│ │ │ │ │ ├── Configuration.java
│ │ │ │ │ ├── Direction.java
│ │ │ │ │ ├── Fleet.java
│ │ │ │ │ ├── KoreJson.java
│ │ │ │ │ ├── Observation.java
│ │ │ │ │ ├── Pair.java
│ │ │ │ │ ├── Player.java
│ │ │ │ │ ├── Point.java
│ │ │ │ │ ├── Shipyard.java
│ │ │ │ │ └── ShipyardAction.java
│ │ │ │ ├── main.py
│ │ │ │ └── test
│ │ │ │ │ ├── BoardTest.java
│ │ │ │ │ ├── ConfigurationTest.java
│ │ │ │ │ ├── KoreJsonTest.java
│ │ │ │ │ ├── ObservationTest.java
│ │ │ │ │ ├── PointTest.java
│ │ │ │ │ ├── ShipyardTest.java
│ │ │ │ │ ├── configuration.json
│ │ │ │ │ ├── fullob.json
│ │ │ │ │ └── observation.json
│ │ │ ├── python
│ │ │ │ ├── __init__.py
│ │ │ │ └── main.py
│ │ │ └── ts
│ │ │ │ ├── Bot.ts
│ │ │ │ ├── DoNothingBot.ts
│ │ │ │ ├── MinerBot.ts
│ │ │ │ ├── README.md
│ │ │ │ ├── interpreter.ts
│ │ │ │ ├── kore
│ │ │ │ ├── Board.ts
│ │ │ │ ├── Cell.ts
│ │ │ │ ├── Configuration.ts
│ │ │ │ ├── Direction.ts
│ │ │ │ ├── Fleet.ts
│ │ │ │ ├── KoreIO.ts
│ │ │ │ ├── Observation.ts
│ │ │ │ ├── Pair.ts
│ │ │ │ ├── Player.ts
│ │ │ │ ├── Point.ts
│ │ │ │ ├── Shipyard.ts
│ │ │ │ └── ShipyardAction.ts
│ │ │ │ ├── main.py
│ │ │ │ ├── miner.py
│ │ │ │ ├── package.json
│ │ │ │ ├── test
│ │ │ │ ├── BoardTest.ts
│ │ │ │ ├── ConfigurationTest.ts
│ │ │ │ ├── ObservationTest.ts
│ │ │ │ ├── PointTest.ts
│ │ │ │ ├── ShipyardTest.ts
│ │ │ │ ├── configuration.json
│ │ │ │ ├── fullob.json
│ │ │ │ └── observation.json
│ │ │ │ └── tsconfig.json
│ │ └── test_kore_fleets.py
│ ├── llm_20_questions
│ │ ├── keywords.py
│ │ ├── llm_20_questions.js
│ │ ├── llm_20_questions.json
│ │ ├── llm_20_questions.py
│ │ └── test_llm_20_questions.py
│ ├── lux_ai_2021
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── agents.py
│ │ ├── dimensions
│ │ │ ├── 754.js
│ │ │ ├── 754.js.LICENSE.txt
│ │ │ └── main.js
│ │ ├── index.html
│ │ ├── lux_ai_2021.json
│ │ ├── lux_ai_2021.py
│ │ ├── test_agents
│ │ │ ├── __init__.py
│ │ │ ├── js_simple
│ │ │ │ ├── lux
│ │ │ │ │ ├── game_constants.js
│ │ │ │ │ ├── game_constants.json
│ │ │ │ │ ├── game_objects.js
│ │ │ │ │ ├── io.js
│ │ │ │ │ ├── kit.js
│ │ │ │ │ ├── map.js
│ │ │ │ │ └── parser.js
│ │ │ │ ├── main.js
│ │ │ │ ├── main.py
│ │ │ │ └── simple.tar.gz
│ │ │ └── python
│ │ │ │ ├── lux
│ │ │ │ ├── __init__.py
│ │ │ │ ├── annotate.py
│ │ │ │ ├── constants.py
│ │ │ │ ├── game.py
│ │ │ │ ├── game_constants.json
│ │ │ │ ├── game_constants.py
│ │ │ │ ├── game_map.py
│ │ │ │ └── game_objects.py
│ │ │ │ ├── random_agent.py
│ │ │ │ └── simple_agent.py
│ │ ├── test_lux.py
│ │ ├── testing.md
│ │ └── todo.md.og
│ ├── lux_ai_s2
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── agents.py
│ │ ├── index.html
│ │ ├── lux_ai_s2.json
│ │ ├── lux_ai_s2.py
│ │ ├── luxai_s2
│ │ │ ├── .DS_Store
│ │ │ ├── __init__.py
│ │ │ ├── actions.py
│ │ │ ├── config.py
│ │ │ ├── env.py
│ │ │ ├── factory.py
│ │ │ ├── globals.py
│ │ │ ├── map
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bfs_deltas_gen.py
│ │ │ │ ├── board.py
│ │ │ │ └── position.py
│ │ │ ├── map_generator
│ │ │ │ ├── .DS_Store
│ │ │ │ ├── __init__.py
│ │ │ │ ├── generator.py
│ │ │ │ ├── symnoise.py
│ │ │ │ ├── timing.py
│ │ │ │ ├── visualize.py
│ │ │ │ └── visualize_samples.py
│ │ │ ├── pyvisual
│ │ │ │ ├── __init__.py
│ │ │ │ └── visualizer.py
│ │ │ ├── replay
│ │ │ │ ├── __init__.py
│ │ │ │ └── replay.py
│ │ │ ├── spaces
│ │ │ │ ├── __init__.py
│ │ │ │ ├── act_space.py
│ │ │ │ └── obs_space.py
│ │ │ ├── state
│ │ │ │ ├── __init__.py
│ │ │ │ ├── state.py
│ │ │ │ ├── stats.py
│ │ │ │ └── typing.py
│ │ │ ├── team.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ └── replay.py
│ │ │ ├── unit.py
│ │ │ ├── utils
│ │ │ │ ├── __init__.py
│ │ │ │ ├── animate.py
│ │ │ │ ├── heuristics
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── bidding.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ └── factory_placement.py
│ │ │ │ └── utils.py
│ │ │ ├── version.py
│ │ │ └── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── controllers.py
│ │ │ │ └── sb3.py
│ │ ├── test_agents
│ │ │ └── python
│ │ │ │ ├── agent.py
│ │ │ │ ├── lux
│ │ │ │ ├── cargo.py
│ │ │ │ ├── config.py
│ │ │ │ ├── factory.py
│ │ │ │ ├── kit.py
│ │ │ │ ├── team.py
│ │ │ │ ├── unit.py
│ │ │ │ └── utils.py
│ │ │ │ └── main.py
│ │ └── test_lux.py
│ ├── lux_ai_s3
│ │ ├── README.md
│ │ ├── agents.py
│ │ ├── index.html
│ │ ├── lux_ai_s3.json
│ │ ├── lux_ai_s3.py
│ │ ├── luxai_s3
│ │ │ ├── __init__.py
│ │ │ ├── env.py
│ │ │ ├── globals.py
│ │ │ ├── params.py
│ │ │ ├── profiler.py
│ │ │ ├── pygame_render.py
│ │ │ ├── spaces.py
│ │ │ ├── state.py
│ │ │ ├── utils.py
│ │ │ └── wrappers.py
│ │ ├── test_agents
│ │ │ └── python
│ │ │ │ ├── agent.py
│ │ │ │ ├── lux
│ │ │ │ ├── __init__.py
│ │ │ │ ├── kit.py
│ │ │ │ └── utils.py
│ │ │ │ └── main.py
│ │ └── test_lux.py
│ ├── mab
│ │ ├── __init__.py
│ │ ├── agents.py
│ │ ├── mab.js
│ │ ├── mab.json
│ │ └── mab.py
│ ├── open_spiel
│ │ ├── open_spiel.py
│ │ └── test_open_spiel.py
│ ├── rps
│ │ ├── __init__.py
│ │ ├── agents.py
│ │ ├── helpers.py
│ │ ├── rps.js
│ │ ├── rps.json
│ │ ├── rps.py
│ │ ├── test_rps.py
│ │ └── utils.py
│ └── tictactoe
│ │ ├── test_tictactoe.py
│ │ ├── tictactoe.ipynb
│ │ ├── tictactoe.js
│ │ ├── tictactoe.json
│ │ └── tictactoe.py
├── errors.py
├── helpers.py
├── main.py
├── schemas.json
├── static
│ └── player.html
├── status_codes.json
└── utils.py
├── package.sh
├── release.sh
├── requirements.txt
└── setup.py
/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | # If you would like to upload your .git directory, .gitignore file or files
11 | # from your .gitignore file, remove the corresponding line
12 | # below:
13 | .git
14 | .gitignore
15 |
16 | node_modules
17 | #!include:.gitignore
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # pyenv
10 | bin/
11 | lib64
12 | pyvenv.cfg
13 | share/
14 |
15 |
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | pip-wheel-metadata/
31 | share/python-wheels/
32 | *.egg-info/
33 | .installed.cfg
34 | *.egg
35 | MANIFEST
36 |
37 | # PyInstaller
38 | # Usually these files are written by a python script from a template
39 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
40 | *.manifest
41 | *.spec
42 |
43 | # Installer logs
44 | pip-log.txt
45 | pip-delete-this-directory.txt
46 |
47 | # Unit test / coverage reports
48 | htmlcov/
49 | .tox/
50 | .nox/
51 | .coverage
52 | .coverage.*
53 | .cache
54 | nosetests.xml
55 | coverage.xml
56 | *.cover
57 | *.py,cover
58 | .hypothesis/
59 | .pytest_cache/
60 |
61 | # Translations
62 | *.mo
63 | *.pot
64 |
65 | # Django stuff:
66 | *.log
67 | local_settings.py
68 | db.sqlite3
69 | db.sqlite3-journal
70 |
71 | # Flask stuff:
72 | instance/
73 | .webassets-cache
74 |
75 | # Scrapy stuff:
76 | .scrapy
77 |
78 | # Sphinx documentation
79 | docs/_build/
80 |
81 | # PyBuilder
82 | target/
83 |
84 | # Jupyter Notebook
85 | .ipynb_checkpoints
86 |
87 | # IPython
88 | profile_default/
89 | ipython_config.py
90 |
91 | # pyenv
92 | .python-version
93 |
94 | # pipenv
95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
98 | # install all needed dependencies.
99 | #Pipfile.lock
100 |
101 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
102 | __pypackages__/
103 |
104 | # Celery stuff
105 | celerybeat-schedule
106 | celerybeat.pid
107 |
108 | # SageMath parsed files
109 | *.sage.py
110 |
111 | # Environments
112 | .env
113 | .venv
114 | env/
115 | venv/
116 | ENV/
117 | env.bak/
118 | venv.bak/
119 | !docker/envs/football/egl/gfootball/env/
120 |
121 | # Spyder project settings
122 | .spyderproject
123 | .spyproject
124 |
125 | # Rope project settings
126 | .ropeproject
127 |
128 | # mkdocs documentation
129 | /site
130 |
131 | # mypy
132 | .mypy_cache/
133 | .dmypy.json
134 | dmypy.json
135 |
136 | # Pyre type checker
137 | .pyre/
138 |
139 | # Temp Files
140 | temp.*
141 |
142 | .idea/
143 |
144 | # Git merge artifacts
145 | *.orig
146 |
147 | # node.js files
148 | node_modules
149 |
150 | # Java class files
151 | *.class
152 |
153 | .vscode
154 |
155 | submission.tar.gz
156 |
157 | replay.html
158 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows
28 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
29 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | recursive-include kaggle_environments *.py
3 | recursive-include kaggle_environments *.html
4 | recursive-include kaggle_environments *.js
5 | recursive-include kaggle_environments *.ts
6 | global-exclude */node_modules
7 | recursive-include kaggle_environments *.json
--------------------------------------------------------------------------------
/docker/README.md:
--------------------------------------------------------------------------------
1 | # Docker Image
2 | This image encapsulates the kaggle-environments library, its dependencies, and agent execution environment.
3 | This image is hosted at `gcr.io/kaggle-images/python-simulations`
4 |
5 | ## Usage
6 | * `./build.sh` will build the image including any local changes to kaggle_environments.
7 | * `./run.sh` will pass any arguments to the kaggle-environments command line tool running in docker. Note that this also binds port 8080 to run `kaggle-environments http-server` commands.
8 | * `./run.sh list`
9 | * `./run.sh run --environment connectx --agent random random`
10 | * `./run.sh http-server`
11 | * `./test.sh` will run the unit test suite in docker with pytest.
12 | * `./test.sh -k "halite"`
--------------------------------------------------------------------------------
/docker/bash.sh:
--------------------------------------------------------------------------------
1 | # Start the orchestrator container in Docker
2 | docker run -it --entrypoint //bin/bash --rm --name python-simulations python-simulations-cpu
--------------------------------------------------------------------------------
/docker/bashsc.sh:
--------------------------------------------------------------------------------
1 | # Start the orchestrator container in gVisor
2 | docker run --runtime=runsc -it --cpus="0.8" --memory="4g" --entrypoint //bin/bash --rm --name python-simulations python-simulations-cpu
--------------------------------------------------------------------------------
/docker/build.sh:
--------------------------------------------------------------------------------
1 | # Just build the orchestrator container
2 | path=$(dirname $0)
3 | ./$path/build_cpu.sh
4 | # We don't use the GPU image yet, uncomment when used.
5 | # ./$path/build_gpu.sh
--------------------------------------------------------------------------------
/docker/build_cpu.sh:
--------------------------------------------------------------------------------
1 | # Just build the orchestrator container
2 | path=$(dirname $0)
3 | # cd to the parent directory to include kaggle_environments folder in Docker build context
4 | cd $path/..
5 | docker build --pull -f ./docker/cpu.Dockerfile -t python-simulations-cpu .
6 | cd -
7 |
--------------------------------------------------------------------------------
/docker/build_gpu.sh:
--------------------------------------------------------------------------------
1 | # Just build the orchestrator container
2 | path=$(dirname $0)
3 | # cd to the parent directory to include kaggle_environments folder in Docker build context
4 | cd $path/..
5 | docker build -f ./docker/gpu.Dockerfile -t python-simulations-gpu .
6 | cd -
--------------------------------------------------------------------------------
/docker/cloudbuild.yaml:
--------------------------------------------------------------------------------
1 | steps:
2 | - id: 'build-cpu-image'
3 | name: gcr.io/cloud-builders/docker
4 | args: ['build', '-f', './docker/cpu.Dockerfile', '-t', 'gcr.io/kaggle-images/python-simulations', '.']
5 | - id: 'build-gpu-image'
6 | name: gcr.io/cloud-builders/docker
7 | args: ['build', '-f', './docker/gpu.Dockerfile', '-t', 'gcr.io/kaggle-gpu-images/python-simulations', '.']
8 | images: ['gcr.io/kaggle-images/python-simulations', 'gcr.io/kaggle-gpu-images/python-simulations']
9 | timeout: 24h
--------------------------------------------------------------------------------
/docker/cpu.Dockerfile:
--------------------------------------------------------------------------------
1 | # DANGER -- If you update this file, make sure to also update gpu.Dockerfile!
2 |
3 | FROM gcr.io/kaggle-images/python:latest
4 |
5 | # NODE
6 |
7 | # install node and npm from nodesource https://github.com/nodesource/distributions
8 | # use a local mirror of the setup script to avoid `curl | bash`
9 | ADD docker/nodesource_setup_14.x.sh node_setup.sh
10 | RUN sh node_setup.sh && apt-get install -y nodejs
11 |
12 | # link the newly installed versions to /opt/node so we can prioritize these versions over the versions /opt/conda has.
13 | RUN mkdir /opt/node && \
14 | ln -s /usr/bin/node /opt/node/ && \
15 | ln -s /usr/bin/npm /opt/node/
16 |
17 | # add node and npm to path so the commands are available
18 | ENV PATH /opt/node:$PATH
19 | ENV NODE_PATH /usr/lib/node_modules
20 |
21 | # confirm installation
22 | RUN node -v && npm -v
23 |
24 | # END NODE
25 |
26 | WORKDIR /usr/src/app/kaggle_environments
27 |
28 | ADD ./setup.py ./setup.py
29 | ADD ./README.md ./README.md
30 | ADD ./MANIFEST.in ./MANIFEST.in
31 | ADD ./kaggle_environments ./kaggle_environments
32 |
33 |
34 | # install kaggle-environments
35 | RUN pip install Flask bitsandbytes accelerate vec-noise jax gymnax==0.0.8 && pip install . && pytest
36 |
37 | # SET UP KAGGLE-ENVIRONMENTS CHESS
38 | # minimal package to reduce memory footprint
39 | RUN mkdir ./kaggle_environments_chess
40 | RUN cp -r ./kaggle_environments/* ./kaggle_environments_chess/
41 | RUN rm -rf ./kaggle_environments
42 | # remove other runtimes
43 | RUN find ./kaggle_environments_chess/envs -mindepth 1 -maxdepth 1 ! -name "chess" -type d -exec rm -rf {} +
44 | # pyclean
45 | RUN rm -rf ./kaggle_environments_chess/__pycache__; rm -rf ./kaggle_environments_chess/envs/__pycache__; rm -rf ./kaggle_environments_chess/envs/chess/__pycache__; true
46 | RUN find ./kaggle_environments_chess/ -name "*.pyc" -exec rm -f {} \;
47 |
48 | # rename pip package
49 | RUN sed -i 's/kaggle-environments/kaggle-environments-chess/g' ./setup.py
50 | RUN sed -i 's/kaggle_environments/kaggle_environments_chess/g' ./setup.py
51 | RUN sed -i 's/kaggle_environments/kaggle_environments_chess/g' ./MANIFEST.in
52 |
53 | # install kaggle-environments-chess
54 | RUN pip install . && pytest
55 |
56 | CMD kaggle-environments
57 |
--------------------------------------------------------------------------------
/docker/gpu.Dockerfile:
--------------------------------------------------------------------------------
1 | # DANGER -- If you update this file, make sure to also update cpu.Dockerfile!
2 |
3 | FROM gcr.io/kaggle-gpu-images/python:latest
4 |
5 | # NODE
6 |
7 | # install node and npm from nodesource https://github.com/nodesource/distributions
8 | # use a local mirror of the setup script to avoid `curl | bash`
9 | ADD docker/nodesource_setup_14.x.sh node_setup.sh
10 | RUN sh node_setup.sh && apt-get install -y nodejs
11 |
12 | # link the newly installed versions to /opt/node so we can prioritize these versions over the versions /opt/conda has.
13 | RUN mkdir /opt/node && \
14 | ln -s /usr/bin/node /opt/node/ && \
15 | ln -s /usr/bin/npm /opt/node/
16 |
17 | # add node and npm to path so the commands are available
18 | ENV PATH /opt/node:$PATH
19 | ENV NODE_PATH /usr/lib/node_modules
20 |
21 | # confirm installation
22 | RUN node -v && npm -v
23 |
24 | # END NODE
25 |
26 | WORKDIR /usr/src/app/kaggle_environments
27 |
28 | ADD ./setup.py ./setup.py
29 | ADD ./README.md ./README.md
30 | ADD ./MANIFEST.in ./MANIFEST.in
31 | ADD ./kaggle_environments ./kaggle_environments
32 | RUN pip install Flask bitsandbytes accelerate vec-noise jax gymnax==0.0.8 && pip install . && pytest
33 |
34 | CMD kaggle-environments
35 |
--------------------------------------------------------------------------------
/docker/run.sh:
--------------------------------------------------------------------------------
1 | # Start the orchestrator container in Docker
2 | docker run -it --entrypoint kaggle-environments --rm -p 127.0.0.1:8080:8080/tcp --name python-simulations python-simulations-cpu "$@"
--------------------------------------------------------------------------------
/docker/runsc.sh:
--------------------------------------------------------------------------------
1 | # Start the orchestrator container in gVisor
2 | docker run --runtime=runsc -it --cpus="0.8" --memory="4g" --entrypoint kaggle-environments --rm -p 127.0.0.1:8080:8080/tcp --name python-simulations python-simulations-cpu "$@"
--------------------------------------------------------------------------------
/docker/test.sh:
--------------------------------------------------------------------------------
1 | # Start the orchestrator container in Docker
2 | # The double slash in the test directory is to force it to translate to a Linux path rather than a Windows path
3 | docker run -it --entrypoint pytest --rm --name python-simulations python-simulations-cpu '/usr/src/app/kaggle_environments' "$@"
4 |
--------------------------------------------------------------------------------
/kaggle_environments/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 Kaggle Inc
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from importlib import import_module
16 | from os import listdir
17 | from .agent import Agent
18 | from .api import get_episode_replay, list_episodes, list_episodes_for_team, list_episodes_for_submission
19 | from .core import *
20 | from .main import http_request
21 | from . import errors
22 |
23 | __version__ = "1.17.2"
24 |
25 | __all__ = ["Agent", "environments", "errors", "evaluate", "http_request",
26 | "make", "register", "utils", "__version__",
27 | "get_episode_replay", "list_episodes", "list_episodes_for_team", "list_episodes_for_submission"]
28 |
29 | # Register Environments.
30 |
31 | for name in listdir(utils.envs_path):
32 | try:
33 | env = import_module(f".envs.{name}.{name}", __name__)
34 | if name == "open_spiel":
35 | for env_name, env_dict in env.registered_open_spiel_envs.items():
36 | register(env_name, {
37 | "agents": env_dict.get("agents"),
38 | "html_renderer": env_dict.get("html_renderer"),
39 | "interpreter": env_dict.get("interpreter"),
40 | "renderer": env_dict.get("renderer"),
41 | "specification": env_dict.get("specification"),
42 | })
43 | else:
44 | register(name, {
45 | "agents": getattr(env, "agents", []),
46 | "html_renderer": getattr(env, "html_renderer", None),
47 | "interpreter": getattr(env, "interpreter"),
48 | "renderer": getattr(env, "renderer"),
49 | "specification": getattr(env, "specification"),
50 | })
51 | except Exception as e:
52 | if "football" not in name:
53 | print("Loading environment %s failed: %s" % (name, e))
54 |
--------------------------------------------------------------------------------
/kaggle_environments/api.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | from typing import *
4 |
5 | base_url = "https://www.kaggle.com/requests/EpisodeService/"
6 | get_url = base_url + "GetEpisodeReplay"
7 | list_url = base_url + "ListEpisodes"
8 |
9 |
10 | def get_episode_replay(episode_id: int):
11 | body = {
12 | "EpisodeId": episode_id
13 | }
14 |
15 | response = requests.post(get_url, json=body)
16 | return response.json()
17 |
18 |
19 | def list_episodes(episode_ids: List[int]):
20 | return __list_episodes({
21 | "Ids": episode_ids
22 | })
23 |
24 |
25 | def list_episodes_for_team(team_id: int):
26 | return __list_episodes({
27 | "TeamId": team_id
28 | })
29 |
30 |
31 | def list_episodes_for_submission(submission_id: int):
32 | return __list_episodes({
33 | "SubmissionId": submission_id
34 | })
35 |
36 |
37 | def __list_episodes(body):
38 | response = requests.post(list_url, json=body)
39 | return response.json()
40 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/chess/chess.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chess",
3 | "title": "Chess",
4 | "description": "Classic Chess with full rule set",
5 | "version": "1.0.0",
6 | "agents": [2],
7 | "configuration": {
8 | "episodeSteps": 1000,
9 | "actTimeout": 0.1,
10 | "runTimeout": 300,
11 | "seed": {
12 | "description": "Integer random value to use to seed the match",
13 | "type": "number",
14 | "default": 0
15 | },
16 | "agentTimeout": {
17 | "description": "Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.",
18 | "type": "number",
19 | "minimum": 0,
20 | "default": 10
21 | }
22 | },
23 | "reward": {
24 | "description": "0 = Lost/Ongoing, 0.5 = Draw, 1 = Won",
25 | "enum": [0, 0.5, 1],
26 | "default": 0
27 | },
28 | "observation": {
29 | "board": {
30 | "description": "FEN string representation of the board",
31 | "type": "string",
32 | "shared": true,
33 | "default": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
34 | },
35 | "mark": {
36 | "description": "Player color, white or black",
37 | "defaults": ["white", "black"],
38 | "enum": ["white", "black"]
39 | },
40 | "opponentRemainingOverageTime": {
41 | "description": "Amount of overage time remaining for the opponent.",
42 | "type": "number",
43 | "default": 10
44 | },
45 | "lastMove": {
46 | "description": "Previous move to get to this position.",
47 | "type": "string",
48 | "default": ""
49 | },
50 | "remainingOverageTime": 10
51 | },
52 | "action": {
53 | "description": "Move in UCI notation (e.g., e2e4)",
54 | "type": "string",
55 | "default": ""
56 | },
57 | "status": {
58 | "defaults": ["ACTIVE", "INACTIVE"]
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/chess/test_chess.py:
--------------------------------------------------------------------------------
1 | from kaggle_environments import make
2 | from Chessnut import Game
3 | from chess import is_insufficient_material
4 |
5 | def test_chess_inits():
6 | env = make("chess", debug=True)
7 | env.run(["random", "random"])
8 | json = env.toJSON()
9 | assert json["name"] == "chess"
10 | assert json["statuses"] == ["DONE", "DONE"]
11 |
12 | def test_chess_three_fold():
13 | env = make("chess", debug=True)
14 | env.run(["king_shuffle", "king_shuffle"])
15 | json = env.toJSON()
16 | assert json["name"] == "chess"
17 | assert json["statuses"] == ["DONE", "DONE"]
18 | assert json["rewards"] == [0.5, 0.5]
19 |
20 | def test_chess_100_move_rule():
21 | env = make("chess", debug=True)
22 | env.run(["board_shuffle", "board_shuffle"])
23 | json = env.toJSON()
24 | assert json["name"] == "chess"
25 | assert json["statuses"] == ["DONE", "DONE"]
26 | assert json["rewards"] == [0.5, 0.5]
27 |
28 | def test_sufficient_material():
29 | game = Game()
30 | assert not is_insufficient_material(game.board)
31 |
32 | def test_insufficient_material_with_two_kings():
33 | game = Game('8/8/K7/8/8/3k4/8/8 w - - 58 282')
34 | assert is_insufficient_material(game.board)
35 |
36 | def test_insufficient_material_with_two_kings_and_bishop():
37 | game = Game('6k1/8/7B/8/8/8/8/2K5 b - - 90 250')
38 | assert is_insufficient_material(game.board)
39 |
40 | def test_insufficient_material_with_two_kings_and_two_knights():
41 | game = Game('6k1/8/6NN/8/8/8/8/2K5 b - - 90 250')
42 | assert is_insufficient_material(game.board)
43 |
44 | def test_sufficient_material_with_king_knight_and_bishop():
45 | game = Game('6k1/8/6NB/8/8/8/8/2K5 b - - 90 250')
46 | assert not is_insufficient_material(game.board)
47 |
48 | def test_sufficient_material_with_king_bishop_and_bishop():
49 | game = Game('6k1/8/6BB/8/8/8/8/2K5 b - - 90 250')
50 | assert not is_insufficient_material(game.board)
--------------------------------------------------------------------------------
/kaggle_environments/envs/connectx/connectx.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "connectx",
3 | "title": "ConnectX",
4 | "description": "Classic Connect in a row but configurable.",
5 | "version": "1.0.1",
6 | "agents": [2],
7 | "configuration": {
8 | "columns": {
9 | "description": "The number of columns on the board",
10 | "type": "integer",
11 | "default": 7,
12 | "minimum": 1
13 | },
14 | "rows": {
15 | "description": "The number of rows on the board",
16 | "type": "integer",
17 | "default": 6,
18 | "minimum": 1
19 | },
20 | "inarow": {
21 | "description": "The number of checkers in a row required to win.",
22 | "type": "integer",
23 | "default": 4,
24 | "minimum": 1
25 | },
26 | "agentTimeout": {
27 | "description": "Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.",
28 | "type": "number",
29 | "minimum": 0,
30 | "default": 60
31 | },
32 | "actTimeout": 2,
33 | "timeout": {
34 | "description": "Obsolete copy of actTimeout maintained for backwards compatibility. May be removed in the future.",
35 | "type": "integer",
36 | "default": 2,
37 | "minimum": 0
38 | }
39 | },
40 | "reward": {
41 | "description": "-1 = Lost, 0 = Draw/Ongoing, 1 = Won",
42 | "enum": [-1, 0, 1],
43 | "default": 0
44 | },
45 | "observation": {
46 | "board": {
47 | "description": "Serialized grid (rows x columns). 0 = Empty, 1 = P1, 2 = P2",
48 | "type": "array",
49 | "shared": true,
50 | "items": {
51 | "enum": [0, 1, 2]
52 | },
53 | "default": []
54 | },
55 | "mark": {
56 | "defaults": [1, 2],
57 | "description": "Which checkers are the agents.",
58 | "enum": [1, 2]
59 | },
60 | "remainingOverageTime": 60
61 | },
62 | "action": {
63 | "description": "Column to drop a checker onto the board.",
64 | "type": "integer",
65 | "minimum": 0,
66 | "default": 0
67 | },
68 | "status": {
69 | "defaults": ["ACTIVE", "INACTIVE"]
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/football/football.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Kaggle football example",
7 | "provenance": []
8 | },
9 | "kernelspec": {
10 | "name": "python3",
11 | "display_name": "Python 3"
12 | }
13 | },
14 | "cells": [
15 | {
16 | "cell_type": "code",
17 | "metadata": {
18 | "id": "edvwsjsJsAQY",
19 | "colab_type": "code",
20 | "colab": {}
21 | },
22 | "source": [
23 | "## Installing kaggle-environments.\n",
24 | "!pip install kaggle-environments\n",
25 | "\n",
26 | "# 4. Import register to define the environment and make to create it.\n",
27 | "from kaggle_environments import make, register"
28 | ],
29 | "execution_count": 0,
30 | "outputs": []
31 | },
32 | {
33 | "cell_type": "code",
34 | "metadata": {
35 | "id": "dWXjFxmDsiVb",
36 | "colab_type": "code",
37 | "colab": {}
38 | },
39 | "source": [
40 | "# Installing Google Football environment.\n",
41 | "\n",
42 | "!apt-get update\n",
43 | "!apt-get install -y libsdl2-gfx-dev libsdl2-ttf-dev\n",
44 | "\n",
45 | "# Make sure that the Branch in git clone and in wget call matches !!\n",
46 | "!git clone -b v2.3 https://github.com/google-research/football.git\n",
47 | "!mkdir -p football/third_party/gfootball_engine/lib\n",
48 | "\n",
49 | "!wget https://storage.googleapis.com/gfootball/prebuilt_gameplayfootball_v2.3.so -O football/third_party/gfootball_engine/lib/prebuilt_gameplayfootball.so\n",
50 | "!cd football && GFOOTBALL_USE_PREBUILT_SO=1 pip3 install ."
51 | ],
52 | "execution_count": 0,
53 | "outputs": []
54 | },
55 | {
56 | "cell_type": "code",
57 | "metadata": {
58 | "id": "4URn2BRvs3qL",
59 | "colab_type": "code",
60 | "colab": {}
61 | },
62 | "source": [
63 | "env = make(\"football\", debug=True, configuration={\"scenario_name\": \"11_vs_11_kaggle\", \"team_1\": 1, \"team_2\": 1, \"running_in_notebook\": True, \"save_video\": True})\n",
64 | "print(env.name, env.version)\n",
65 | "print(\"Default Agents: \", *env.agents)\n",
66 | "\n",
67 | "env.run([\"run_right\", \"run_left\"])\n",
68 | " \n",
69 | "env.render(mode=\"html\", width=960, height=720)"
70 | ],
71 | "execution_count": 0,
72 | "outputs": []
73 | }
74 | ]
75 | }
76 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/football/football.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "football",
3 | "agents": [2],
4 | "configuration": {
5 | "episodeSteps": 3002,
6 | "agentTimeout": {
7 | "description": "Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.",
8 | "type": "number",
9 | "minimum": 0,
10 | "default": 60
11 | },
12 | "actTimeout": 0.5,
13 | "runTimeout": 12000,
14 | "scenario_name": {
15 | "description": "Name of the scenario: for example 11_vs_11_kaggle. Look inside https://github.com/google-research/football/tree/master/gfootball/scenarios.",
16 | "type": "string",
17 | "default": "11_vs_11_kaggle"
18 | },
19 | "id": {
20 | "description": "Id of this environment run, a random uuid.",
21 | "type": "string",
22 | "default": null
23 | },
24 | "team_1": {
25 | "description": "Number of players from the first team that agent controls.",
26 | "type": "integer",
27 | "minimum": 0,
28 | "maximum": 11,
29 | "default": 1
30 | },
31 | "team_2": {
32 | "description": "Number of players that other agent controls. If set to 0 - the second agent will always have to return 0 as action.",
33 | "type": "integer",
34 | "minimum": 0,
35 | "maximum": 11,
36 | "default": 1
37 | },
38 | "render": {
39 | "description": "If true - renders the game on the screen. This option will work on your local computer, but is not supported in colabs/notebooks.",
40 | "type": "boolean",
41 | "default": false
42 | },
43 | "save_video": {
44 | "description": "If true, will record the video of the playthrough.",
45 | "type": "boolean",
46 | "default": false
47 | },
48 | "logdir": {
49 | "description": "Directory to write the state dump and video information.",
50 | "type": "string",
51 | "default": "/tmp/football"
52 | },
53 | "running_in_notebook": {
54 | "description": "Set to true, if you're creating this environment inside Kaggle/Colab notebook.",
55 | "type": "boolean",
56 | "default": false
57 | }
58 | },
59 | "reward": {
60 | "description": "1.0 for scored goal, -1.0 for lost goal (it is given only when the goal is scored, and changes back to 0 afterwards)",
61 | "type": "number"
62 | },
63 | "info": {
64 | "debug_info": {
65 | "description": "Human readable information passed from the system.",
66 | "type": "string"
67 | }
68 | },
69 | "observation": {
70 | "players_raw": {
71 | "description": "Array of raw observations, one entry per each player that your agent controls. See https://github.com/google-research/football/blob/master/gfootball/doc/observation.md for detailed description. WARNING: your players will always look like they are 'playing from left to right' (to make training easier).",
72 | "type": "array"
73 | },
74 | "controlled_players": {
75 | "description": "number of players that agent controls",
76 | "type": "number",
77 | "minimum": 0,
78 | "maximum": 11
79 | },
80 | "remainingOverageTime": 60
81 | },
82 | "action": {
83 | "description": "An action to execute for each player that agent controls: 0-idle, 1-left, 2-top_left, etc. See https://github.com/google-research/football/blob/master/gfootball/doc/observation.md",
84 | "type": "array",
85 | "items": {
86 | "type": "number",
87 | "minimum": 0,
88 | "maximum": 19
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/football/helpers.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 | from enum import Enum
3 | from typing import *
4 |
5 |
6 | class Action(Enum):
7 | Idle = 0
8 | Left = 1
9 | TopLeft = 2
10 | Top = 3
11 | TopRight = 4
12 | Right = 5
13 | BottomRight = 6
14 | Bottom = 7
15 | BottomLeft = 8
16 | LongPass= 9
17 | HighPass = 10
18 | ShortPass = 11
19 | Shot = 12
20 | Sprint = 13
21 | ReleaseDirection = 14
22 | ReleaseSprint = 15
23 | Slide = 16
24 | Dribble = 17
25 | ReleaseDribble = 18
26 |
27 |
28 | sticky_index_to_action = [
29 | Action.Left,
30 | Action.TopLeft,
31 | Action.Top,
32 | Action.TopRight,
33 | Action.Right,
34 | Action.BottomRight,
35 | Action.Bottom,
36 | Action.BottomLeft,
37 | Action.Sprint,
38 | Action.Dribble
39 | ]
40 |
41 |
42 | class PlayerRole(Enum):
43 | GoalKeeper = 0
44 | CenterBack = 1
45 | LeftBack = 2
46 | RightBack = 3
47 | DefenceMidfield = 4
48 | CentralMidfield = 5
49 | LeftMidfield = 6
50 | RIghtMidfield = 7
51 | AttackMidfield = 8
52 | CentralFront = 9
53 |
54 |
55 | class GameMode(Enum):
56 | Normal = 0
57 | KickOff = 1
58 | GoalKick = 2
59 | FreeKick = 3
60 | Corner = 4
61 | ThrowIn = 5
62 | Penalty = 6
63 |
64 |
65 | def human_readable_agent(agent: Callable[[Dict], Action]):
66 | """
67 | Decorator allowing for more human-friendly implementation of the agent function.
68 |
69 | @human_readable_agent
70 | def my_agent(obs):
71 | ...
72 | return football_action_set.action_right
73 | """
74 | @wraps(agent)
75 | def agent_wrapper(obs) -> List[int]:
76 | # Extract observations for the first (and only) player we control.
77 | obs = obs['players_raw'][0]
78 | # Turn 'sticky_actions' into a set of active actions (strongly typed).
79 | obs['sticky_actions'] = { sticky_index_to_action[nr] for nr, action in enumerate(obs['sticky_actions']) if action }
80 | # Turn 'game_mode' into an enum.
81 | obs['game_mode'] = GameMode(obs['game_mode'])
82 | # In case of single agent mode, 'designated' is always equal to 'active'.
83 | if 'designated' in obs:
84 | del obs['designated']
85 | # Conver players' roles to enum.
86 | obs['left_team_roles'] = [ PlayerRole(role) for role in obs['left_team_roles'] ]
87 | obs['right_team_roles'] = [ PlayerRole(role) for role in obs['right_team_roles'] ]
88 |
89 | action = agent(obs)
90 | return [action.value]
91 |
92 | return agent_wrapper
93 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/halite/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/halite/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/hungry_geese/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/hungry_geese/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/hungry_geese/hungry_geese.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hungry_geese",
3 | "title": "Hungry Geese",
4 | "description": "Similar to the classic snake game with multiple players",
5 | "version": "1.0.0",
6 | "agents": [1, 2, 3, 4, 5, 6, 7, 8],
7 | "configuration": {
8 | "episodeSteps": 200,
9 | "actTimeout": 1,
10 | "columns": {
11 | "description": "Horizontal number of cells on the board.",
12 | "type": "integer",
13 | "default": 11,
14 | "minimum": 3
15 | },
16 | "rows": {
17 | "description": "Vertical number of cells on the board.",
18 | "type": "integer",
19 | "default": 7,
20 | "minimum": 3
21 | },
22 | "hunger_rate": {
23 | "description": "The number of steps before the goose shrinks a cell.",
24 | "type": "integer",
25 | "minimum": 1,
26 | "default": 40
27 | },
28 | "min_food": {
29 | "description": "The minimum amount of food present for all steps.",
30 | "type": "integer",
31 | "default": 2,
32 | "minimum": 1
33 | },
34 | "max_length": {
35 | "description": "The max length any goose can be. Total reward = (max length + 1) * steps survived + goose length.",
36 | "type": "integer",
37 | "default": 99
38 | }
39 | },
40 | "reward": {
41 | "description": "steps survived * (max goose length + 1) + current goose length.",
42 | "type": "integer",
43 | "default": 0,
44 | "minimum": 0
45 | },
46 | "observation": {
47 | "geese": {
48 | "description": "List of geese in order by the agent index.",
49 | "type": "array",
50 | "default": [],
51 | "shared": true,
52 | "items": {
53 | "description": "A goose represented by positions on the board.",
54 | "type": "array",
55 | "items": {
56 | "description": "A position of a goose with the 0 position representing the head.",
57 | "type": "integer",
58 | "minimum": 0
59 | }
60 | }
61 | },
62 | "food": {
63 | "description": "Positions on the board where food is present.",
64 | "type": "array",
65 | "default": [],
66 | "shared": true,
67 | "items": {
68 | "type": "integer",
69 | "minimum": 0
70 | }
71 | },
72 | "index": {
73 | "description": "Index of the current agent's goose in the list of geese.",
74 | "type": "integer",
75 | "minimum": 0,
76 | "defaults": [0, 1, 2, 3, 4, 5, 6, 7]
77 | },
78 | "remainingOverageTime": 60
79 | },
80 | "action": {
81 | "description": "Direction to move the head of your players goose.",
82 | "type": "string",
83 | "enum": ["NORTH", "EAST", "SOUTH", "WEST"],
84 | "default": "NORTH"
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/hungry_geese/test_hungry_geese.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/hungry_geese/test_hungry_geese.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/identity/identity.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "identity",
3 | "title": "Identity",
4 | "description": "Used for debugging. Agent action is set as their reward.",
5 | "version": "1.0.0",
6 | "agents": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
7 | "configuration": {
8 | "max": {
9 | "description": "The highest number allowed for an action.",
10 | "type": "integer",
11 | "default": 1000,
12 | "minimum": 1
13 | },
14 | "min": {
15 | "description": "The lowest number allowed for an action.",
16 | "type": "integer",
17 | "default": 0,
18 | "minimum": 0
19 | },
20 | "noise": {
21 | "description": "Noise added to the reward.",
22 | "type": "number",
23 | "default": 0
24 | },
25 | "actTimeout": 1,
26 | "episodeSteps": 25
27 | },
28 | "reward": {
29 | "description": "The value of the agent action is set as: action + gauss * noise.",
30 | "type": "integer"
31 | },
32 | "observation": {
33 | "remainingOverageTime": 12
34 | },
35 | "action": {
36 | "description": "Reward = action if number, otherwise 0.",
37 | "type": ["number", "string", "null"]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/identity/identity.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 Kaggle Inc
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import json
16 | import time
17 | from os import path
18 | from random import choice, gauss
19 |
20 |
21 | def random_agent(obs, config):
22 | return choice(range(config.min, config.max))
23 |
24 |
25 | def max_agent(obs, config):
26 | return config.max
27 |
28 |
29 | def min_agent(obs, config):
30 | return config.min
31 |
32 |
33 | def avg_agent(obs, config):
34 | return (config.min + config.max) // 2
35 |
36 |
37 | def timeout_agent(obs, config):
38 | time.sleep(config.actTimeout + obs.remainingOverageTime / 2)
39 | return random_agent(obs, config)
40 |
41 |
42 | agents = {
43 | "random": random_agent,
44 | "max": max_agent,
45 | "min": min_agent,
46 | "avg": avg_agent,
47 | "timeout": timeout_agent,
48 | }
49 |
50 |
51 | def interpreter(state, env):
52 | if env.done:
53 | return state
54 |
55 | # Validate and assign actions as rewards !(min <= action <= max).
56 | for agent in state:
57 | value = 0
58 | if isinstance(agent.action, (int, float)):
59 | value = agent.action
60 | if value < env.configuration.min or value > env.configuration.max:
61 | agent.status = f"Invalid action: {value}"
62 | else:
63 | agent.reward += value + \
64 | gauss(0, 1) * env.configuration.noise // 1
65 |
66 | if len(env.steps) >= env.configuration.episodeSteps:
67 | for agent in state:
68 | agent.status = "DONE"
69 |
70 | return state
71 |
72 |
73 | def renderer(state, env):
74 | return json.dumps([{"action": a.action, "reward": a.reward} for a in state])
75 |
76 |
77 | def html_renderer(state, env):
78 | return ""
79 |
80 |
81 | dirpath = path.dirname(__file__)
82 | jsonpath = path.abspath(path.join(dirpath, "identity.json"))
83 | with open(jsonpath) as f:
84 | specification = json.load(f)
85 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/kore_fleets/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/kore_fleets.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Kore - Kaggle Environment"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": null,
13 | "metadata": {
14 | "scrolled": true
15 | },
16 | "outputs": [],
17 | "source": [
18 | "!pip install ../../.."
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": null,
24 | "metadata": {},
25 | "outputs": [],
26 | "source": [
27 | "from kaggle_environments import make\n",
28 | "env = make(\"kore_fleets\")\n",
29 | "print(env.name, env.version)\n",
30 | "print(\"Default Agents: \", *env.agents)"
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "## TLDR;"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {
44 | "scrolled": false
45 | },
46 | "outputs": [],
47 | "source": [
48 | "env = make(\"kore_fleets\", debug=True)\n",
49 | "env.run([\"simp\", \"simp\", \"simp\", \"simp\"])\n",
50 | "#env.run([\"simp\", \"random\", \"random\", \"random\"])\n",
51 | "#env.run([\"simple\", \"simple\"])\n",
52 | "env.render(mode=\"ipython\", width=970, height=800)"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "## Specification"
60 | ]
61 | },
62 | {
63 | "cell_type": "code",
64 | "execution_count": null,
65 | "metadata": {
66 | "scrolled": false
67 | },
68 | "outputs": [],
69 | "source": [
70 | "import json\n",
71 | "print(\"Configuration:\", json.dumps(env.specification.configuration, indent=4, sort_keys=True))\n",
72 | "print(\"Observation:\", json.dumps(env.specification.observation, indent=4, sort_keys=True))\n",
73 | "print(\"Action:\", json.dumps(env.specification.action, indent=4, sort_keys=True))"
74 | ]
75 | },
76 | {
77 | "cell_type": "code",
78 | "execution_count": null,
79 | "metadata": {},
80 | "outputs": [],
81 | "source": []
82 | },
83 | {
84 | "cell_type": "code",
85 | "execution_count": null,
86 | "metadata": {},
87 | "outputs": [],
88 | "source": []
89 | }
90 | ],
91 | "metadata": {
92 | "kernelspec": {
93 | "display_name": "Python 3",
94 | "language": "python",
95 | "name": "python3"
96 | },
97 | "language_info": {
98 | "codemirror_mode": {
99 | "name": "ipython",
100 | "version": 3
101 | },
102 | "file_extension": ".py",
103 | "mimetype": "text/x-python",
104 | "name": "python",
105 | "nbconvert_exporter": "python",
106 | "pygments_lexer": "ipython3",
107 | "version": "3.9.9"
108 | }
109 | },
110 | "nbformat": 4,
111 | "nbformat_minor": 2
112 | }
113 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/Bot.java:
--------------------------------------------------------------------------------
1 | import java.util.Scanner;
2 | import java.util.Map.Entry;
3 |
4 | import kore.*;
5 |
6 | public class Bot {
7 | private final static Scanner scanner = new Scanner(System.in);
8 | public static void main(final String[] args) throws Exception {
9 | while (true) {
10 | /** Do not edit! **/
11 | String rawObservation = scanner.nextLine();
12 | String rawConfiguration = scanner.nextLine();
13 | Board board = new Board(rawObservation, rawConfiguration);
14 | /** end do not edit */
15 |
16 | Player me = board.currentPlayer();
17 | int turn = board.step;
18 | int spawnCost = board.configuration.spawnCost;
19 | double koreLeft = me.kore;
20 |
21 | for (Shipyard shipyard : me.shipyards()) {
22 | if (shipyard.shipCount > 10) {
23 | Direction dir = Direction.fromIndex(turn % 4);
24 | ShipyardAction action = ShipyardAction.launchFleetWithFlightPlan(2, dir.toChar());
25 | shipyard.setNextAction(action);
26 | } else if (koreLeft > spawnCost * shipyard.maxSpawn()) {
27 | ShipyardAction action = ShipyardAction.spawnShips(shipyard.maxSpawn());
28 | shipyard.setNextAction(action);
29 | koreLeft -= spawnCost * shipyard.maxSpawn();
30 | } else if (koreLeft > spawnCost) {
31 | ShipyardAction action = ShipyardAction.spawnShips(1);
32 | shipyard.setNextAction(action);
33 | koreLeft -= spawnCost;
34 | }
35 | }
36 |
37 | /** AI Code Goes Above! **/
38 |
39 | /** Do not edit! **/
40 | StringBuilder commandBuilder = new StringBuilder("");
41 | boolean first = true;
42 | for (Entry entry : board.currentPlayer().nextActions().entrySet()) {
43 | if (first) {
44 | first = false;
45 | } else {
46 | commandBuilder.append(",");
47 | }
48 | commandBuilder.append(String.format("%s:%s", entry.getKey(), entry.getValue().toString()));
49 | }
50 | System.out.println(commandBuilder.toString());
51 | System.out.flush();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/README.md:
--------------------------------------------------------------------------------
1 | # Kore Fleets Java Bot
2 |
3 | ## Running locally
4 |
5 | 1. compile your bot with `javac Bot.java`
6 | 2. run a match with `kaggle-environments run --environment kore_fleets --agents ./main.py ./main.py`
7 |
8 | * where `./main.py` is the relative path from your current working directory to your bot's `main.py` file
9 | * 1, 2, or 4 agents are supported
10 | ## Watching a replay locally
11 | 1. compile your bot with `javac Bot.java`
12 | 2. run a match with `kaggle-environments run --environment kore_fleets --agents ./main.py ./main.py --log out.log --out replay.html --render '{"mode": "html"}'`
13 | 3. open `replay.html` with your browser of choice!
14 |
15 |
16 | ## Creating a submission
17 |
18 | 1. compile your both with `javac Bot.java`
19 | 2. create a tar.gz with `tar --exclude='test' --exclude='jars' -czvf submission.tar.gz *`
20 |
21 | note you must do this in the same directory as `main.py`!
22 |
23 | ## Running tests
24 |
25 | 1. Add the jars/ to visual studio as described [here](https://stackoverflow.com/questions/50232557/visual-studio-code-java-extension-howto-add-jar-to-classpath)
26 | 2. Run tests!
27 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/jars/hamcrest-core-1.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/kore_fleets/starter_bots/java/jars/hamcrest-core-1.3.jar
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/jars/junit-4.13.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/kore_fleets/starter_bots/java/jars/junit-4.13.2.jar
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Cell.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | import java.util.Optional;
4 |
5 | public class Cell {
6 |
7 | public final Point position;
8 | public double kore;
9 | public String shipyardId;
10 | public String fleetId;
11 | public final Board board;
12 |
13 | public Cell(Point position, double kore, String shipyardId, String fleetId, Board board) {
14 | this.position = position;
15 | this.kore = kore;
16 | this.shipyardId = shipyardId;
17 | this.fleetId = fleetId;
18 | this.board = board;
19 | }
20 |
21 | public Cell cloneToBoard(Board board) {
22 | return new Cell(this.position, this.kore, this.shipyardId, this.fleetId, board);
23 | }
24 |
25 | public Optional fleet() {
26 | if (this.board.fleets.containsKey(this.fleetId)) {
27 | return Optional.of(this.board.fleets.get(this.fleetId));
28 | }
29 | return Optional.empty();
30 | }
31 |
32 |
33 | public Optional shipyard() {
34 | if (this.board.shipyards.containsKey(this.shipyardId)) {
35 | return Optional.of(this.board.shipyards.get(this.shipyardId));
36 | }
37 | return Optional.empty();
38 | }
39 |
40 | public Cell neighbor(Point offset) {
41 | Point next = this.position.translate(offset, this.board.size);
42 | return this.board.getCellAtPosition(next);
43 | }
44 |
45 |
46 | public Cell north() {
47 | return this.neighbor(Direction.NORTH);
48 | }
49 |
50 | public Cell south() {
51 | return this.neighbor(((Point)Direction.SOUTH));
52 | }
53 |
54 | public Cell east() {
55 | return this.neighbor(Direction.EAST);
56 | }
57 |
58 | public Cell west() {
59 | return this.neighbor(Direction.WEST);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Configuration.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | public class Configuration {
4 |
5 | public final int agentTimeout;
6 | public final int startingKore;
7 | public final int size;
8 | public final double spawnCost;
9 | public final int convertCost;
10 | public final double regenRate;
11 | public final int maxRegenCellKore;
12 | public final int randomSeed;
13 |
14 | public Configuration(String rawConfiguration) {
15 | this.agentTimeout = KoreJson.getIntFromJson(rawConfiguration, "agentTimeout");
16 | this.startingKore = KoreJson.getIntFromJson(rawConfiguration, "startingKore");
17 | this.size = KoreJson.getIntFromJson(rawConfiguration, "size");
18 | this.spawnCost = KoreJson.getDoubleFromJson(rawConfiguration, "spawnCost");
19 | this.convertCost = KoreJson.getIntFromJson(rawConfiguration, "convertCost");
20 | this.regenRate = KoreJson.getDoubleFromJson(rawConfiguration, "regenRate");
21 | this.maxRegenCellKore = KoreJson.getIntFromJson(rawConfiguration, "maxRegenCellKore");
22 | this.randomSeed = KoreJson.getIntFromJson(rawConfiguration, "randomSeed");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Fleet.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | public class Fleet {
4 |
5 | public final String id;
6 | public int shipCount;
7 | public Direction direction;
8 | public Point position;
9 | public String flightPlan;
10 | public double kore;
11 | public final int playerId;
12 | public final Board board;
13 |
14 | public Fleet(String fleetId, int shipCount, Direction direction, Point position, double kore, String flightPlan, int playerId, Board board) {
15 | this.id = fleetId;
16 | this.shipCount = shipCount;
17 | this.direction = direction;
18 | this.position = position;
19 | this.flightPlan = flightPlan;
20 | this.kore = kore;
21 | this.playerId = playerId;
22 | this.board = board;
23 | }
24 |
25 | public Fleet cloneToBoard(Board board) {
26 | return new Fleet(this.id, this.shipCount, this.direction, this.position, this.kore, this.flightPlan, this.playerId, board);
27 | }
28 |
29 | public Cell cell() {
30 | return this.board.getCellAtPosition(this.position);
31 | }
32 |
33 | public Player player() {
34 | return this.board.players[this.playerId];
35 | }
36 |
37 | public double collectionRate() {
38 | return Math.min(Math.log(this.shipCount) / 10, .99);
39 | }
40 |
41 | /**
42 | * Returns the length of the longest possible flight plan this fleet can be assigned
43 | * @return
44 | */
45 | public static int maxFlightPlanLenForShipCount(int shipCount) {
46 | return (int) (Math.floor(2 * Math.log(shipCount)) + 1);
47 | }
48 |
49 | /**
50 | * Converts a fleet back to the normalized observation subset that constructed it.
51 | */
52 | public String[] observation() {
53 | return new String[]{
54 | String.valueOf(this.position.toIndex(this.board.configuration.size)),
55 | String.valueOf(this.kore),
56 | String.valueOf(this.shipCount),
57 | String.valueOf(this.direction.toIndex()),
58 | this.flightPlan
59 | };
60 | }
61 |
62 | public boolean lessThanOtherAlliedFleet(Fleet other) {
63 | if (this.shipCount != other.shipCount) {
64 | return this.shipCount < other.shipCount;
65 | }
66 | if (this.kore != other.kore) {
67 | return this.kore < other.kore;
68 | }
69 | return this.direction.toIndex() > other.direction.toIndex();
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Observation.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.HashMap;
6 |
7 | public class Observation {
8 | public final double[] kore;
9 | public final double[] playerHlt;
10 | public final ArrayList> playerShipyards;
11 | public final ArrayList> playerFleets;
12 | public final int player;
13 | public final int step;
14 | public final double remainingOverageTime;
15 |
16 | private static String shortenFrontAndBack(String target, int n) {
17 | return target.substring(n, target.length() - n);
18 | }
19 |
20 | public Observation(String rawObservation) {
21 | // avoid importing json library? worth it?
22 | this.kore = KoreJson.getDoubleArrFromJson(rawObservation, "kore");
23 | this.player = KoreJson.getPlayerIdxFromJson(rawObservation);
24 | this.step = KoreJson.getIntFromJson(rawObservation, "step");
25 | this.remainingOverageTime = KoreJson.getDoubleFromJson(rawObservation, "remainingOverageTime");
26 | String[] playerParts = KoreJson.getPlayerPartsFromJson(rawObservation);
27 | playerHlt = new double[playerParts.length];
28 | playerShipyards = new ArrayList>();
29 | playerFleets = new ArrayList>();
30 |
31 | for (int i = 0; i < playerParts.length; i ++) {
32 | String playerPart = playerParts[i];
33 | playerHlt[i] = Double.parseDouble(playerPart.split(", ")[0]);
34 |
35 | int startShipyards = playerPart.indexOf("{");
36 | int endShipyards = playerPart.indexOf("}");
37 | String shipyardsStr = playerPart.substring(startShipyards + 1, endShipyards - 1);
38 | HashMap shipyards = new HashMap();
39 | Arrays.stream(shipyardsStr.split("], ")).forEach(shipyardStr -> {
40 | if (shipyardStr.length() == 0) {
41 | return;
42 | }
43 | String[] kvparts = shipyardStr.split(": \\[");
44 | String shipyardId = shortenFrontAndBack(kvparts[0], 1);
45 | String[] shipyardStrs = kvparts[1].split(", ");
46 | int[] shipyard = new int[shipyardStrs.length];
47 | Integer[] shipyardInts = Arrays.stream(shipyardStrs).map(s -> Integer.parseInt(s)).toArray(Integer[]::new);
48 | for(int j = 0; j < shipyard.length; j++) {
49 | shipyard[j] = shipyardInts[j];
50 | }
51 | shipyards.put(shipyardId, shipyard);
52 | });
53 | playerShipyards.add(shipyards);
54 |
55 | int startFleets = playerPart.indexOf("}, ");
56 | String fleetsStr = playerPart.substring(startFleets + 4, playerPart.length() - 1);
57 | HashMap fleets = new HashMap<>();
58 | Arrays.stream(fleetsStr.split("], ")).forEach(fleetStr -> {
59 | if (fleetStr.length() == 0) {
60 | return;
61 | }
62 | String[] kvparts = fleetStr.split(": ");
63 | String fleetId = shortenFrontAndBack(kvparts[0], 1);
64 | String[] fleet = shortenFrontAndBack(kvparts[1], 1).split(", ");
65 | fleets.put(fleetId, fleet);
66 | });
67 | playerFleets.add(fleets);
68 | }
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Pair.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | public class Pair {
4 |
5 | public final F first;
6 | public final S second;
7 |
8 | public Pair(F first, S second) {
9 | this.first = first;
10 | this.second = second;
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Player.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.HashMap;
6 | import java.util.stream.Collectors;
7 |
8 | public class Player {
9 | public final int id;
10 | public double kore;
11 | public final ArrayList shipyardIds;
12 | public final ArrayList fleetIds;
13 | public final Board board;
14 |
15 | public Player(int playerId, double kore, ArrayList shipyardIds, ArrayList fleetIds, Board board) {
16 | this.id = playerId;
17 | this.kore = kore;
18 | this.shipyardIds = shipyardIds;
19 | this.fleetIds = fleetIds;
20 | this.board = board;
21 | }
22 |
23 | public Player cloneToBoard(Board board) {
24 | return new Player(this.id, this.kore, new ArrayList(this.shipyardIds.stream().collect(Collectors.toList())), new ArrayList(this.fleetIds.stream().collect(Collectors.toList())), board);
25 | }
26 |
27 | /**
28 | * Returns all shipyards owned by this player.
29 | * @return
30 | */
31 | public Shipyard[] shipyards() {
32 | return this.board.shipyards.values().stream().filter(shipyard -> this.shipyardIds.stream().anyMatch(sId -> sId == shipyard.id)).toArray(Shipyard[]::new);
33 | }
34 |
35 | /**
36 | * Returns all fleets owned by this player.
37 | */
38 | public Fleet[] fleets() {
39 | return this.board.fleets.values().stream().filter(fleet -> this.fleetIds.stream().anyMatch(fId -> fId == fleet.id)).toArray(Fleet[]::new);
40 | }
41 |
42 | /**
43 | * Returns whether this player is the current player (generally if this returns True, this player is you.
44 | */
45 | public boolean isCurrentPlayer() {
46 | return this.id == this.board.currentPlayerId;
47 | }
48 |
49 | /**
50 | * Returns all queued fleet and shipyard actions for this player formatted for the kore interpreter to receive as an agent response.
51 | */
52 | public HashMap nextActions() {
53 | HashMap result = new HashMap<>();
54 | Arrays.stream(this.shipyards()).filter(shipyard -> shipyard.nextAction.isPresent()).forEach(shipyard -> result.put(shipyard.id, shipyard.nextAction.get()));
55 | return result;
56 | }
57 |
58 | /**
59 | * Converts a player back to the normalized observation subset that constructed it.
60 | */
61 | public Object[] observation() {
62 | HashMap shipyards = new HashMap<>();
63 | Arrays.stream(this.shipyards()).forEach(shipyard -> shipyards.put(shipyard.id, shipyard.observation()));
64 | HashMap fleets = new HashMap<>();
65 | Arrays.stream(this.fleets()).forEach(fleet -> fleets.put(fleet.id, fleet.observation()));
66 | return new Object[]{this.kore, shipyards, fleets};
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Point.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | public class Point {
4 | public final int x, y;
5 |
6 | public Point(int x, int y) {
7 | this.x = x;
8 | this.y = y;
9 | }
10 |
11 | public Point translate(Point offset, int size) {
12 | return this.add(offset).mod(size);
13 | }
14 |
15 | public Point add(Point other) {
16 | return new Point(this.x + other.x, this.y + other.y);
17 | }
18 |
19 | public Point mod(int size) {
20 | return new Point(this.x % size, this.y % size);
21 | }
22 |
23 | /**
24 | * Gets the manhatten distance between two points
25 | */
26 | public int distanceTo(Point other, int size) {
27 | int abs_x = Math.abs(this.x - other.x);
28 | int dist_x = abs_x < size/2 ? abs_x : size - abs_x;
29 | int abs_y = Math.abs(this.y - other.y);
30 | int dist_y = abs_y < size/2 ? abs_y : size - abs_y;
31 | return dist_x + dist_y;
32 | }
33 |
34 | /**
35 | * Converts a 2d position in the form (x, y) to an index in the observation.kore list.
36 | * See fromIndex for the inverse.
37 | */
38 | public int toIndex(int size) {
39 | return (size - this.y - 1) * size + this.x;
40 | }
41 |
42 | public static Point fromIndex(int index, int size) {
43 | return new Point(index % size, size - index/size - 1);
44 | }
45 |
46 | public Point abs() {
47 | return new Point(Math.abs(this.x), Math.abs(this.y));
48 | }
49 |
50 | public boolean equals(Point other) {
51 | return this.x == other.x && this.y == other.y;
52 | }
53 |
54 | public String toString() {
55 | return "(" + this.x + "," + this.y + ")";
56 | }
57 |
58 | public Point multiply(int factor) {
59 | return new Point(factor * this.x, factor * this.y);
60 | }
61 |
62 | public Point subtract(Point other) {
63 | return new Point(this.x - other.x, this.y - other.y);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Shipyard.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | import java.util.Optional;
4 |
5 | public class Shipyard {
6 | public final String id;
7 | public int shipCount;
8 | public Point position;
9 | public int playerId;
10 | public int turnsControlled;
11 | public final Board board;
12 | public Optional nextAction;
13 | private final int[] SPAWN_VALUES;
14 |
15 | public Shipyard(String shipyardId, int shipCount, Point position, int playerId, int turnsControlled, Board board, Optional nextAction) {
16 | this.id = shipyardId;
17 | this.shipCount = shipCount;
18 | this.position = position;
19 | this.playerId = playerId;
20 | this.turnsControlled = turnsControlled;
21 | this.board = board;
22 | this.nextAction = nextAction;
23 |
24 | int[] upgradeTimes = new int[9];
25 | for(int i = 1; i < 10; i++) {
26 | upgradeTimes[i-1] = (int) Math.pow(i, 2) + 1;
27 | }
28 | SPAWN_VALUES = new int[9];
29 | int current = 0;
30 | for(int i = 1; i < 10; i++) {
31 | current += upgradeTimes[i-1];
32 | SPAWN_VALUES[i-1] = current;
33 | }
34 | }
35 |
36 | public Shipyard cloneToBoard(Board board) {
37 | return new Shipyard(this.id, this.shipCount, this.position, this.playerId, this.turnsControlled, board, this.nextAction);
38 | }
39 |
40 | public void setNextAction(ShipyardAction action) {
41 | this.nextAction = Optional.of(action);
42 | }
43 |
44 | public int maxSpawn() {
45 | for (int i = 0; i < this.SPAWN_VALUES.length; i++) {
46 | if (this.turnsControlled < this.SPAWN_VALUES[i]) {
47 | return i + 1;
48 | }
49 | }
50 | return this.SPAWN_VALUES.length + 1;
51 | }
52 |
53 | /**
54 | * Returns the cell this shipyard is on.
55 | */
56 | public Cell cell() {
57 | return this.board.getCellAtPosition(this.position);
58 | }
59 |
60 | public Player player() {
61 | return this.board.players[this.playerId];
62 | }
63 |
64 | /**
65 | * Converts a shipyard back to the normalized observation subset that constructed it.
66 | */
67 | public int[] observation() {
68 | return new int[]{this.position.toIndex(this.board.configuration.size), this.shipCount, this.turnsControlled};
69 | }
70 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/kore/ShipyardAction.java:
--------------------------------------------------------------------------------
1 | package kore;
2 |
3 | public class ShipyardAction {
4 | public static final String SPAWN = "SPAWN";
5 | public static final String LAUNCH = "LAUNCH";
6 | public final String actionType;
7 | public final int shipCount;
8 | public final String flightPlan;
9 |
10 | public static ShipyardAction spawnShips(int shipCount) {
11 | return new ShipyardAction(SPAWN, shipCount, "");
12 | }
13 |
14 | public static ShipyardAction launchFleetWithFlightPlan(int shipCount, String flightPlan) {
15 | return new ShipyardAction(LAUNCH, shipCount, flightPlan);
16 | }
17 |
18 | public static ShipyardAction fromString(String raw) {
19 | if (raw.length() == 0) {
20 | throw new IllegalStateException("invalid raw shipyard empty string");
21 | }
22 | int shipCount = Integer.parseInt(raw.split("_")[1]);
23 | if (raw.startsWith(LAUNCH)) {
24 | return ShipyardAction.spawnShips(shipCount);
25 | }
26 | if (raw.startsWith(SPAWN)) {
27 | String flightPlan = raw.split("_")[2];
28 | return ShipyardAction.launchFleetWithFlightPlan(shipCount, flightPlan);
29 | }
30 | throw new IllegalStateException("invalid Shipyard Action raw " + raw);
31 | }
32 |
33 | public ShipyardAction(String type, int shipCount, String flightPlan) {
34 | assert type.equals(SPAWN) || type.equals(LAUNCH) : "Type must be SPAWN or LAUNCH";
35 | assert shipCount >= 0 : "numShips must be a non-negative number";
36 | this.actionType = type;
37 | this.shipCount = shipCount;
38 | this.flightPlan = flightPlan;
39 | }
40 |
41 | private boolean isSpawn() {
42 | return this.actionType.equals(SPAWN);
43 | }
44 |
45 | private boolean isLaunch() {
46 | return this.actionType.equals(LAUNCH);
47 | }
48 |
49 | public String toString() {
50 | if (this.isSpawn()) {
51 | return String.format("%s_%d", SPAWN, this.shipCount);
52 | }
53 | if (this.isLaunch()) {
54 | return String.format("%s_%d_%s", LAUNCH, this.shipCount, this.flightPlan);
55 | }
56 | throw new IllegalStateException("invalid Shpyard Action");
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/main.py:
--------------------------------------------------------------------------------
1 | from subprocess import Popen, PIPE
2 | from threading import Thread
3 | from queue import Queue, Empty
4 |
5 | import atexit
6 | import os
7 | import sys
8 | agent_processes = [None, None, None, None]
9 | t = None
10 | q = None
11 | def cleanup_process():
12 | global agent_processes
13 | for proc in agent_processes:
14 | if proc is not None:
15 | proc.kill()
16 | def enqueue_output(out, queue):
17 | for line in iter(out.readline, b''):
18 | queue.put(line)
19 | out.close()
20 |
21 | def agent(observation, configuration):
22 | global agent_processes, t, q
23 |
24 | agent_process = agent_processes[observation.player]
25 | ### Do not edit ###
26 | if agent_process is None:
27 | if "__raw_path__" in configuration:
28 | cwd = os.path.dirname(configuration["__raw_path__"])
29 | else:
30 | cwd = os.path.dirname(__file__)
31 | agent_process = Popen(['java', 'Bot'], stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=cwd)
32 | agent_processes[observation.player] = agent_process
33 | atexit.register(cleanup_process)
34 |
35 | # following 4 lines from https://stackoverflow.com/questions/375427/a-non-blocking-read-on-a-subprocess-pipe-in-python
36 | q = Queue()
37 | t = Thread(target=enqueue_output, args=(agent_process.stderr, q))
38 | t.daemon = True # thread dies with the program
39 | t.start()
40 |
41 | # print observations to agent
42 | import json
43 | agent_process.stdin.write((json.dumps(observation) + "\n").encode())
44 | agent_process.stdin.write((json.dumps(configuration) + "\n").encode())
45 | agent_process.stdin.flush()
46 |
47 | # wait for data written to stdout
48 | agent1res = (agent_process.stdout.readline()).decode()
49 |
50 | while True:
51 | try: line = q.get_nowait()
52 | except Empty:
53 | # no standard error received, break
54 | break
55 | else:
56 | # standard error output received, print it out
57 | print(line.decode(), file=sys.stderr, end='')
58 |
59 | agent1res = agent1res.strip()
60 | outputs = agent1res.split(",")
61 | actions = {}
62 | for cmd in outputs:
63 | if cmd != "":
64 | shipyard_id, action_str = cmd.split(":")
65 | actions[shipyard_id] = action_str
66 | return actions
67 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/test/ConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | import org.junit.Assert;
9 | import org.junit.Test;
10 |
11 | import kore.Configuration;
12 |
13 | public class ConfigurationTest {
14 |
15 | @Test
16 | public void givenValidConfiguration_createSuccessful() throws IOException {
17 | Path configPath = Paths.get("bin", "test", "configuration.json");
18 | String rawConfig = Files.readString(configPath);
19 |
20 | Configuration config = new Configuration(rawConfig);
21 |
22 | Assert.assertEquals(0.02, config.regenRate, .001);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/test/KoreJsonTest.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | import org.junit.Assert;
9 | import org.junit.Test;
10 |
11 | import kore.KoreJson;
12 |
13 | public class KoreJsonTest {
14 | @Test
15 | public void containsKey() throws IOException {
16 | Path observation = Paths.get("bin", "test", "observation.json");
17 | String raw = Files.readString(observation);
18 |
19 | Assert.assertTrue(KoreJson.containsKey(raw, "kore"));
20 | Assert.assertFalse(KoreJson.containsKey(raw, "notThere"));
21 | }
22 |
23 | @Test
24 | public void getIntFromJson() throws IOException {
25 | Path observation = Paths.get("bin", "test", "observation.json");
26 | String raw = Files.readString(observation);
27 |
28 | Assert.assertEquals(KoreJson.getIntFromJson(raw, "step"), 16);
29 | }
30 |
31 | @Test
32 | public void getStrFromJson() {
33 | Assert.assertTrue(KoreJson.getStrFromJson("{'test': 'foo'}", "test").equals("foo"));
34 | }
35 |
36 | @Test
37 | public void getFloatArrFromJson() throws IOException {
38 | Path observation = Paths.get("bin", "test", "observation.json");
39 | String raw = Files.readString(observation);
40 |
41 | double[] kore = KoreJson.getDoubleArrFromJson(raw, "kore");
42 | Assert.assertEquals(kore[3], 1.372, 0.0001);
43 | }
44 |
45 | @Test
46 | public void getPlayerPartsFromJson() throws IOException {
47 | Path observation = Paths.get("bin", "test", "observation.json");
48 | String raw = Files.readString(observation);
49 |
50 | String[] players = KoreJson.getPlayerPartsFromJson(raw);
51 | Assert.assertEquals(players.length, 4);
52 | Assert.assertEquals(players[0].substring(0, 3), "500");
53 | }
54 |
55 | @Test
56 | public void getPlayerIdxFromJson() throws IOException {
57 | Path observation = Paths.get("bin", "test", "observation.json");
58 | String raw = Files.readString(observation);
59 |
60 | Assert.assertEquals(KoreJson.getPlayerIdxFromJson(raw), 0);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/test/ObservationTest.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | import org.junit.Assert;
9 | import org.junit.Test;
10 |
11 | import kore.Observation;
12 |
13 | public class ObservationTest {
14 |
15 | @Test
16 | public void givenValidObservation_createSuccessful() throws IOException {
17 | Path observation = Paths.get("bin", "test", "observation.json");
18 | String rawObservation = Files.readString(observation);
19 |
20 | Observation ob = new Observation(rawObservation);
21 |
22 | Assert.assertEquals(0, ob.player);
23 | Assert.assertEquals(16, ob.step);
24 | Assert.assertEquals(4, ob.playerHlt.length);
25 | Assert.assertEquals(4, ob.playerFleets.size());
26 | Assert.assertEquals(0, ob.playerFleets.get(0).size());
27 | Assert.assertEquals(4, ob.playerShipyards.size());
28 | Assert.assertEquals(1, ob.playerShipyards.get(0).size());
29 | }
30 |
31 | @Test
32 | public void givenFullObservation_createSuccessful() throws IOException {
33 | Path observation = Paths.get("bin", "test", "fullob.json");
34 | String rawObservation = Files.readString(observation);
35 |
36 | Observation ob = new Observation(rawObservation);
37 |
38 | Assert.assertEquals(0, ob.player);
39 | Assert.assertEquals(200, ob.step);
40 | Assert.assertEquals(2, ob.playerHlt.length);
41 | Assert.assertEquals(2, ob.playerFleets.size());
42 | Assert.assertEquals(1, ob.playerFleets.get(0).size());
43 | Assert.assertEquals(2, ob.playerShipyards.size());
44 | Assert.assertEquals(6, ob.playerShipyards.get(0).size());
45 | }
46 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/test/PointTest.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | import kore.Point;
7 |
8 | public class PointTest {
9 |
10 | @Test
11 | public void fromIndexToIndex_isIdentity() {
12 | int idx = 254;
13 | int size = 31;
14 |
15 | Point point = Point.fromIndex(idx, size);
16 | int mirroredIdx = point.toIndex(size);
17 |
18 | Assert.assertEquals(idx, mirroredIdx);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/test/ShipyardTest.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | import kore.Point;
7 | import kore.Shipyard;
8 |
9 | public class ShipyardTest {
10 |
11 | @Test
12 | public void maxSpawn_worksCorrectly() {
13 | int[] turns = {0, 1, 2, 293, 294, 295};
14 | int[] expected = {1, 1, 2, 9, 10, 10};
15 | for (int i = 0; i < turns.length; i ++) {
16 | Shipyard shipyard = new Shipyard("A", 0, new Point(0, 0), 1, turns[i], null, null);
17 |
18 | Assert.assertEquals(shipyard.maxSpawn(), expected[i]);
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/java/test/configuration.json:
--------------------------------------------------------------------------------
1 | {"episodeSteps": 400, "actTimeout": 3, "runTimeout": 9600, "startingKore": 6000, "size": 31, "spawnCost": 10, "convertCost": 50, "regenRate": 0.02, "maxRegenCellKore": 500, "agentTimeout": 60, "randomSeed": 1464814655, "__raw_path__": "java/main.py"}
2 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/python/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/kore_fleets/starter_bots/python/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/python/main.py:
--------------------------------------------------------------------------------
1 | from kaggle_environments.envs.kore_fleets.helpers import *
2 | from random import randint
3 |
4 | def agent(obs, config):
5 | board = Board(obs, config)
6 | me=board.current_player
7 |
8 | me = board.current_player
9 | turn = board.step
10 | spawn_cost = board.configuration.spawn_cost
11 | kore_left = me.kore
12 |
13 | for shipyard in me.shipyards:
14 | if shipyard.ship_count > 10:
15 | direction = Direction.from_index(turn % 4)
16 | action = ShipyardAction.launch_fleet_with_flight_plan(2, direction.to_char())
17 | shipyard.next_action = action
18 | elif kore_left > spawn_cost * shipyard.max_spawn:
19 | action = ShipyardAction.spawn_ships(shipyard.max_spawn)
20 | shipyard.next_action = action
21 | kore_left -= spawn_cost * shipyard.max_spawn
22 | elif kore_left > spawn_cost:
23 | action = ShipyardAction.spawn_ships(1)
24 | shipyard.next_action = action
25 | kore_left -= spawn_cost
26 |
27 | return me.next_actions
28 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/Bot.ts:
--------------------------------------------------------------------------------
1 | import {Board} from "./kore/Board";
2 | import { Direction } from "./kore/Direction";
3 | import { ShipyardAction } from "./kore/ShipyardAction";
4 | import { KoreIO } from "./kore/KoreIO";
5 |
6 | export const tick = async (board: Board): Promise => {
7 | const me = board.currentPlayer;
8 | const turn = board.step;
9 | const spawnCost = board.configuration.spawnCost;
10 | let koreLeft = me.kore;
11 |
12 | for (let shipyard of me.shipyards) {
13 | if (shipyard.shipCount > 10) {
14 | const dir = Direction.fromIndex(turn % 4);
15 | const action = ShipyardAction.launchFleetWithFlightPlan(2, dir.toChar());
16 | shipyard.setNextAction(action);
17 | } else if (koreLeft > spawnCost * shipyard.maxSpawn) {
18 | const action = ShipyardAction.spawnShips(shipyard.maxSpawn);
19 | shipyard.setNextAction(action);
20 | koreLeft -= spawnCost * shipyard.maxSpawn;
21 | } else if (koreLeft > spawnCost) {
22 | const action = ShipyardAction.spawnShips(1);
23 | shipyard.setNextAction(action);
24 | koreLeft -= spawnCost;
25 | }
26 | }
27 |
28 | // nextActions will be pulled off of your shipyards
29 | return board;
30 | }
31 |
32 | // agent.run takes care of running your code per tick
33 | const io = new KoreIO();
34 | io.run(tick);
35 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/DoNothingBot.ts:
--------------------------------------------------------------------------------
1 | import {Board} from "./kore/Board";
2 | import { Direction } from "./kore/Direction";
3 | import { ShipyardAction } from "./kore/ShipyardAction";
4 | import { KoreIO } from "./kore/KoreIO";
5 |
6 |
7 | export const tick = async (board: Board): Promise => {
8 | return board;
9 | }
10 |
11 | const io = new KoreIO();
12 | io.run(tick);
13 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/MinerBot.ts:
--------------------------------------------------------------------------------
1 | import {Board} from "./kore/Board";
2 | import { Direction } from "./kore/Direction";
3 | import { ShipyardAction } from "./kore/ShipyardAction";
4 | import { KoreIO } from "./kore/KoreIO";
5 |
6 | export const tick = async (board: Board): Promise => {
7 | const me = board.currentPlayer;
8 | const spawnCost = board.configuration.spawnCost;
9 | const convertCost = board.configuration.convertCost;
10 | let remainingKore = me.kore;
11 |
12 | // the following code is mostly auto-generated using GitHub co-pilot
13 | // using miner Python code and instruction "convert python into javascript" as comment prompts
14 | for (let shipyard of me.shipyards) {
15 | if(remainingKore > 1000 && shipyard.maxSpawn > 5) {
16 | if(shipyard.shipCount >= convertCost + 10) {
17 | const gap1 = getRandomInt(3, 9);
18 | const gap2 = getRandomInt(3, 9);
19 | const startDir = Math.floor(Math.random() * 4);
20 | let flightPlan = Direction.listDirections()[startDir].toChar() + gap1;
21 | const nextDir = (startDir + 1) % 4;
22 | flightPlan += Direction.listDirections()[nextDir].toChar() + gap2;
23 | const nextDir2 = (nextDir + 1) % 4;
24 | flightPlan += Direction.listDirections()[nextDir2].toChar();
25 | shipyard.setNextAction(ShipyardAction.launchFleetWithFlightPlan(Math.min(convertCost + 10, Math.floor(shipyard.shipCount / 2)), flightPlan));
26 | } else if(remainingKore >= spawnCost) {
27 | remainingKore -= spawnCost;
28 | shipyard.setNextAction(ShipyardAction.spawnShips(Math.min(shipyard.maxSpawn, Math.floor(remainingKore / spawnCost))));
29 | }
30 | } else if(shipyard.shipCount >= 21) {
31 | const gap1 = getRandomInt(3, 9);
32 | const gap2 = getRandomInt(3, 9);
33 | const startDir = Math.floor(Math.random() * 4);
34 | let flightPlan = Direction.listDirections()[startDir].toChar() + gap1;
35 | const nextDir = (startDir + 1) % 4;
36 | flightPlan += Direction.listDirections()[nextDir].toChar() + gap2;
37 | const nextDir2 = (nextDir + 1) % 4;
38 | flightPlan += Direction.listDirections()[nextDir2].toChar() + gap1;
39 | const nextDir3 = (nextDir2 + 1) % 4;
40 | flightPlan += Direction.listDirections()[nextDir3].toChar();
41 | shipyard.setNextAction(ShipyardAction.launchFleetWithFlightPlan(21, flightPlan));
42 | } else if(remainingKore > board.configuration.spawnCost * shipyard.maxSpawn) {
43 | remainingKore -= board.configuration.spawnCost;
44 | if(remainingKore >= spawnCost) {
45 | shipyard.setNextAction(ShipyardAction.spawnShips(Math.min(shipyard.maxSpawn, Math.floor(remainingKore / spawnCost))));
46 | }
47 | } else if(shipyard.shipCount >= 2) {
48 | const dirStr = Direction.randomDirection().toChar();
49 | shipyard.setNextAction(ShipyardAction.launchFleetWithFlightPlan(2, dirStr));
50 | }
51 | }
52 |
53 | // nextActions will be pulled off of your shipyards
54 | return board;
55 | }
56 |
57 | const io = new KoreIO();
58 | io.run(tick);
59 |
60 | function getRandomInt(min, max) {
61 | return Math.floor(Math.random() * (max - min + 1)) + min;
62 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/README.md:
--------------------------------------------------------------------------------
1 | # Kore Fleets typescript bot
2 |
3 | ## Requirements
4 |
5 | 1. node and npm/npx/yarn
6 | 2. typescript installed
7 | 3. python3 installed
8 | 4. kaggle_environments pip package installed
9 |
10 | ## Getting started
11 |
12 | 1. `npm install`
13 |
14 | ## Running Locally
15 |
16 | 1. transpile your bot with `npm run compile` or `tsc`
17 | 2. run a match with `npm watch4`
18 |
19 | * if you don't have google-chrome installed, open the replay.html in the browser of your choice
20 | * see package.json for more options
21 |
22 | ## Creating a submission
23 |
24 | 1. `npm run package`
25 | 2. upload submission.tar.gz to kaggle
26 | 3. profit!
27 |
28 | ## Running tests
29 |
30 | 1. `npm test`
31 |
32 | ## Interpreter and training
33 |
34 | A basic TS interpreter has been created in `interpreter.ts`. You can use or modify this file to train machine learning models in JS/TS.
35 |
36 | Currently it supports 2 agents and customizable number of episodes.
37 |
38 | It has two modes: `run` and `step`.
39 |
40 | `run` mode: After each episode, you can access the complete history of the game. For each turn, you can access the full observation (state) as a Board object, actions performed and the reward obtained after performing the action. This mode is useful for evaluating an agent.
41 |
42 | `step` mode: The interpreter initializes new games and allows stepping through the game interactively. You have complete control over the board and the agent during each step. This mode is useful for training machine learning models.
43 |
44 | Sample command to run the interpreter can be found in npm scripts as `npm run interpreter:run` and `npm run interpreter:step`.
45 |
46 | ## Miner bot and Do nothing bot
47 |
48 | A sample miner bot `MinerBot.ts` is provided, with Python entrypoint as `miner.py`. It has the same logic as the Python `miner` bot in `kore_fleets.py`.
49 |
50 | To run it aginst Python miner bot with TS interpreter for 20 episodes:
51 |
52 | 1. `npm run compile`
53 | 2. `node --require ts-node/register interpreter.ts 20 ./miner.py miner`
54 |
55 | A sample do nothing bot `DoNothingBot.ts` is also provided.
56 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Cell.ts:
--------------------------------------------------------------------------------
1 | import {Board} from "./Board";
2 | import {Direction} from "./Direction";
3 | import {Fleet} from "./Fleet";
4 | import {Point} from "./Point";
5 | import {Shipyard} from "./Shipyard";
6 |
7 | export class Cell {
8 |
9 | public readonly position: Point;
10 | public kore: number;
11 | public shipyardId: string;
12 | public fleetId: string;
13 | public readonly board: Board;
14 |
15 | public constructor(position: Point, kore: number, shipyardId: string, fleetId: string, board: Board) {
16 | this.position = position;
17 | this.kore = kore;
18 | this.shipyardId = shipyardId;
19 | this.fleetId = fleetId;
20 | this.board = board;
21 | }
22 |
23 | public cloneToBoard(board: Board): Cell {
24 | return new Cell(this.position, this.kore, this.shipyardId, this.fleetId, board);
25 | }
26 |
27 | public get fleet(): Fleet | undefined {
28 | if (this.board.fleets.has(this.fleetId)) {
29 | return this.board.fleets.get(this.fleetId);
30 | }
31 | return undefined;
32 | }
33 |
34 |
35 | public get shipyard(): Shipyard | undefined {
36 | if (this.board.shipyards.has(this.shipyardId)) {
37 | return this.board.shipyards.get(this.shipyardId);
38 | }
39 | return undefined;
40 | }
41 |
42 | public neighbor(offset: Point): Cell {
43 | const next = this.position.translate(offset, this.board.size);
44 | return this.board.getCellAtPosition(next);
45 | }
46 |
47 |
48 | public north(): Cell {
49 | return this.neighbor(Direction.NORTH);
50 | }
51 |
52 | public south(): Cell {
53 | return this.neighbor((Direction.SOUTH));
54 | }
55 |
56 | public east(): Cell {
57 | return this.neighbor(Direction.EAST);
58 | }
59 |
60 | public west(): Cell {
61 | return this.neighbor(Direction.WEST);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Configuration.ts:
--------------------------------------------------------------------------------
1 | export class Configuration {
2 |
3 | public readonly agentTimeout: number;
4 | public readonly startingKore: number;
5 | public readonly size: number;
6 | public readonly spawnCost: number;
7 | public readonly convertCost: number;
8 | public readonly regenRate: number;
9 | public readonly maxRegenCellKore: number;
10 | public readonly randomSeed: number;
11 | public readonly episodeSteps: number;
12 |
13 | public constructor(rawConfiguration: string) {
14 | const config = JSON.parse(rawConfiguration);
15 | this.agentTimeout = config.agentTimeout;
16 | this.startingKore = config.startingKore;
17 | this.size = config.size;
18 | this.spawnCost = config.spawnCost;
19 | this.convertCost = config.convertCost;
20 | this.regenRate = config.regenRate;
21 | this.maxRegenCellKore = config.maxRegenCellKore;
22 | this.randomSeed = config.randomSeed;
23 | this.episodeSteps = config.episodeSteps;
24 | }
25 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Fleet.ts:
--------------------------------------------------------------------------------
1 | import {Board} from "./Board";
2 | import {Cell} from "./Cell";
3 | import {Direction} from "./Direction";
4 | import {Player} from "./Player";
5 | import {Point} from "./Point";
6 |
7 | export class Fleet {
8 |
9 | public readonly id: string;
10 | public shipCount: number;
11 | public direction: Direction;
12 | public position: Point;
13 | public flightPlan: string;
14 | public kore: number;
15 | public readonly playerId: number;
16 | public readonly board: Board;
17 |
18 | public constructor(fleetId: string, shipCount: number, direction: Direction, position: Point, kore: number, flightPlan: string, playerId: number, board: Board) {
19 | this.id = fleetId;
20 | this.shipCount = shipCount;
21 | this.direction = direction;
22 | this.position = position;
23 | this.flightPlan = flightPlan;
24 | this.kore = kore;
25 | this.playerId = playerId;
26 | this.board = board;
27 | }
28 |
29 | public cloneToBoard(board: Board): Fleet {
30 | return new Fleet(this.id, this.shipCount, this.direction, this.position, this.kore, this.flightPlan, this.playerId, board);
31 | }
32 |
33 | public get cell(): Cell {
34 | return this.board.getCellAtPosition(this.position);
35 | }
36 |
37 | public get player(): Player {
38 | return this.board.players[this.playerId];
39 | }
40 |
41 | public get collectionRate(): number {
42 | return Math.min(Math.log(this.shipCount) / 10, .99);
43 | }
44 |
45 | /**
46 | * Returns the length of the longest possible flight plan this fleet can be assigned
47 | * @return
48 | */
49 | public static maxFlightPlanLenForShipCount(shipCount: number): number {
50 | return (Math.floor(2 * Math.log(shipCount)) + 1);
51 | }
52 |
53 | /**
54 | * Converts a fleet back to the normalized observation subset that constructed it.
55 | */
56 | public observation(): string[] {
57 | return [
58 | this.position.toIndex(this.board.configuration.size).toString(),
59 | this.kore.toString(),
60 | this.shipCount.toString(),
61 | this.direction.toIndex().toString(),
62 | this.flightPlan
63 | ];
64 | }
65 |
66 | public lessThanOtherAlliedFleet(other: Fleet): boolean {
67 | if (this.shipCount != other.shipCount) {
68 | return this.shipCount < other.shipCount;
69 | }
70 | if (this.kore != other.kore) {
71 | return this.kore < other.kore;
72 | }
73 | return this.direction.toIndex() > other.direction.toIndex();
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/KoreIO.ts:
--------------------------------------------------------------------------------
1 | import readline from 'readline';
2 | import { Board } from './Board';
3 | import { ShipyardAction } from './ShipyardAction';
4 |
5 | export class KoreIO {
6 | public getLine: () => Promise;
7 |
8 | public _setup(): void {
9 | // Prepare to read input
10 | const rl = readline.createInterface({
11 | input: process.stdin,
12 | output: null,
13 | });
14 |
15 | const buffer = [];
16 | let currentResolve: () => void;
17 | let currentPromise;
18 | const makePromise = function () {
19 | return new Promise((resolve) => {
20 | currentResolve = resolve;
21 | });
22 | };
23 | // on each line, push line to buffer
24 | rl.on('line', (line) => {
25 | buffer.push(line);
26 | currentResolve();
27 | currentPromise = makePromise();
28 | });
29 | // The current promise for retrieving the next line
30 | currentPromise = makePromise();
31 |
32 | // with await, we pause process until there is input
33 | this.getLine = async () => {
34 | return new Promise(async (resolve) => {
35 | while (buffer.length === 0) {
36 | // pause while buffer is empty, continue if new line read
37 | await currentPromise;
38 | }
39 | // once buffer is not empty, resolve the most recent line in stdin, and remove it
40 | resolve(buffer.shift());
41 | });
42 | };
43 | }
44 |
45 | /**
46 | * Constructor for a new agent
47 | * User should edit this according to the `Design` this agent will compete under
48 | */
49 | public constructor() {
50 | this._setup(); // DO NOT REMOVE
51 | }
52 |
53 | public async run(loop: (board: Board) => Promise): Promise {
54 | while (true) {
55 | const rawObservation = await this.getLine();
56 | const rawConfiguration = await this.getLine();
57 | const board = Board.fromRaw(rawObservation, rawConfiguration);
58 | try {
59 | const nextBoard = await loop(board);
60 | let actions = [];
61 | board.currentPlayer.nextActions.forEach((action: ShipyardAction, id: string) =>
62 | actions.push(`${id}:${action.toString()}`)
63 | );
64 | console.log(actions.join(','));
65 | } catch (err) {
66 | console.log(err);
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Observation.ts:
--------------------------------------------------------------------------------
1 |
2 | export class Observation {
3 | public readonly kore: number[];
4 | public readonly playerHlt: number[];
5 | public readonly playerShipyards: Map[];
6 | public readonly playerFleets: Map[];
7 | public readonly player: number;
8 | public readonly step: number;
9 | public readonly remainingOverageTime: number;
10 |
11 | public constructor(rawObservation: string) {
12 | const json = JSON.parse(rawObservation);
13 | this.kore = json["kore"];
14 | this.player = json["player"];
15 | this.step = json["step"];
16 | this.remainingOverageTime = rawObservation["remainingOverageTime"];
17 | const playerParts = json["players"];
18 | this.playerHlt = [];
19 | this.playerShipyards = [];
20 | this.playerFleets = [];
21 |
22 | for (var i = 0; i < playerParts.length; i ++) {
23 | const playerPart = playerParts[i];
24 | this.playerHlt.push(parseInt(playerPart[0]));
25 |
26 | const shipyards = new Map();
27 | Object.entries(playerPart[1]).forEach(entry => {
28 | const shipyardId = entry[0];
29 | const shipyardInts = entry[1];
30 | shipyards.set(shipyardId, shipyardInts as number[]);
31 | });
32 | this.playerShipyards.push(shipyards);
33 |
34 | const fleets = new Map();
35 | Object.entries(playerPart[2]).forEach(entry => {
36 | const fleetId = entry[0];
37 | const fleetStrs = entry[1];
38 | fleets.set(fleetId, fleetStrs as string[])
39 | })
40 | this.playerFleets.push(fleets)
41 | }
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Pair.ts:
--------------------------------------------------------------------------------
1 | export class Pair {
2 |
3 | public readonly first: F;
4 | public readonly second: S;
5 |
6 | public constructor(first: F, second: S) {
7 | this.first = first;
8 | this.second = second;
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Player.ts:
--------------------------------------------------------------------------------
1 | import {Board} from "./Board";
2 | import {Fleet} from "./Fleet";
3 | import {Shipyard} from "./Shipyard";
4 | import {ShipyardAction} from "./ShipyardAction";
5 |
6 | export class Player {
7 | public readonly id: number;
8 | public kore: number;
9 | public readonly shipyardIds: string[];
10 | public readonly fleetIds: string[];
11 | public readonly board: Board;
12 |
13 | public constructor(playerId: number, kore: number, shipyardIds: string[], fleetIds: string[], board: Board) {
14 | this.id = playerId;
15 | this.kore = kore;
16 | this.shipyardIds = shipyardIds;
17 | this.fleetIds = fleetIds;
18 | this.board = board;
19 | }
20 |
21 | public cloneToBoard(board: Board): Player {
22 | return new Player(this.id, this.kore, this.shipyardIds.slice(), this.fleetIds.slice(), board);
23 | }
24 |
25 | /**
26 | * Returns all shipyards owned by this player.
27 | * @return
28 | */
29 | public get shipyards(): Shipyard[] {
30 | return Array.from(this.board.shipyards.values())
31 | .filter(shipyard => this.shipyardIds.some(sId => sId == shipyard.id));
32 | }
33 |
34 | /**
35 | * Returns all fleets owned by this player.
36 | */
37 | public get fleets(): Fleet[] {
38 | return Array.from(this.board.fleets.values())
39 | .filter(fleet => this.fleetIds.some(fId => fId == fleet.id));
40 | }
41 |
42 | /**
43 | * Returns whether this player is the current player (generally if this returns True, this player is you.
44 | */
45 | public isCurrentPlayer(): boolean {
46 | return this.id == this.board.currentPlayerId;
47 | }
48 |
49 | /**
50 | * Returns all queued fleet and shipyard actions for this player formatted for the kore interpreter to receive as an agent response.
51 | */
52 | public get nextActions(): Map {
53 | const result = new Map();
54 | this.shipyards.filter(shipyard => shipyard.nextAction).forEach(shipyard => result.set(shipyard.id, shipyard.nextAction as ShipyardAction));
55 | return result;
56 | }
57 |
58 | /**
59 | * Converts a player back to the normalized observation subset that constructed it.
60 | */
61 | public observation(): any[] {
62 | const shipyards = new Map();
63 | this.shipyards.forEach(shipyard => shipyards.set(shipyard.id, shipyard.observation()));
64 | const fleets = new Map();
65 | this.fleets.forEach(fleet => fleets.set(fleet.id, fleet.observation()));
66 | return [this.kore, shipyards, fleets];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Point.ts:
--------------------------------------------------------------------------------
1 | export class Point {
2 | public readonly x: number;
3 | public readonly y: number;
4 |
5 | public constructor(x: number, y: number) {
6 | this.x = x;
7 | this.y = y;
8 | }
9 |
10 | public translate(offset: Point, size: number): Point {
11 | return this.add(offset).mod(size);
12 | }
13 |
14 | public add(other: Point): Point {
15 | return new Point(this.x + other.x, this.y + other.y);
16 | }
17 |
18 | public mod(size: number): Point {
19 | // handle cases where the point is negative due to translation offset being negative
20 | return new Point((this.x + size) % size, (this.y + size) % size);
21 | }
22 |
23 | /**
24 | * Gets the manhatten distance between two points
25 | */
26 | public distanceTo(other: Point, size: number): number {
27 | const abs_x = Math.abs(this.x - other.x);
28 | const dist_x = abs_x < size/2 ? abs_x : size - abs_x;
29 | const abs_y = Math.abs(this.y - other.y);
30 | const dist_y = abs_y < size/2 ? abs_y : size - abs_y;
31 | return dist_x + dist_y;
32 | }
33 |
34 | /**
35 | * Converts a 2d position in the form (x, y) to an index in the observation.kore list.
36 | * See fromIndex for the inverse.
37 | */
38 | public toIndex(size: number) {
39 | return (size - this.y - 1) * size + this.x;
40 | }
41 |
42 | public static fromIndex(index: number, size: number): Point {
43 | return new Point(index % size, size - Math.floor(index/size) - 1);
44 | }
45 |
46 | public abs(): Point {
47 | return new Point(Math.abs(this.x), Math.abs(this.y));
48 | }
49 |
50 | public equals(other: Point): boolean {
51 | return this.x == other.x && this.y == other.y;
52 | }
53 |
54 | public toString(): string {
55 | return "(" + this.x + "," + this.y + ")";
56 | }
57 |
58 | public multiply(factor: number): Point {
59 | return new Point(factor * this.x, factor * this.y);
60 | }
61 |
62 | public subtract(other: Point): Point {
63 | return new Point(this.x - other.x, this.y - other.y);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Shipyard.ts:
--------------------------------------------------------------------------------
1 |
2 | import {Board} from "./Board";
3 | import {Cell} from "./Cell";
4 | import {Player} from "./Player";
5 | import {Point} from "./Point";
6 | import {ShipyardAction} from "./ShipyardAction";
7 |
8 | const SPAWN_VALUES = [];
9 | const upgradeTimes: number[] = [];
10 | for(let i = 1; i < 10; i++) {
11 | upgradeTimes[i-1] = Math.pow(i, 2) + 1;
12 | }
13 | let current = 0;
14 | for(let i = 1; i < 10; i++) {
15 | current += upgradeTimes[i-1];
16 | SPAWN_VALUES[i-1] = current;
17 | }
18 |
19 | export class Shipyard {
20 | public readonly id: string;
21 | public shipCount: number;
22 | public position: Point;
23 | public playerId: number;
24 | public turnsControlled: number;
25 | public readonly board: Board;
26 | public nextAction: ShipyardAction | undefined;
27 |
28 | public constructor(shipyardId: string, shipCount: number, position: Point, playerId: number, turnsControlled: number, board: Board, nextAction: ShipyardAction | undefined) {
29 | this.id = shipyardId;
30 | this.shipCount = shipCount;
31 | this.position = position;
32 | this.playerId = playerId;
33 | this.turnsControlled = turnsControlled;
34 | this.board = board;
35 | this.nextAction = nextAction;
36 | }
37 |
38 | public cloneToBoard(board: Board): Shipyard {
39 | return new Shipyard(this.id, this.shipCount, this.position, this.playerId, this.turnsControlled, board, this.nextAction);
40 | }
41 |
42 | public setNextAction(action: ShipyardAction): void {
43 | this.nextAction = action;
44 | }
45 |
46 | public get maxSpawn(): number {
47 | for (let i = 0; i < SPAWN_VALUES.length; i++) {
48 | if (this.turnsControlled < SPAWN_VALUES[i]) {
49 | return i + 1;
50 | }
51 | }
52 | return SPAWN_VALUES.length + 1;
53 | }
54 |
55 | /**
56 | * Returns the cell this shipyard is on.
57 | */
58 | public get cell(): Cell {
59 | return this.board.getCellAtPosition(this.position);
60 | }
61 |
62 | public get player(): Player {
63 | return this.board.players[this.playerId];
64 | }
65 |
66 | /**
67 | * Converts a shipyard back to the normalized observation subset that constructed it.
68 | */
69 | public observation(): number[] {
70 | return [this.position.toIndex(this.board.configuration.size), this.shipCount, this.turnsControlled];
71 | }
72 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/ShipyardAction.ts:
--------------------------------------------------------------------------------
1 |
2 | export class ShipyardAction {
3 | public static readonly SPAWN = "SPAWN";
4 | public static readonly LAUNCH = "LAUNCH";
5 | public readonly actionType: string;
6 | public readonly shipCount: number;
7 | public readonly flightPlan: string;
8 |
9 | public static spawnShips(shipCount: number): ShipyardAction {
10 | return new ShipyardAction(ShipyardAction.SPAWN, shipCount, "");
11 | }
12 |
13 | public static launchFleetWithFlightPlan(shipCount: number, flightPlan: string): ShipyardAction {
14 | return new ShipyardAction(ShipyardAction.LAUNCH, shipCount, flightPlan);
15 | }
16 |
17 | public static fromstring(raw: string): ShipyardAction {
18 | if (raw.length == 0) {
19 | throw new Error("invalid raw shipyard empty string");
20 | }
21 | const shipCount = parseInt(raw.split("_")[1]);
22 | if (raw.startsWith(ShipyardAction.LAUNCH)) {
23 | return ShipyardAction.spawnShips(shipCount);
24 | }
25 | if (raw.startsWith(ShipyardAction.SPAWN)) {
26 | const flightPlan = raw.split("_")[2];
27 | return ShipyardAction.launchFleetWithFlightPlan(shipCount, flightPlan);
28 | }
29 | throw new Error("invalid Shipyard Action raw " + raw);
30 | }
31 |
32 | public constructor(type: string, shipCount: number, flightPlan: string) {
33 | // assert type.equals(SPAWN) || type.equals(LAUNCH) : "Type must be SPAWN or LAUNCH";
34 | // assert shipCount > 0 : "numShips must be a non-negative number";
35 | this.actionType = type;
36 | this.shipCount = shipCount;
37 | this.flightPlan = flightPlan;
38 | }
39 |
40 | private get isSpawn(): boolean {
41 | return this.actionType == ShipyardAction.SPAWN;
42 | }
43 |
44 | private get isLaunch(): boolean {
45 | return this.actionType == ShipyardAction.LAUNCH;
46 | }
47 |
48 | public toString(): string {
49 | if (this.isSpawn) {
50 | return `${ShipyardAction.SPAWN}_${this.shipCount}`;
51 | }
52 | if (this.isLaunch) {
53 | return `${ShipyardAction.LAUNCH}_${this.shipCount}_${this.flightPlan}`;
54 | }
55 | throw new Error("invalid Shpyard Action");
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/main.py:
--------------------------------------------------------------------------------
1 | from subprocess import Popen, PIPE
2 | from threading import Thread
3 | from queue import Queue, Empty
4 |
5 | import atexit
6 | import os
7 | import sys
8 | agent_processes = [None, None, None, None]
9 | t = None
10 | q = None
11 | def cleanup_process():
12 | global agent_processes
13 | for proc in agent_processes:
14 | if proc is not None:
15 | proc.kill()
16 | def enqueue_output(out, queue):
17 | for line in iter(out.readline, b''):
18 | queue.put(line)
19 | out.close()
20 |
21 | def agent(observation, configuration):
22 | global agent_processes, t, q
23 |
24 | agent_process = agent_processes[observation.player]
25 | ### Do not edit ###
26 | if agent_process is None:
27 | if "__raw_path__" in configuration:
28 | cwd = os.path.dirname(configuration["__raw_path__"])
29 | else:
30 | cwd = os.path.dirname(__file__)
31 | agent_process = Popen(["node", "dist/Bot.js"], stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=cwd)
32 | agent_processes[observation.player] = agent_process
33 | atexit.register(cleanup_process)
34 |
35 | # following 4 lines from https://stackoverflow.com/questions/375427/a-non-blocking-read-on-a-subprocess-pipe-in-python
36 | q = Queue()
37 | t = Thread(target=enqueue_output, args=(agent_process.stderr, q))
38 | t.daemon = True # thread dies with the program
39 | t.start()
40 |
41 | # print observations to agent
42 | import json
43 | agent_process.stdin.write((json.dumps(observation) + "\n").encode())
44 | agent_process.stdin.write((json.dumps(configuration) + "\n").encode())
45 | agent_process.stdin.flush()
46 |
47 | # wait for data written to stdout
48 | agent1res = (agent_process.stdout.readline()).decode()
49 |
50 | while True:
51 | try: line = q.get_nowait()
52 | except Empty:
53 | # no standard error received, break
54 | break
55 | else:
56 | # standard error output received, print it out
57 | print(line.decode(), file=sys.stderr, end='')
58 |
59 | agent1res = agent1res.strip()
60 | outputs = agent1res.split(",")
61 | actions = {}
62 | for cmd in outputs:
63 | if cmd != "":
64 | shipyard_id, action_str = cmd.split(":")
65 | actions[shipyard_id] = action_str
66 | return actions
67 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/miner.py:
--------------------------------------------------------------------------------
1 | from subprocess import Popen, PIPE
2 | from threading import Thread
3 | from queue import Queue, Empty
4 |
5 | import atexit
6 | import os
7 | import sys
8 | agent_processes = [None, None, None, None]
9 | t = None
10 | q = None
11 | def cleanup_process():
12 | global agent_processes
13 | for proc in agent_processes:
14 | if proc is not None:
15 | proc.kill()
16 | def enqueue_output(out, queue):
17 | for line in iter(out.readline, b''):
18 | queue.put(line)
19 | out.close()
20 |
21 | def agent(observation, configuration):
22 | global agent_processes, t, q
23 |
24 | agent_process = agent_processes[observation.player]
25 | ### Do not edit ###
26 | if agent_process is None:
27 | if "__raw_path__" in configuration:
28 | cwd = os.path.dirname(configuration["__raw_path__"])
29 | else:
30 | cwd = os.path.dirname(__file__)
31 | agent_process = Popen(["node", "dist/MinerBot.js"], stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=cwd)
32 | agent_processes[observation.player] = agent_process
33 | atexit.register(cleanup_process)
34 |
35 | # following 4 lines from https://stackoverflow.com/questions/375427/a-non-blocking-read-on-a-subprocess-pipe-in-python
36 | q = Queue()
37 | t = Thread(target=enqueue_output, args=(agent_process.stderr, q))
38 | t.daemon = True # thread dies with the program
39 | t.start()
40 |
41 | # print observations to agent
42 | import json
43 | agent_process.stdin.write((json.dumps(observation) + "\n").encode())
44 | agent_process.stdin.write((json.dumps(configuration) + "\n").encode())
45 | agent_process.stdin.flush()
46 |
47 | # wait for data written to stdout
48 | agent1res = (agent_process.stdout.readline()).decode()
49 |
50 | while True:
51 | try: line = q.get_nowait()
52 | except Empty:
53 | # no standard error received, break
54 | break
55 | else:
56 | # standard error output received, print it out
57 | print(line.decode(), file=sys.stderr, end='')
58 |
59 | agent1res = agent1res.strip()
60 | outputs = agent1res.split(",")
61 | actions = {}
62 | for cmd in outputs:
63 | if cmd != "":
64 | shipyard_id, action_str = cmd.split(":")
65 | actions[shipyard_id] = action_str
66 | return actions
67 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "@types/chai": "^4.3.0",
4 | "@types/mocha": "^9.1.0",
5 | "chai": "^4.3.4",
6 | "mocha": "^9.2.0",
7 | "ts-node": "^10.4.0",
8 | "typescript": "^4.5.5"
9 | },
10 | "scripts": {
11 | "test": "mocha --require ts-node/register test/**/*.ts",
12 | "compile": "tsc",
13 | "package": "tsc && tar -czvf submission.tar.gz main.py dist/*",
14 | "interpreter:run": "node --require ts-node/register interpreter.ts run 2 ./main.py miner",
15 | "interpreter:step": "node --require ts-node/register interpreter.ts step 2 miner do_nothing",
16 | "watch4": "kaggle-environments run --environment kore_fleets --agents ./main.py ./main.py ./main.py ./main.py --log out.log --render '{\"mode\": \"html\"}' --out replay.html && google-chrome replay.html",
17 | "watch2": "kaggle-environments run --environment kore_fleets --agents ./main.py ./main.py --log out.log --render '{\"mode\": \"html\"}' --out replay.html && google-chrome replay.html",
18 | "watch1": "kaggle-environments run --environment kore_fleets --agents ./main.py --log out.log --render '{\"mode\": \"html\"}' --out replay.html && google-chrome replay.html",
19 | "play4": "kaggle-environments run --environment kore_fleets --agents ./main.py ./main.py ./main.py ./main.py --log out.log --out replay.html",
20 | "play2": "kaggle-environments run --environment kore_fleets --agents ./main.py ./main.py --log out.log --out replay.html",
21 | "play1": "kaggle-environments run --environment kore_fleets --agents ./main.py --log out.log --out replay.html"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ConfigurationTest.ts:
--------------------------------------------------------------------------------
1 | import { describe } from 'mocha';
2 | import { expect } from 'chai';
3 |
4 | import * as fs from 'fs';
5 |
6 | import { Configuration } from "../kore/Configuration";
7 |
8 | describe('Configuration', () => {
9 | it('init works correctly', () => {
10 | const rawConfig = fs.readFileSync('./test/configuration.json','utf8');
11 |
12 | const config = new Configuration(rawConfig);
13 |
14 | expect(config.regenRate).to.equal(.02);
15 | })
16 | });
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ObservationTest.ts:
--------------------------------------------------------------------------------
1 | import { describe } from 'mocha';
2 | import { expect } from 'chai';
3 |
4 | import * as fs from 'fs';
5 |
6 | import { Observation } from "../kore/Observation";
7 |
8 | describe('Observation', () => {
9 | it('valid observation works', () => {
10 | const rawObs = fs.readFileSync('./test/observation.json', 'utf8');
11 | const ob = new Observation(rawObs);
12 |
13 | expect(ob.player).to.equal(0);
14 | expect(ob.step).to.equal(16);
15 | expect(ob.playerFleets.length).to.equal(4);
16 | expect(ob.playerFleets[0].size).to.equal(0);
17 | expect(ob.playerShipyards.length).to.equal(4);
18 | expect(ob.playerShipyards[0].size).to.equal(1);
19 | })
20 |
21 | it('full observation works', () => {
22 | const rawObs = fs.readFileSync('./test/fullob.json', 'utf8');
23 | const ob = new Observation(rawObs);
24 |
25 | expect(ob.player).to.equal(0);
26 | expect(ob.step).to.equal(200);
27 | expect(ob.playerHlt.length).to.equal(2);
28 | expect(ob.playerFleets.length).to.equal(2);
29 | expect(ob.playerFleets[0].size).to.equal(1);
30 | expect(ob.playerShipyards.length).to.equal(2);
31 | expect(ob.playerShipyards[0].size).to.equal(6);
32 | })
33 | });
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/test/PointTest.ts:
--------------------------------------------------------------------------------
1 | import { describe } from 'mocha';
2 | import { expect } from 'chai';
3 |
4 | import { Point } from "../kore/Point";
5 |
6 | describe('Point', () => {
7 | it('fontIndex toIndex isIdetity', () => {
8 | const idx = 254;
9 | const size = 31;
10 |
11 | const point = Point.fromIndex(idx, size);
12 | const mirroredIdx = point.toIndex(size);
13 |
14 | expect(mirroredIdx).to.equal(idx);
15 | })
16 |
17 | });
18 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ShipyardTest.ts:
--------------------------------------------------------------------------------
1 | import { describe } from 'mocha';
2 | import { expect } from 'chai';
3 |
4 | import { Shipyard } from "../kore/Shipyard";
5 | import { Point } from '../kore/Point';
6 |
7 | describe('Shipyard', () => {
8 | const turns = [0, 1, 2, 293, 294, 295];
9 | const expected = [1, 1, 2, 9, 10, 10]
10 | for (let i = 0; i < turns.length; i ++) {
11 | it(`max spawn is correct at ${turns[i]} turns controlled`, () => {
12 | const shipyard = new Shipyard("A", 0, new Point(0, 0), 1, turns[i], null, null);
13 |
14 | expect(shipyard.maxSpawn).to.equal(expected[i]);
15 | })
16 | }
17 |
18 | });
19 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/test/configuration.json:
--------------------------------------------------------------------------------
1 | {"episodeSteps": 401, "actTimeout": 3, "runTimeout": 9600, "startingKore": 6000, "size": 31, "spawnCost": 10, "convertCost": 50, "regenRate": 0.02, "maxRegenCellKore": 500, "agentTimeout": 60, "randomSeed": 1464814655, "__raw_path__": "java/main.py"}
2 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/kore_fleets/starter_bots/ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "CommonJS",
4 | "lib": ["esnext"],
5 | "target": "es5",
6 | "moduleResolution": "node",
7 | "experimentalDecorators": true,
8 | "emitDecoratorMetadata": true,
9 | "esModuleInterop": true,
10 | "sourceMap": true,
11 | "declaration": true,
12 | "resolveJsonModule": true,
13 | "outDir": "dist"
14 | },
15 | "include": [
16 | "**/*.ts"
17 | ],
18 | "exclude": [
19 | "node_modules",
20 | "dist"
21 | ]
22 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/llm_20_questions/llm_20_questions.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "llm_20_questions",
3 | "title": "20 Questions",
4 | "description": "20 Questions played between two LLM agents",
5 | "version": "1.0.0",
6 | "agents": [4],
7 | "configuration": {
8 | "episodeSteps": 61,
9 | "actTimeout": 60,
10 | "runTimeout": 9600,
11 | "agentTimeout": {
12 | "description": "Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.",
13 | "type": "number",
14 | "minimum": 0,
15 | "default": 3600
16 | }
17 | },
18 | "reward": {
19 | "description": "1-20 = Won, -1 = Lost",
20 | "enum": [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
21 | "defaults": [0, 0, 0, 0]
22 | },
23 | "observation": {
24 | "questions": {
25 | "description": "Questions the guessing agent has asked.",
26 | "type": "array",
27 | "default": []
28 | },
29 | "guesses": {
30 | "description": "Guesses the guessing agent has made.",
31 | "type": "array",
32 | "default": []
33 | },
34 | "answers": {
35 | "description": "Answers the answering agent has given.",
36 | "type": "array",
37 | "default": []
38 | },
39 | "role": {
40 | "description": "The role of the agent for this episode.",
41 | "enum": ["guesser", "answerer"],
42 | "defaults": ["guesser", "answerer", "guesser", "answerer"]
43 | },
44 | "turnType": {
45 | "description": "The type of action that should be taken this turn.",
46 | "enum": ["ask", "guess", "answer"],
47 | "defaults": ["ask", "answer", "ask", "answer"]
48 | },
49 | "keyword": {
50 | "description": "The keyword to win the game",
51 | "type": "string",
52 | "shared": "false",
53 | "default": ""
54 | },
55 | "category": {
56 | "description": "The catagory of the keyword.",
57 | "type": "string",
58 | "shared": "false",
59 | "default": ""
60 | },
61 | "remainingOverageTime": 300
62 | },
63 | "action": {
64 | "description": "LLM agent response.",
65 | "type": "string",
66 | "default": ""
67 | },
68 | "status": {
69 | "defaults": ["ACTIVE", "INACTIVE", "ACTIVE", "INACTIVE"]
70 | }
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/llm_20_questions/test_llm_20_questions.py:
--------------------------------------------------------------------------------
1 |
2 | from kaggle_environments import make
3 |
4 | def custom_questioner(obs):
5 | if obs.turnType == "guess":
6 | return "banana"
7 | return "Is it a banana?"
8 |
9 | def last_round_guesser_error(obs):
10 | if obs.turnType == "guess" and len(obs.questions) == 20:
11 | a = 1
12 | b = 0
13 | return a / b
14 | if obs.turnType == "guess":
15 | return "banana"
16 | return "Is it a banana?"
17 |
18 | def custom_answerer():
19 | return "no"
20 |
21 | def bad_answerer():
22 | return "maybe?"
23 |
24 | def error_agent():
25 | raise ValueError
26 |
27 | def test_llm_20_q_completes():
28 | env = make("llm_20_questions", debug=True)
29 | env.run([custom_questioner, custom_answerer, custom_questioner, custom_answerer])
30 | json = env.toJSON()
31 | assert json["name"] == "llm_20_questions"
32 | assert json["statuses"] == ["DONE", "DONE", "DONE", "DONE"]
33 |
34 | def test_llm_20_q_errors_on_bad_answer():
35 | env = make("llm_20_questions", debug=True)
36 | env.run([custom_questioner, custom_answerer, custom_questioner, bad_answerer])
37 | json = env.toJSON()
38 | assert json["name"] == "llm_20_questions"
39 | assert json["rewards"] == [1, 1, 1, None]
40 | assert json["statuses"] == ["DONE", "DONE", "DONE", "ERROR"]
41 | print(len(json["steps"]))
42 | assert len(json["steps"]) == 3
43 |
44 | def test_llm_20_q_errors_on_error_answer():
45 | env = make("llm_20_questions", debug=True)
46 | env.run([custom_questioner, custom_answerer, custom_questioner, error_agent])
47 | json = env.toJSON()
48 | assert json["name"] == "llm_20_questions"
49 | assert json["rewards"] == [1, 1, 1, None]
50 | assert json["statuses"] == ["DONE", "DONE", "DONE", "ERROR"]
51 | assert len(json["steps"]) == 3
52 |
53 | def test_llm_20_q_errors_on_error_question():
54 | env = make("llm_20_questions", debug=True)
55 | env.run([custom_questioner, custom_answerer, error_agent, custom_answerer])
56 | json = env.toJSON()
57 | assert json["name"] == "llm_20_questions"
58 | assert json["rewards"] == [1, 1, None, 1]
59 | assert json["statuses"] == ["DONE", "DONE", "ERROR", "DONE"]
60 | assert len(json["steps"]) == 2
61 |
62 | def test_llm_20_q_errors_on_error_last_guess():
63 | env = make("llm_20_questions", debug=True)
64 | env.run([custom_questioner, custom_answerer, last_round_guesser_error, custom_answerer])
65 | json = env.toJSON()
66 | assert json["name"] == "llm_20_questions"
67 | assert json["rewards"] == [1, 1, None, 1]
68 | assert json["statuses"] == ["DONE", "DONE", "ERROR", "DONE"]
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/README.md:
--------------------------------------------------------------------------------
1 | # Lux AI Challenge Season 1
2 |
3 | Welcome to the Kaggle Environments wrapped around the Lux AI Challenge Season 1! For more information or if you have an issues or want to make contributes, check out the main repository at https://github.com/Lux-AI-Challenge/Lux-Design-2021
4 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_2021/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/agents.py:
--------------------------------------------------------------------------------
1 | from kaggle_environments.envs.lux_ai_2021.test_agents.python.random_agent import random_agent
2 | import random
3 | from .test_agents.js_simple.main import js_agent as js_simple_agent
4 | from .test_agents.python.random_agent import random_agent
5 | from .test_agents.python.simple_agent import agent as simple_agent
6 | agents = {
7 | "random_agent": random_agent,
8 | "simple_agent": simple_agent,
9 | "js_simple_agent": js_simple_agent,
10 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | Lux AI Challenge Viewer
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
30 |
31 |
32 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/lux_ai_2021.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lux_ai_2021",
3 | "title": "Lux AI Challenge: 2021",
4 | "description": "A Novel AI Programming Challenge about Lux",
5 | "version": "3.1.0",
6 | "agents": [2],
7 | "configuration": {
8 | "episodeSteps": {
9 | "description": "Maximum number of steps the environment can run. Total is this number -1. One complete game is 360 steps",
10 | "type": "integer",
11 | "minimum": 2,
12 | "default": 361
13 | },
14 | "parameters": {
15 | "description": "Parameters for Lux AI 2021",
16 | "type": "object"
17 | },
18 | "mapType": {
19 | "description": "Map type to use",
20 | "type": "string",
21 | "default": "random"
22 | },
23 | "width": {
24 | "description": "Width of map to generate",
25 | "type": "integer"
26 | },
27 | "seed": {
28 | "description": "Seed to use for episodes",
29 | "type": "integer"
30 | },
31 | "annotations": {
32 | "description": "Whether to enable debug annotations or not.",
33 | "type": "boolean",
34 | "default": false
35 | },
36 | "actTimeout": 3,
37 | "loglevel": {
38 | "description": "Logging level of the game. 2 for warnings (e.g unit collisions, malformed actions), 1 for errors, 0 for none",
39 | "type": "integer",
40 | "default": 0
41 | }
42 | },
43 | "reward": {
44 | "description": "Reward of the agent. Equal to number of city tiles * 1000 + number of units",
45 | "type": "integer",
46 | "default": 0
47 | },
48 | "observation": {
49 | "remainingOverageTime": 60,
50 | "width": {
51 | "description": "The width of the map",
52 | "type": "integer",
53 | "shared": true,
54 | "default": 12
55 | },
56 | "height": {
57 | "description": "The height of the map",
58 | "type": "integer",
59 | "shared": true,
60 | "default": 12
61 | },
62 | "reward": {
63 | "description": "Current reward of the agent. Equal to number of city tiles * 10000 + number of units",
64 | "type": "integer",
65 | "default": 0
66 | },
67 | "updates": {
68 | "description": "List of update strings for agents to use and generate the observed state",
69 | "type": "array",
70 | "shared": true,
71 | "items": {
72 | "type": "string"
73 | }
74 | },
75 | "globalUnitIDCount": {
76 | "description": "Used purely to ensure state is the exact same including generated IDs",
77 | "type": "integer",
78 | "shared": true,
79 | "default": 0
80 | },
81 | "globalCityIDCount": {
82 | "description": "Used purely to ensure state is the exact same including generated IDs",
83 | "type": "integer",
84 | "shared": true,
85 | "default": 0
86 | },
87 | "player": {
88 | "description": "Current player's index / team id",
89 | "type": "integer",
90 | "defaults": [0, 1]
91 | }
92 | },
93 | "action": {
94 | "description": "Actions",
95 | "type": "array",
96 | "items": {
97 | "type": "string"
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_2021/test_agents/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * All game constants
3 | */
4 | const GAME_CONSTANTS = require('./game_constants.json');
5 |
6 | module.exports = GAME_CONSTANTS;
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.json:
--------------------------------------------------------------------------------
1 | {
2 | "UNIT_TYPES": {
3 | "WORKER": 0,
4 | "CART": 1
5 | },
6 | "RESOURCE_TYPES": {
7 | "WOOD": "wood",
8 | "COAL": "coal",
9 | "URANIUM": "uranium"
10 | },
11 | "DIRECTIONS": {
12 | "NORTH": "n",
13 | "WEST": "w",
14 | "EAST": "e",
15 | "SOUTH": "s",
16 | "CENTER": "c"
17 | },
18 | "PARAMETERS": {
19 | "DAY_LENGTH": 30,
20 | "NIGHT_LENGTH": 10,
21 | "MAX_DAYS": 360,
22 | "LIGHT_UPKEEP": {
23 | "CITY": 30,
24 | "WORKER": 4,
25 | "CART": 10
26 | },
27 | "WOOD_GROWTH_RATE": 1.01,
28 | "MAX_WOOD_AMOUNT": 500,
29 | "CITY_BUILD_COST": 100,
30 | "CITY_ADJACENCY_BONUS": 5,
31 | "RESOURCE_CAPACITY": {
32 | "WORKER": 100,
33 | "CART": 2000
34 | },
35 | "WORKER_COLLECTION_RATE": {
36 | "WOOD": 20,
37 | "COAL": 5,
38 | "URANIUM": 2
39 | },
40 | "RESOURCE_TO_FUEL_RATE": {
41 | "WOOD": 1,
42 | "COAL": 10,
43 | "URANIUM": 40
44 | },
45 | "RESEARCH_REQUIREMENTS": {
46 | "COAL": 50,
47 | "URANIUM": 200
48 | },
49 | "CITY_ACTION_COOLDOWN": 10,
50 | "UNIT_ACTION_COOLDOWN": {
51 | "CART": 3,
52 | "WORKER": 2
53 | },
54 | "MAX_ROAD": 6,
55 | "MIN_ROAD": 0,
56 | "CART_ROAD_DEVELOPMENT_RATE": 0.5,
57 | "PILLAGE_RATE": 0.5
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/io.js:
--------------------------------------------------------------------------------
1 | /** all constants related to any input from match engine */
2 | const INPUT_CONSTANTS = {
3 | DONE: 'D_DONE',
4 | RESEARCH_POINTS: 'rp',
5 | RESOURCES: 'r',
6 | UNITS: 'u',
7 | CITY: 'c',
8 | CITY_TILES: 'ct',
9 | ROADS: 'ccd',
10 | }
11 |
12 | module.exports = {
13 | INPUT_CONSTANTS,
14 | }
15 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/map.js:
--------------------------------------------------------------------------------
1 | const GAME_CONSTANTS = require('./game_constants');
2 | const DIRECTIONS = GAME_CONSTANTS.DIRECTIONS;
3 | class GameMap {
4 | constructor(width, height) {
5 | this.height = height;
6 | this.width = width;
7 | this.map = new Array(this.height);
8 |
9 | for (let y = 0; y < this.height; y++) {
10 | this.map[y] = new Array(this.width);
11 | for (let x = 0; x < this.width; x++) {
12 | this.map[y][x] = new Cell(x, y);
13 | }
14 | }
15 | }
16 | getCellByPos(pos) {
17 | return this.map[pos.y][pos.x];
18 | }
19 | getCell(x, y) {
20 | return this.map[y][x];
21 | }
22 | _setResource(type, x, y, amount) {
23 | const cell = this.getCell(x, y);
24 | cell.resource = {
25 | type: type,
26 | amount: amount
27 | }
28 | }
29 |
30 | }
31 |
32 | class Cell {
33 | constructor(x, y) {
34 | this.pos = new Position(x, y);
35 | this.resource = null;
36 | this.citytile = null;
37 | this.road = 0;
38 | }
39 | hasResource() {
40 | return this.resource !== null && this.resource.amount > 0;
41 | }
42 | }
43 |
44 | class Position {
45 | constructor(x, y) {
46 | this.x = x;
47 | this.y = y;
48 | }
49 | isAdjacent(pos) {
50 | const dx = this.x - pos.x;
51 | const dy = this.y - pos.y;
52 | if (Math.abs(dx) + Math.abs(dy) > 1) {
53 | return false;
54 | }
55 | return true;
56 | }
57 | equals(pos) {
58 | return this.x === pos.x && this.y === pos.y;
59 | }
60 |
61 | translate(direction, units) {
62 | switch (direction) {
63 | case DIRECTIONS.NORTH:
64 | return new Position(this.x, this.y - units);
65 | case DIRECTIONS.EAST:
66 | return new Position(this.x + units, this.y);
67 | case DIRECTIONS.SOUTH:
68 | return new Position(this.x, this.y + units);
69 | case DIRECTIONS.WEST:
70 | return new Position(this.x - units, this.y);
71 | case DIRECTIONS.CENTER:
72 | return new Position(this.x, this.y);
73 | }
74 | }
75 |
76 | /** Returns Manhattan distance to pos from this position */
77 | distanceTo(pos) {
78 | return Math.abs(pos.x - this.x) + Math.abs(pos.y - this.y);
79 | }
80 |
81 | /** Returns closest direction to targetPos, or null if staying put is best */
82 | directionTo(targetPos) {
83 | const checkDirections = [
84 | DIRECTIONS.NORTH,
85 | DIRECTIONS.EAST,
86 | DIRECTIONS.SOUTH,
87 | DIRECTIONS.WEST,
88 | ];
89 | let closestDirection = DIRECTIONS.CENTER;
90 | let closestDist = this.distanceTo(targetPos);
91 | checkDirections.forEach((dir) => {
92 | const newpos = this.translate(dir, 1);
93 | const dist = targetPos.distanceTo(newpos);
94 | if (dist < closestDist) {
95 | closestDist = dist;
96 | closestDirection = dir;
97 | }
98 | });
99 | return closestDirection;
100 | }
101 | }
102 |
103 | module.exports = {
104 | GameMap,
105 | Cell,
106 | Position,
107 | }
108 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/parser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Parser class to help parse a input line of data
3 | */
4 | class Parser {
5 |
6 | constructor(d = ',') {
7 | this.delimiter = d;
8 | return this.parse.bind(this);
9 | }
10 | setDelimeter(s) {
11 | this.delimiter = s;
12 | }
13 | parse(str) {
14 | return new Parsed(str, this.delimiter);
15 | }
16 |
17 | }
18 | class Parsed {
19 | constructor(str, d) {
20 | this.str = str;
21 | this.contents = str.split(d);
22 |
23 | // remove the last element if its empty string
24 | if (this.contents[this.contents.length - 1] === '') {
25 | this.contents = this.contents.slice(0, this.contents.length - 1);
26 | }
27 | this.index = 0;
28 | }
29 | _nextStr() {
30 | if (this.index < this.contents.length) {
31 | return this.contents[this.index++];
32 | }
33 | else {
34 | throw new Error("No more contents to consume from line")
35 | }
36 | }
37 | // Returns the remainder of the line as an array of integers
38 | nextIntArr() {
39 | if (this.index < this.contents.length) {
40 | let remainder = this.contents.slice(this.index, this.contents.length).map((val) => parseInt(val));
41 | return remainder;
42 | }
43 | else {
44 | throw new Error("No more contents to consume from line")
45 | }
46 | }
47 | nextInt() {
48 | let str = this._nextStr();
49 | return parseInt(str);
50 | }
51 | // Returns the remainder of the line as an array of floats
52 | nextFloatArr() {
53 | if (this.index < this.contents.length) {
54 | let remainder = this.contents.slice(this.index++).map((val) => parseFloat(val));
55 | return remainder;
56 | }
57 | else {
58 | throw new Error("No more contents to consume from line")
59 | }
60 | }
61 | nextFloat() {
62 | let str = this._nextStr();
63 | return parseFloat(str);
64 | }
65 | // Returns the remainder of the line as an array of strings
66 | nextStrArr() {
67 | if (this.index < this.contents.length) {
68 | let remainder = this.contents.slice(this.index++);
69 | return remainder;
70 | }
71 | else {
72 | throw new Error("No more contents to consume from line")
73 | }
74 | }
75 | nextStr() {
76 | return this._nextStr();
77 | }
78 | }
79 | module.exports = Parser
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.js:
--------------------------------------------------------------------------------
1 | const kit = require('./lux/kit');
2 | const GAME_CONSTANTS = require('./lux/game_constants');
3 | const DIRECTIONS = GAME_CONSTANTS.DIRECTIONS;
4 | // create a new agent
5 | const agent = new kit.Agent();
6 | const annotate = kit.annotate;
7 |
8 | // first initialize the agent, and then proceed to go in a loop waiting for updates and running the AI
9 | agent.initialize().then(async () => {
10 | while (true) {
11 | /** Do not edit! **/
12 | // wait for updates
13 | await agent.update();
14 |
15 | const actions = [];
16 | const gameState = agent.gameState;
17 | /** AI Code Goes Below! **/
18 |
19 | const player = gameState.players[gameState.id];
20 | const opponent = gameState.players[(gameState.id + 1) % 2];
21 | const gameMap = gameState.map;
22 |
23 | const resourceTiles = [];
24 | for (let y = 0; y < gameMap.height; y++) {
25 | for (let x = 0; x < gameMap.width; x++) {
26 | const cell = gameMap.getCell(x, y);
27 | if (cell.hasResource()) {
28 | resourceTiles.push(cell);
29 | }
30 | }
31 | }
32 |
33 | // we iterate over all our units and do something with them
34 | for (let i = 0; i < player.units.length; i++) {
35 | const unit = player.units[i];
36 | if (unit.isWorker() && unit.canAct()) {
37 | if (unit.getCargoSpaceLeft() > 0) {
38 | // if the unit is a worker and we have space in cargo, lets find the nearest resource tile and try to mine it
39 | let closestResourceTile = null;
40 | let closestDist = 9999999;
41 | resourceTiles.forEach((cell) => {
42 | if (cell.resource.type === GAME_CONSTANTS.RESOURCE_TYPES.COAL && !player.researchedCoal()) return;
43 | if (cell.resource.type === GAME_CONSTANTS.RESOURCE_TYPES.URANIUM && !player.researchedUranium()) return;
44 | const dist = cell.pos.distanceTo(unit.pos);
45 | if (dist < closestDist) {
46 | closestDist = dist;
47 | closestResourceTile = cell;
48 | }
49 | })
50 | if (closestResourceTile != null) {
51 | const dir = unit.pos.directionTo(closestResourceTile.pos);
52 | // move the unit in the direction towards the closest resource tile's position.
53 | actions.push(unit.move(dir));
54 | }
55 | } else {
56 | // if unit is a worker and there is no cargo space left, and we have cities, lets return to them
57 | if (player.cities.size > 0) {
58 | const city = player.cities.values().next().value
59 | let closestDist = 999999;
60 | let closestCityTile = null;
61 |
62 | city.citytiles.forEach((citytile) => {
63 | const dist = citytile.pos.distanceTo(unit.pos);
64 | if (dist < closestDist) {
65 | closestCityTile = citytile;
66 | closestDist = dist;
67 | }
68 | });
69 | if (closestCityTile != null) {
70 | const dir = unit.pos.directionTo(closestCityTile.pos);
71 | actions.push(unit.move(dir));
72 | }
73 | }
74 | }
75 | }
76 | }
77 |
78 | // you can add debug annotations using the functions in the annotate object
79 | // actions.push(annotate.circle(0, 0))
80 |
81 | /** AI Code Goes Above! **/
82 |
83 | /** Do not edit! **/
84 | console.log(actions.join(","));
85 | // end turn
86 | agent.endTurn();
87 | }
88 | });
89 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.py:
--------------------------------------------------------------------------------
1 | from subprocess import Popen, PIPE
2 | from threading import Thread
3 | from queue import Queue, Empty
4 |
5 | import atexit
6 | import os
7 | import sys
8 | agent_processes = [None, None]
9 | t = None
10 | q = None
11 | def cleanup_process():
12 | global agent_processes
13 | for proc in agent_processes:
14 | if proc is not None:
15 | proc.kill()
16 | def enqueue_output(out, queue):
17 | for line in iter(out.readline, b''):
18 | queue.put(line)
19 | out.close()
20 | def js_agent(observation, configuration):
21 | """
22 | a wrapper around a js agent
23 | """
24 | global agent_processes, t, q
25 |
26 | agent_process = agent_processes[observation.player]
27 | ### Do not edit ###
28 | if agent_process is None:
29 | if "__raw_path__" in configuration:
30 | cwd = os.path.dirname(configuration["__raw_path__"])
31 | else:
32 | cwd = os.path.dirname(__file__)
33 | agent_process = Popen(["node", "main.js"], stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=cwd)
34 | agent_processes[observation.player] = agent_process
35 | atexit.register(cleanup_process)
36 |
37 | # following 4 lines from https://stackoverflow.com/questions/375427/a-non-blocking-read-on-a-subprocess-pipe-in-python
38 | q = Queue()
39 | t = Thread(target=enqueue_output, args=(agent_process.stderr, q))
40 | t.daemon = True # thread dies with the program
41 | t.start()
42 | if observation.step == 0:
43 | # fixes bug where updates array is shared, but the first update is agent dependent actually
44 | observation["updates"][0] = f"{observation.player}"
45 |
46 | # print observations to agent
47 | agent_process.stdin.write(("\n".join(observation["updates"]) + "\n").encode())
48 | agent_process.stdin.flush()
49 |
50 | # wait for data written to stdout
51 | agent1res = (agent_process.stdout.readline()).decode()
52 | _end_res = (agent_process.stdout.readline()).decode()
53 |
54 | while True:
55 | try: line = q.get_nowait()
56 | except Empty:
57 | # no standard error received, break
58 | break
59 | else:
60 | # standard error output received, print it out
61 | print(line.decode(), file=sys.stderr, end='')
62 |
63 | outputs = agent1res.split("\n")[0].split(",")
64 | actions = []
65 | for cmd in outputs:
66 | if cmd != "":
67 | actions.append(cmd)
68 | return actions
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/simple.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/simple.tar.gz
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/annotate.py:
--------------------------------------------------------------------------------
1 | def circle(x: int, y: int) -> str:
2 | return f"dc {x} {y}"
3 |
4 | def x(x: int, y: int) -> str:
5 | return f"dx {x} {y}"
6 |
7 | def line(x1: int, y1: int, x2: int, y2: int) -> str:
8 | return f"dl {x1} {y1} {x2} {y2}"
9 |
10 | # text at cell on map
11 | def text(x: int, y: int, message: str, fontsize: int = 16) -> str:
12 | return f"dt {x} {y} {fontsize} '{message}'"
13 |
14 | # text besides map
15 | def sidetext(message: str) -> str:
16 | return f"dst '{message}'"
17 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/constants.py:
--------------------------------------------------------------------------------
1 | class Constants:
2 | class INPUT_CONSTANTS:
3 | RESEARCH_POINTS = "rp"
4 | RESOURCES = "r"
5 | UNITS = "u"
6 | CITY = "c"
7 | CITY_TILES = "ct"
8 | ROADS = "ccd"
9 | DONE = "D_DONE"
10 | class DIRECTIONS:
11 | NORTH = "n"
12 | WEST = "w"
13 | SOUTH = "s"
14 | EAST = "e"
15 | CENTER = "c"
16 | class UNIT_TYPES:
17 | WORKER = 0
18 | CART = 1
19 | class RESOURCE_TYPES:
20 | WOOD = "wood"
21 | URANIUM = "uranium"
22 | COAL = "coal"
23 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game.py:
--------------------------------------------------------------------------------
1 | from .constants import Constants
2 | from .game_map import GameMap
3 | from .game_objects import Player, Unit, City, CityTile
4 |
5 | INPUT_CONSTANTS = Constants.INPUT_CONSTANTS
6 |
7 |
8 | class Game:
9 | def _initialize(self, messages):
10 | """
11 | initialize state
12 | """
13 | self.id = int(messages[0])
14 | self.turn = -1
15 | # get some other necessary initial input
16 | mapInfo = messages[1].split(" ")
17 | self.map_width = int(mapInfo[0])
18 | self.map_height = int(mapInfo[1])
19 | self.map = GameMap(self.map_width, self.map_height)
20 | self.players = [Player(0), Player(1)]
21 |
22 | def _end_turn(self):
23 | print("D_FINISH")
24 |
25 | def _reset_player_states(self):
26 | self.players[0].units = []
27 | self.players[0].cities = {}
28 | self.players[0].city_tile_count = 0
29 | self.players[1].units = []
30 | self.players[1].cities = {}
31 | self.players[1].city_tile_count = 0
32 |
33 | def _update(self, messages):
34 | """
35 | update state
36 | """
37 | self.map = GameMap(self.map_width, self.map_height)
38 | self.turn += 1
39 | self._reset_player_states()
40 |
41 | for update in messages:
42 | if update == "D_DONE":
43 | break
44 | strs = update.split(" ")
45 | input_identifier = strs[0]
46 | if input_identifier == INPUT_CONSTANTS.RESEARCH_POINTS:
47 | team = int(strs[1])
48 | self.players[team].research_points = int(strs[2])
49 | elif input_identifier == INPUT_CONSTANTS.RESOURCES:
50 | r_type = strs[1]
51 | x = int(strs[2])
52 | y = int(strs[3])
53 | amt = int(float(strs[4]))
54 | self.map._setResource(r_type, x, y, amt)
55 | elif input_identifier == INPUT_CONSTANTS.UNITS:
56 | unittype = int(strs[1])
57 | team = int(strs[2])
58 | unitid = strs[3]
59 | x = int(strs[4])
60 | y = int(strs[5])
61 | cooldown = float(strs[6])
62 | wood = int(strs[7])
63 | coal = int(strs[8])
64 | uranium = int(strs[9])
65 | self.players[team].units.append(Unit(team, unittype, unitid, x, y, cooldown, wood, coal, uranium))
66 | elif input_identifier == INPUT_CONSTANTS.CITY:
67 | team = int(strs[1])
68 | cityid = strs[2]
69 | fuel = float(strs[3])
70 | lightupkeep = float(strs[4])
71 | self.players[team].cities[cityid] = City(team, cityid, fuel, lightupkeep)
72 | elif input_identifier == INPUT_CONSTANTS.CITY_TILES:
73 | team = int(strs[1])
74 | cityid = strs[2]
75 | x = int(strs[3])
76 | y = int(strs[4])
77 | cooldown = float(strs[5])
78 | city = self.players[team].cities[cityid]
79 | citytile = city._add_city_tile(x, y, cooldown)
80 | self.map.get_cell(x, y).citytile = citytile
81 | self.players[team].city_tile_count += 1;
82 | elif input_identifier == INPUT_CONSTANTS.ROADS:
83 | x = int(strs[1])
84 | y = int(strs[2])
85 | road = float(strs[3])
86 | self.map.get_cell(x, y).road = road
87 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.json:
--------------------------------------------------------------------------------
1 | {
2 | "UNIT_TYPES": {
3 | "WORKER": 0,
4 | "CART": 1
5 | },
6 | "RESOURCE_TYPES": {
7 | "WOOD": "wood",
8 | "COAL": "coal",
9 | "URANIUM": "uranium"
10 | },
11 | "DIRECTIONS": {
12 | "NORTH": "n",
13 | "WEST": "w",
14 | "EAST": "e",
15 | "SOUTH": "s",
16 | "CENTER": "c"
17 | },
18 | "PARAMETERS": {
19 | "DAY_LENGTH": 30,
20 | "NIGHT_LENGTH": 10,
21 | "MAX_DAYS": 360,
22 | "LIGHT_UPKEEP": {
23 | "CITY": 30,
24 | "WORKER": 4,
25 | "CART": 10
26 | },
27 | "WOOD_GROWTH_RATE": 1.01,
28 | "MAX_WOOD_AMOUNT": 500,
29 | "CITY_BUILD_COST": 100,
30 | "CITY_ADJACENCY_BONUS": 5,
31 | "RESOURCE_CAPACITY": {
32 | "WORKER": 100,
33 | "CART": 2000
34 | },
35 | "WORKER_COLLECTION_RATE": {
36 | "WOOD": 20,
37 | "COAL": 5,
38 | "URANIUM": 2
39 | },
40 | "RESOURCE_TO_FUEL_RATE": {
41 | "WOOD": 1,
42 | "COAL": 10,
43 | "URANIUM": 40
44 | },
45 | "RESEARCH_REQUIREMENTS": {
46 | "COAL": 50,
47 | "URANIUM": 200
48 | },
49 | "CITY_ACTION_COOLDOWN": 10,
50 | "UNIT_ACTION_COOLDOWN": {
51 | "CART": 3,
52 | "WORKER": 2
53 | },
54 | "MAX_ROAD": 6,
55 | "MIN_ROAD": 0,
56 | "CART_ROAD_DEVELOPMENT_RATE": 0.5,
57 | "PILLAGE_RATE": 0.5
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.py:
--------------------------------------------------------------------------------
1 | import json
2 | from os import path
3 | dir_path = path.dirname(__file__)
4 | constants_path = path.abspath(path.join(dir_path, "game_constants.json"))
5 | with open(constants_path) as f:
6 | GAME_CONSTANTS = json.load(f)
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_agents/python/random_agent.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import random
3 | if __package__ == "":
4 | # for kaggle-environments
5 | from lux.game import Game
6 | from lux.game_map import Cell, RESOURCE_TYPES
7 | from lux.constants import Constants
8 | from lux.game_constants import GAME_CONSTANTS
9 | from lux import annotate
10 | else:
11 | # for CLI tool
12 | from .lux.game import Game
13 | from .lux.game_map import Cell, RESOURCE_TYPES
14 | from .lux.constants import Constants
15 | from .lux.game_constants import GAME_CONSTANTS
16 | from .lux import annotate
17 | DIRECTIONS = Constants.DIRECTIONS
18 | game_state = None
19 |
20 | def random_agent(observation, configuration):
21 | """
22 | a blank, completely empty agent, usually incapable of surviving past the first night
23 | """
24 | global game_state
25 |
26 | ### Do not edit ###
27 | if observation["step"] == 0:
28 | game_state = Game()
29 | game_state._initialize(observation["updates"])
30 | game_state._update(observation["updates"][2:])
31 | else:
32 | game_state._update(observation["updates"])
33 |
34 | actions = []
35 |
36 | ### AI Code goes down here! ###
37 | player = game_state.players[observation.player]
38 | for unit in player.units:
39 | dirs = [DIRECTIONS.NORTH, DIRECTIONS.WEST, DIRECTIONS.EAST, DIRECTIONS.SOUTH]
40 | action = unit.move(random.choice(dirs))
41 | actions.append(action)
42 |
43 | return actions
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/test_lux.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from kaggle_environments import make
3 | from .agents import random_agent, js_simple_agent, simple_agent
4 |
5 | def test_lux_completes():
6 | env = make("lux_ai_2021", configuration={})
7 | env.run([random_agent, simple_agent])
8 | json = env.toJSON()
9 | assert json["name"] == "lux_ai_2021"
10 | assert json["statuses"] == ["DONE", "DONE"]
11 |
12 | def test_js_agents():
13 | env = make("lux_ai_2021", configuration={})
14 | env.run([simple_agent, js_simple_agent])
15 | json = env.toJSON()
16 | assert json["name"] == "lux_ai_2021"
17 | assert json["statuses"] == ["DONE", "DONE"]
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/testing.md:
--------------------------------------------------------------------------------
1 | Unfortunately at this moment, there isn't a progammatic way to test if the Kaggle Engine is the exact same as the engine competitors use when local testing. This is part of a TODO to make kaggle replays match the local replays players generate when they develop locally using https://github.com/Lux-AI-Challenge/Lux-Design-2021
2 |
3 | The following steps work for now:
4 |
5 | First download the simple kit from https://github.com/Lux-AI-Challenge/Lux-Design-2021/tree/master/kits/python (or another language) or use your own bot
6 |
7 | First run a game in Kaggle like so:
8 |
9 | ```
10 | kaggle-environments run --environment lux_ai_2021 --agents path/to/bot/main.py path/to/bot/main.py --render '{"mode": "json"}' --out out.json --debug=True
11 | ```
12 |
13 | Then upload the out.json to https://2021vis.lux-ai.org/ and go to the final turn.
14 |
15 | Then install the local engine `npm i -g install @lux-ai/2021-challenge` if you haven't done so already (you can remove `-g` and do `npx lux-ai-2021` as opposed to `lux-ai-2021`)
16 |
17 | Then run
18 |
19 | ```
20 | lux-ai-2021 path/to/bot/main.py path/to/bot/main.py --out=replay.json
21 | ```
22 |
23 | upload `replay.json` to the replay viewer again in a new tab and compare the final state with the other kaggle produced match. If the statistics and layout of units on the map match, then the engine is working correctly. (Given the complexity of the game and that `lux-ai-2021` generates action based replays, should a single thing be wrong, the differences in the final turn would be fairly massive so this is generally a sufficient test)
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_2021/todo.md.og:
--------------------------------------------------------------------------------
1 | # TODOs
2 |
3 |
4 | [x] Setup Visualizer
5 |
6 | [x] Keep dimensions engine results consistent with kaggle-env integated version
7 |
8 | [ ] Verify rewards work correctly
9 |
10 | [ ] display correct agent names
11 |
12 | [ ] default turn debug mode off
13 |
14 | [ ] add tests for more bots
15 |
16 | [ ] allow user to pass in custom configurations
17 |
18 | [ ] allow user to specify debug mode level for the dimensions engine
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/.gitignore:
--------------------------------------------------------------------------------
1 | build/
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/README.md:
--------------------------------------------------------------------------------
1 | # Lux AI Challenge Season 2
2 |
3 | Welcome to the Kaggle Environments wrapped around the Lux AI Challenge Season 2! For more information or if you have an issues or want to make contributes, check out the main repository at https://github.com/Lux-AI-Challenge/Lux-Design-2022
4 |
5 | ## Test scripts
6 |
7 | ```
8 | kaggle-environments run --environment lux_ai_2022 --agents path/to/bot/main.py path/to/bot/main.py --render '{"mode": "json"}' --out out.json --debug=True
9 | ```
10 |
11 | ```
12 | kaggle-environments run --environment lux_ai_2022 --agents ../Lux-Design-2022/kits/js/main.py ../Lux-Design-2022/kits/js/main.py --render '{"mode": "json"}' --out out.json --debug=True
13 | ```
14 |
15 | ## Packaging external packages locally
16 |
17 | git clone open_simplex and petting zoo directly and move them into here
18 |
19 | ## Visualizer
20 |
21 | Ensure that the script module is at the bottom of tag.
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/agents.py:
--------------------------------------------------------------------------------
1 | from .test_agents.python.main import agent_fn as random_agent
2 | all_agents = {
3 | "random_agent": random_agent,
4 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Lux Eye S2
9 |
10 |
11 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/lux_ai_s2.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lux_ai_s2",
3 | "title": "Lux AI Challenge Season 2",
4 | "description": "A Novel AI Programming Challenge about Lux",
5 | "version": "2.1.7",
6 | "agents": [2],
7 | "configuration": {
8 | "episodeSteps": {
9 | "description": "Maximum number of steps the environment can run. Total is this number -1. One complete game is 1000 + N * 2 + 1 steps where N is number of factories each player is given.",
10 | "type": "integer",
11 | "minimum": 2,
12 | "default": 1020
13 | },
14 | "max_episode_length": {
15 | "description": "Max game steps the environment can run, not including the early phase of the game.",
16 | "minimum": 2,
17 | "type": "integer",
18 | "default": 1000
19 | },
20 | "seed": {
21 | "description": "Seed to use for episodes",
22 | "type": "integer"
23 | },
24 | "actTimeout": 3,
25 | "runTimeout": 9600,
26 | "env_cfg": {
27 | "type": "object"
28 | }
29 | },
30 | "reward": {
31 | "description": "Reward of the agent. Equal to amount of lichen grown.",
32 | "type": "integer",
33 | "default": 0
34 | },
35 | "observation": {
36 | "remainingOverageTime": 60,
37 | "width": {
38 | "description": "The width of the map",
39 | "type": "integer",
40 | "shared": true,
41 | "default": 48
42 | },
43 | "height": {
44 | "description": "The height of the map",
45 | "type": "integer",
46 | "shared": true,
47 | "default": 48
48 | },
49 | "reward": {
50 | "description": "Current reward of the agent. Equal to amount of lichen grown.",
51 | "type": "integer",
52 | "default": 0
53 | },
54 | "obs": {
55 | "description": "String containing the observations",
56 | "type": "string",
57 | "shared": true
58 | },
59 | "player": {
60 | "description": "Current player's index / team id",
61 | "type": "string",
62 | "defaults": "player_0"
63 | },
64 | "stats": {
65 | "description": "Aggregate statistics for an episode",
66 | "type": "object"
67 | }
68 | },
69 | "action": {
70 | "description": "Actions",
71 | "type": "object"
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/.DS_Store
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/__init__.py:
--------------------------------------------------------------------------------
1 | from .env import LuxAI_S2
2 | from .version import __version__
3 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/globals.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | TERM_COLORS = True
4 | try:
5 | from termcolor import colored
6 |
7 | TERM_COLORS = (
8 | os.environ["LUX_COLORS"] == "False" if "LUX_COLORS" in os.environ else True
9 | )
10 | except:
11 | TERM_COLORS = False
12 | print("termcolor not installed, skipping dependency")
13 | pass
14 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/map/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map/bfs_deltas_gen.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | move_deltas = np.array([[0, 0], [0, -1], [1, 0], [0, 1], [-1, 0]])
4 |
5 |
6 | def gen_deltas(size=3):
7 | start = (0, 0)
8 | f = [start]
9 | seen = set()
10 | r = set()
11 | while len(f) > 0:
12 | pos = f.pop(0)
13 | seen.add(pos)
14 | if abs(pos[0]) + abs(pos[1]) > size:
15 | break
16 | r.add(pos)
17 | for md in move_deltas:
18 | new_pos = (pos[0] + md[0], pos[1] + md[1])
19 | if new_pos not in seen:
20 | f.append(new_pos)
21 | print(r)
22 |
23 |
24 | gen_deltas(6)
25 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map/position.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 |
4 | class Position:
5 | def __init__(self, pos: np.ndarray) -> None:
6 | self.pos: np.ndarray = pos
7 |
8 | @property
9 | def x(self) -> int:
10 | return self.pos[0]
11 |
12 | @property
13 | def y(self) -> int:
14 | return self.pos[1]
15 |
16 | def __add__(self, o):
17 | if isinstance(o, Position):
18 | return Position(pos=self.pos + o.pos)
19 | else:
20 | return Position(pos=self.pos + o)
21 |
22 | def __sub__(self, o):
23 | if isinstance(o, Position):
24 | return Position(pos=self.pos - o.pos)
25 | else:
26 | return Position(pos=self.pos - o)
27 |
28 | def __str__(self) -> str:
29 | return f"({self.x}, {self.y})"
30 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/.DS_Store
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/__init__.py:
--------------------------------------------------------------------------------
1 | from .generator import GameMap
2 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/timing.py:
--------------------------------------------------------------------------------
1 | import timeit
2 |
3 | N = 100
4 | for map_type in ["Cave", "Craters", "Island", "Mountain"]:
5 | time = timeit.timeit(
6 | f"{map_type}(64, 64)", setup=f"from generator import {map_type}", number=N
7 | )
8 | print(f"Took {time / N * 1000:.2f}ms for {map_type}.")
9 |
10 |
11 | # If you want to use cProfile, you can look in git history.
12 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/visualize.py:
--------------------------------------------------------------------------------
1 | # A quick visualizer to aid in map generating algorithms.
2 | try:
3 | import pygame
4 | except:
5 | pass
6 | import numpy as np
7 |
8 |
9 | def viz(game_map, screen=None):
10 | N = min(500 // game_map.width, 750 // game_map.height)
11 | if screen is None:
12 | screen = pygame.display.set_mode((3 * N * game_map.width, N * game_map.height))
13 |
14 | for x in range(game_map.width):
15 | for y in range(game_map.height):
16 | rubble_color = [255 - game_map.rubble[y][x] * 255 / 100] * 3
17 | ice_color = [0, 0, game_map.ice[y][x] * 255 / 100]
18 | ore_color = [game_map.ore[y][x] * 255 / 100, 0, 0]
19 | screen.fill(rubble_color, (N * x, N * y, N, N))
20 | screen.fill(ice_color, (N * x + N * game_map.width, N * y, N, N))
21 | screen.fill(ore_color, (N * x + 2 * N * game_map.width, N * y, N, N))
22 | pygame.display.update()
23 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/map_generator/visualize_samples.py:
--------------------------------------------------------------------------------
1 | from math import prod
2 | from pathlib import Path
3 |
4 | import numpy as np
5 | import pygame
6 |
7 | from luxai_s2.env import LuxAI_S2
8 |
9 | if __name__ == "__main__":
10 | env = LuxAI_S2()
11 | N = 100
12 | Path("./map_samples").mkdir(parents=True, exist_ok=True)
13 | stats = dict(rubble_count=[], ice=[], ore=[])
14 | for seed in range(10000, 10000 + N):
15 | env.reset(seed)
16 | env.render()
17 | env.py_visualizer.update_scene(env.state)
18 |
19 | pygame.image.save(env.py_visualizer.screen, f"map_samples/{seed}.jpg")
20 | stats["ice"] += [env.state.board.ice.sum()]
21 | stats["ore"] += [env.state.board.ore.sum()]
22 | stats["rubble_count"] += [env.state.board.rubble.sum()]
23 |
24 | for k in stats:
25 | stats[k] = np.mean(stats[k])
26 | stats["rubble_count"] /= prod(env.state.board.rubble.shape)
27 | print(stats)
28 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/pyvisual/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/pyvisual/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/replay/__init__.py:
--------------------------------------------------------------------------------
1 | from .replay import decode_replay_file, generate_replay
2 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/replay/replay.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import os.path as osp
4 | from typing import List, Tuple
5 |
6 | from luxai_s2.state import State
7 |
8 |
9 | def decode_replay_file(replay_file) -> Tuple[State, List]:
10 | """
11 | Takes an input replay file of any kind from any source and extracts the full trajectory with observations
12 | or just initial state and actions if observations aren't there
13 | """
14 | ext = osp.splitext(replay_file)[-1]
15 | if ext == ".json":
16 | # probably kaggle replay
17 | with open(replay_file, "r") as f:
18 | replay = json.load(f)
19 | init_state = replay["init_state"]
20 | pass
21 | elif ext == ".h5":
22 | pass
23 |
24 |
25 | def generate_replay(states: List[State]):
26 | """
27 | Generates a compressed replay.
28 |
29 | """
30 | return [s.get_compressed_obs() for s in states]
31 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/spaces/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/spaces/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/state/__init__.py:
--------------------------------------------------------------------------------
1 | from .state import DeltaObservationStateDict, ObservationStateDict, State
2 | from .stats import StatsStateDict, create_empty_stats
3 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/state/typing.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/state/typing.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/team.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from enum import Enum
3 | from typing import List
4 | try:
5 | from typing import TypedDict
6 | except:
7 | from typing_extensions import TypedDict
8 |
9 | from luxai_s2.config import EnvConfig
10 | from luxai_s2.globals import TERM_COLORS
11 |
12 | try:
13 | from termcolor import colored
14 | except:
15 | pass
16 |
17 |
18 | @dataclass
19 | class FactionInfo:
20 | color: str = "none"
21 | alt_color: str = "red"
22 | faction_id: int = -1
23 |
24 |
25 | class FactionTypes(Enum):
26 | AlphaStrike = FactionInfo(color="yellow", faction_id=0)
27 | MotherMars = FactionInfo(color="green", faction_id=1)
28 | TheBuilders = FactionInfo(color="blue", faction_id=2)
29 | FirstMars = FactionInfo(color="red", faction_id=3)
30 |
31 |
32 | class TeamStateDict(TypedDict):
33 | team_id: int
34 | faction: str
35 | water: int
36 | metal: int
37 | factories_to_place: int
38 | factory_strains: List[int]
39 | place_first: bool
40 | bid: int
41 |
42 |
43 | class Team:
44 | def __init__(self, team_id: int, agent: str, faction: FactionTypes = None) -> None:
45 | self.faction = faction
46 | self.team_id = team_id
47 | # the key used to differentiate ownership of things in state
48 | self.agent = agent
49 |
50 | self.init_water = 0
51 | self.init_metal = 0
52 | self.factories_to_place = 0
53 | self.factory_strains = []
54 |
55 | # whether this team gets to place factories down first or not. The bid winner has this set to True.
56 | # If tied, player_0's team has this True
57 | self.place_first = False
58 |
59 | self.bid = 0
60 |
61 | def state_dict(self) -> TeamStateDict:
62 | return dict(
63 | team_id=self.team_id,
64 | faction=self.faction.name,
65 | # note for optimization, water,metal, factories_to_place doesn't change after the early game.
66 | water=self.init_water,
67 | metal=self.init_metal,
68 | factories_to_place=self.factories_to_place,
69 | factory_strains=self.factory_strains,
70 | place_first=self.place_first,
71 | bid=self.bid,
72 | )
73 |
74 | def __str__(self) -> str:
75 | out = f"[Player {self.team_id}]"
76 | if TERM_COLORS:
77 | return colored(out, self.faction.value.color)
78 | return out
79 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s2/luxai_s2/tools/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/tools/replay.py:
--------------------------------------------------------------------------------
1 | import os
2 | import os.path as osp
3 | from typing import List
4 |
5 | from luxai_s2.replay import decode_replay_file
6 | from luxai_s2.state import State
7 |
8 |
9 | def replay_trajectory(replay_file: str):
10 | decoded = decode_replay_file(replay_file)
11 | if "observations" in decoded:
12 | print("replay file already contains observations, there is nothing to do")
13 | return replay_file
14 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .animate import animate
2 | from .utils import is_day, my_turn_to_place_factory
3 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/animate.py:
--------------------------------------------------------------------------------
1 | def animate(imgs, _return=True, fps=10, filename="__temp__.mp4"):
2 | from moviepy.editor import ImageSequenceClip
3 |
4 | clip = ImageSequenceClip(imgs, fps=fps)
5 | clip.write_videofile(filename, verbose=False, logger=None)
6 | if _return:
7 | from IPython.display import Video
8 |
9 | return Video(filename)
10 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/heuristics/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/heuristics/bidding.py:
--------------------------------------------------------------------------------
1 | from luxai_s2.unit import BidActionType
2 | from luxai_s2.state import ObservationStateDict
3 | def zero_bid(player, obs: ObservationStateDict) -> BidActionType:
4 | faction = "AlphaStrike"
5 | if player == "player_1":
6 | faction = "MotherMars"
7 | return dict(bid=0, faction=faction)
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/heuristics/factory.py:
--------------------------------------------------------------------------------
1 | from luxai_s2.state import ObservationStateDict
2 |
3 |
4 | def build_single_heavy(agent, obs: ObservationStateDict):
5 | actions = dict()
6 | if agent == "player_0":
7 | factories = obs["factories"][agent]
8 | units = obs["units"][agent]
9 | if len(units) == 0:
10 | for unit_id in factories:
11 | factory = factories[unit_id]
12 | # if factory["cargo"]["metal"] >= 100:
13 | actions[unit_id] = 1 # build a heavy
14 |
15 | return actions
16 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/heuristics/factory_placement.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from luxai_s2.unit import FactoryPlacementActionType
3 | from luxai_s2.state import ObservationStateDict
4 |
5 | def random_factory_placement(player, obs: ObservationStateDict) -> FactoryPlacementActionType:
6 | """
7 | This policy places factories with 150 water and metal at random locations
8 | """
9 | # we will spawn our factory in a random location with 150 metal and water if it is our turn to place
10 | potential_spawns = np.array(list(zip(*np.where(obs["board"]["valid_spawns_mask"] == 1))))
11 | spawn_loc = potential_spawns[np.random.randint(0, len(potential_spawns))]
12 | return dict(spawn=spawn_loc, metal=150, water=150)
13 |
14 | def place_near_random_ice(player, obs: ObservationStateDict):
15 | if obs["teams"][player]["metal"] == 0:
16 | return dict()
17 | potential_spawns = list(zip(*np.where(obs["board"]["valid_spawns_mask"] == 1)))
18 | potential_spawns_set = set(potential_spawns)
19 | done_search = False
20 | # if player == "player_1":
21 | ice_diff = np.diff(obs["board"]["ice"])
22 | pot_ice_spots = np.argwhere(ice_diff == 1)
23 | if len(pot_ice_spots) == 0:
24 | pot_ice_spots = potential_spawns
25 | trials = 5
26 | while trials > 0:
27 | pos_idx = np.random.randint(0, len(pot_ice_spots))
28 | pos = pot_ice_spots[pos_idx]
29 |
30 | area = 3
31 | for x in range(area):
32 | for y in range(area):
33 | check_pos = [pos[0] + x - area // 2, pos[1] + y - area // 2]
34 | if tuple(check_pos) in potential_spawns_set:
35 | done_search = True
36 | pos = check_pos
37 | break
38 | if done_search:
39 | break
40 | if done_search:
41 | break
42 | trials -= 1
43 | spawn_loc = potential_spawns[np.random.randint(0, len(potential_spawns))]
44 | if not done_search:
45 | pos = spawn_loc
46 |
47 | metal = obs["teams"][player]["metal"]
48 | return dict(spawn=pos, metal=metal, water=metal)
49 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/utils/utils.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from luxai_s2.config import EnvConfig
4 | from luxai_s2.unit import Unit, UnitType
5 |
6 |
7 | def is_day(config: EnvConfig, env_step):
8 | return env_step % config.CYCLE_LENGTH < config.DAY_LENGTH
9 |
10 |
11 | def get_top_two_power_units(units: List[Unit], unit_type: UnitType):
12 | most_power_unit: Unit = units[0]
13 | most_power = -1
14 | next_most_power_unit: Unit = units[1]
15 | next_most_power = -1
16 | for u in units:
17 | if u.unit_type == unit_type:
18 | if u.power > most_power:
19 | next_most_power_unit = most_power_unit
20 | most_power_unit = u
21 | most_power = u.power
22 | elif (
23 | u.power >= next_most_power
24 | ): # >= check since we want to top 2 power units which can tie
25 | next_most_power_unit = u
26 | next_most_power = u.power
27 |
28 | return (most_power_unit, next_most_power_unit)
29 |
30 |
31 | def my_turn_to_place_factory(place_first: bool, step: int):
32 | if place_first:
33 | if step % 2 == 1:
34 | return True
35 | else:
36 | if step % 2 == 0:
37 | return True
38 | return False
39 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/version.py:
--------------------------------------------------------------------------------
1 | __version__ = ""
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/wrappers/__init__.py:
--------------------------------------------------------------------------------
1 | from .controllers import Controller
2 | from .sb3 import SB3Wrapper
3 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/luxai_s2/wrappers/controllers.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Any
2 |
3 | import numpy.typing as npt
4 | from gymnasium import spaces
5 |
6 | class Controller:
7 | def __init__(self, action_space: spaces.Space) -> None:
8 | self.action_space = action_space
9 |
10 | def action_to_lux_action(
11 | self, agent: str, obs: Dict[str, Any], action: npt.NDArray
12 | ):
13 | """
14 | Takes as input the current "raw observation" and the parameterized action and returns
15 | an action formatted for the Lux env
16 | """
17 | raise NotImplementedError()
18 | def action_masks(self, agent: str, obs: Dict[str, Any]):
19 | """
20 | Generates a boolean action mask indicating in each discrete dimension whether it would be valid or not
21 | """
22 | raise NotImplementedError()
23 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_agents/python/lux/cargo.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 |
3 | @dataclass
4 | class UnitCargo:
5 | ice: int = 0
6 | ore: int = 0
7 | water: int = 0
8 | metal: int = 0
9 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_agents/python/lux/factory.py:
--------------------------------------------------------------------------------
1 | import math
2 | from sys import stderr
3 | import numpy as np
4 | from dataclasses import dataclass
5 | if __package__ == "":
6 | from lux.cargo import UnitCargo
7 | from lux.config import EnvConfig
8 | else:
9 | from .cargo import UnitCargo
10 | from .config import EnvConfig
11 | @dataclass
12 | class Factory:
13 | team_id: int
14 | unit_id: str
15 | strain_id: int
16 | power: int
17 | cargo: UnitCargo
18 | pos: np.ndarray
19 | # lichen tiles connected to this factory
20 | # lichen_tiles: np.ndarray
21 | env_cfg: EnvConfig
22 |
23 | def build_heavy_metal_cost(self, game_state):
24 | unit_cfg = self.env_cfg.ROBOTS["HEAVY"]
25 | return unit_cfg.METAL_COST
26 | def build_heavy_power_cost(self, game_state):
27 | unit_cfg = self.env_cfg.ROBOTS["HEAVY"]
28 | return unit_cfg.POWER_COST
29 | def can_build_heavy(self, game_state):
30 | return self.power >= self.build_heavy_power_cost(game_state) and self.cargo.metal >= self.build_heavy_metal_cost(game_state)
31 | def build_heavy(self):
32 | return 1
33 |
34 | def build_light_metal_cost(self, game_state):
35 | unit_cfg = self.env_cfg.ROBOTS["LIGHT"]
36 | return unit_cfg.METAL_COST
37 | def build_light_power_cost(self, game_state):
38 | unit_cfg = self.env_cfg.ROBOTS["LIGHT"]
39 | return unit_cfg.POWER_COST
40 | def can_build_light(self, game_state):
41 | return self.power >= self.build_light_power_cost(game_state) and self.cargo.metal >= self.build_light_metal_cost(game_state)
42 |
43 | def build_light(self):
44 | return 0
45 |
46 | def water_cost(self, game_state):
47 | """
48 | Water required to perform water action
49 | """
50 | owned_lichen_tiles = (game_state.board.lichen_strains == self.strain_id).sum()
51 | return np.ceil(owned_lichen_tiles / self.env_cfg.LICHEN_WATERING_COST_FACTOR)
52 | def can_water(self, game_state):
53 | return self.cargo.water >= self.water_cost(game_state)
54 | def water(self):
55 | return 2
56 |
57 | @property
58 | def pos_slice(self):
59 | return slice(self.pos[0] - 1, self.pos[0] + 2), slice(self.pos[1] - 1, self.pos[1] + 2)
60 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_agents/python/lux/team.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from enum import Enum
3 | if __package__ == "":
4 | from lux.config import EnvConfig
5 | else:
6 | from .config import EnvConfig
7 | TERM_COLORS = False
8 | try:
9 | from termcolor import colored
10 | TERM_COLORS=True
11 | except:
12 | pass
13 | @dataclass
14 | class FactionInfo:
15 | color: str = "none"
16 | alt_color: str = "red"
17 | faction_id: int = -1
18 |
19 | class FactionTypes(Enum):
20 | Null = FactionInfo(color="gray", faction_id=0)
21 | AlphaStrike = FactionInfo(color="yellow", faction_id=1)
22 | MotherMars = FactionInfo(color="green", faction_id=2)
23 | TheBuilders = FactionInfo(color="blue", faction_id=3)
24 | FirstMars = FactionInfo(color="red", faction_id=4)
25 |
26 | class Team:
27 | def __init__(self, team_id: int, agent: str, faction: FactionTypes = None, water=0, metal=0, factories_to_place=0, factory_strains=[], place_first=False, bid=0) -> None:
28 | self.faction = faction
29 | self.team_id = team_id
30 | # the key used to differentiate ownership of things in state
31 | self.agent = agent
32 |
33 | self.water = water
34 | self.metal = metal
35 | self.factories_to_place = factories_to_place
36 | self.factory_strains = factory_strains
37 | # whether this team gets to place factories down first or not. The bid winner has this set to True.
38 | # If tied, player_0's team has this True
39 | self.place_first = place_first
40 | def state_dict(self):
41 | return dict(
42 | team_id=self.team_id,
43 | faction=self.faction.name,
44 | # note for optimization, water,metal, factories_to_place doesn't change after the early game.
45 | water=self.init_water,
46 | metal=self.init_metal,
47 | factories_to_place=self.factories_to_place,
48 | factory_strains=self.factory_strains,
49 | place_first=self.place_first,
50 | )
51 | def __str__(self) -> str:
52 | out = f"[Player {self.team_id}]"
53 | if TERM_COLORS:
54 | return colored(out, self.faction.value.color)
55 | return out
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_agents/python/lux/unit.py:
--------------------------------------------------------------------------------
1 | import math
2 | import sys
3 | from typing import List
4 | import numpy as np
5 | from dataclasses import dataclass
6 | if __package__ == "":
7 | from lux.cargo import UnitCargo
8 | from lux.config import EnvConfig
9 | else:
10 | from .cargo import UnitCargo
11 | from .config import EnvConfig
12 |
13 | # a[1] = direction (0 = center, 1 = up, 2 = right, 3 = down, 4 = left)
14 | move_deltas = np.array([[0, 0], [0, -1], [1, 0], [0, 1], [-1, 0]])
15 |
16 | @dataclass
17 | class Unit:
18 | team_id: int
19 | unit_id: str
20 | unit_type: str # "LIGHT" or "HEAVY"
21 | pos: np.ndarray
22 | power: int
23 | cargo: UnitCargo
24 | env_cfg: EnvConfig
25 | unit_cfg: dict
26 | action_queue: List
27 |
28 | @property
29 | def agent_id(self):
30 | if self.team_id == 0: return "player_0"
31 | return "player_1"
32 |
33 | def action_queue_cost(self, game_state):
34 | cost = self.env_cfg.ROBOTS[self.unit_type].ACTION_QUEUE_POWER_COST
35 | return cost
36 |
37 | def move_cost(self, game_state, direction):
38 | board = game_state.board
39 | target_pos = self.pos + move_deltas[direction]
40 | if target_pos[0] < 0 or target_pos[1] < 0 or target_pos[1] >= len(board.rubble) or target_pos[0] >= len(board.rubble[0]):
41 | # print("Warning, tried to get move cost for going off the map", file=sys.stderr)
42 | return None
43 | factory_there = board.factory_occupancy_map[target_pos[0], target_pos[1]]
44 | if factory_there not in game_state.teams[self.agent_id].factory_strains and factory_there != -1:
45 | # print("Warning, tried to get move cost for going onto a opposition factory", file=sys.stderr)
46 | return None
47 | rubble_at_target = board.rubble[target_pos[0]][target_pos[1]]
48 |
49 | return math.floor(self.unit_cfg.MOVE_COST + self.unit_cfg.RUBBLE_MOVEMENT_COST * rubble_at_target)
50 | def move(self, direction, repeat=0, n=1):
51 | if isinstance(direction, int):
52 | direction = direction
53 | else:
54 | pass
55 | return np.array([0, direction, 0, 0, repeat, n])
56 |
57 | def transfer(self, transfer_direction, transfer_resource, transfer_amount, repeat=0, n=1):
58 | assert transfer_resource < 5 and transfer_resource >= 0
59 | assert transfer_direction < 5 and transfer_direction >= 0
60 | return np.array([1, transfer_direction, transfer_resource, transfer_amount, repeat, n])
61 |
62 | def pickup(self, pickup_resource, pickup_amount, repeat=0, n=1):
63 | assert pickup_resource < 5 and pickup_resource >= 0
64 | return np.array([2, 0, pickup_resource, pickup_amount, repeat, n])
65 |
66 | def dig_cost(self, game_state):
67 | return self.unit_cfg.DIG_COST
68 | def dig(self, repeat=0, n=1):
69 | return np.array([3, 0, 0, 0, repeat, n])
70 |
71 | def self_destruct_cost(self, game_state):
72 | return self.unit_cfg.SELF_DESTRUCT_COST
73 | def self_destruct(self, repeat=0, n=1):
74 | return np.array([4, 0, 0, 0, repeat, n])
75 |
76 | def recharge(self, x, repeat=0, n=1):
77 | return np.array([5, 0, 0, x, repeat, n])
78 |
79 | def __str__(self) -> str:
80 | out = f"[{self.team_id}] {self.unit_id} {self.unit_type} at {self.pos}"
81 | return out
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_agents/python/lux/utils.py:
--------------------------------------------------------------------------------
1 | def my_turn_to_place_factory(place_first: bool, step: int):
2 | if place_first:
3 | if step % 2 == 1:
4 | return True
5 | else:
6 | if step % 2 == 0:
7 | return True
8 | return False
9 |
10 | # direction (0 = center, 1 = up, 2 = right, 3 = down, 4 = left)
11 | def direction_to(src, target):
12 | ds = target - src
13 | dx = ds[0]
14 | dy = ds[1]
15 | if dx == 0 and dy == 0:
16 | return 0
17 | if abs(dx) > abs(dy):
18 | if dx > 0:
19 | return 2
20 | else:
21 | return 4
22 | else:
23 | if dy > 0:
24 | return 3
25 | else:
26 | return 1
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_agents/python/main.py:
--------------------------------------------------------------------------------
1 | import json
2 | from typing import Dict
3 | import sys
4 | from argparse import Namespace
5 |
6 | if __package__ == "":
7 | from agent import Agent
8 | from lux.config import EnvConfig
9 | from lux.kit import GameState, process_obs, to_json, from_json, process_action, obs_to_game_state
10 | else:
11 | from .agent import Agent
12 | from .lux.config import EnvConfig
13 | from .lux.kit import GameState, process_obs, to_json, from_json, process_action, obs_to_game_state
14 |
15 | ### DO NOT REMOVE THE FOLLOWING CODE ###
16 | agent_dict = dict() # store potentially multiple dictionaries as kaggle imports code directly
17 | agent_prev_obs = dict()
18 | def agent_fn(observation, configurations):
19 | """
20 | agent definition for kaggle submission.
21 | """
22 | global agent_dict
23 | step = observation.step
24 |
25 |
26 | player = observation.player
27 | remainingOverageTime = observation.remainingOverageTime
28 | if step == 0:
29 | env_cfg = EnvConfig.from_dict(configurations["env_cfg"])
30 | agent_dict[player] = Agent(player, env_cfg)
31 | agent_prev_obs[player] = dict()
32 | agent = agent_dict[player]
33 | agent = agent_dict[player]
34 | obs = process_obs(player, agent_prev_obs[player], step, json.loads(observation.obs))
35 | if step == 100:
36 | with open("obs.json", "w") as f:
37 | json.dump(to_json(obs), f)
38 | agent_prev_obs[player] = obs
39 | agent.step = step
40 | if obs["real_env_steps"] < 0:
41 | actions = agent.early_setup(step, obs, remainingOverageTime)
42 | else:
43 | actions = agent.act(step, obs, remainingOverageTime)
44 |
45 | return process_action(actions)
46 |
47 | if __name__ == "__main__":
48 |
49 | def read_input():
50 | """
51 | Reads input from stdin
52 | """
53 | try:
54 | return input()
55 | except EOFError as eof:
56 | raise SystemExit(eof)
57 | step = 0
58 | player_id = 0
59 | configurations = None
60 | i = 0
61 | while True:
62 | inputs = read_input()
63 | obs = json.loads(inputs)
64 |
65 | observation = Namespace(**dict(step=obs["step"], obs=json.dumps(obs["obs"]), remainingOverageTime=obs["remainingOverageTime"], player=obs["player"], info=obs["info"]))
66 | if i == 0:
67 | configurations = obs["info"]["env_cfg"]
68 | i += 1
69 | actions = agent_fn(observation, dict(env_cfg=configurations))
70 | # send actions to engine
71 | print(json.dumps(actions))
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s2/test_lux.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from kaggle_environments import make
3 | from .agents import random_agent
4 |
5 | def test_lux_completes():
6 | env = make("lux_ai_s2", debug=True)
7 | env.run([random_agent, random_agent])
8 | json = env.toJSON()
9 | assert json["name"] == "lux_ai_s2"
10 | assert json["statuses"] == ["DONE", "DONE"]
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/README.md:
--------------------------------------------------------------------------------
1 | # Lux AI Challenge Season 3
2 |
3 | Welcome to the Kaggle Environments wrapped around the Lux AI Challenge Season 3! For more information or if you have an issues or want to make contributes, check out the main repository at https://github.com/Lux-AI-Challenge/Lux-Design-S3
4 |
5 | ## Test scripts
6 |
7 | ```
8 | kaggle-environments run --environment lux_ai_s3 --agents path/to/bot/main.py path/to/bot/main.py --render '{"mode": "json"}' --out out.json --debug=True
9 | ```
10 |
11 | ```
12 | kaggle-environments run --environment lux_ai_s3 --agents ../LuxAI/Lux-Design-S3/kits/python/main.py ../LuxAI/Lux-Design-S3/kits/python/main.py --render '{"mode": "json"}' --out out.json --debug=True
13 | ```
14 |
18 |
19 | ## Visualizer
20 |
21 | Ensure that the script module is at the bottom of tag.
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/agents.py:
--------------------------------------------------------------------------------
1 | from .test_agents.python.main import agent_fn as random_agent
2 | all_agents = {
3 | "random_agent": random_agent,
4 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Lux Eye S3
9 |
10 |
11 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/lux_ai_s3.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lux_ai_s3",
3 | "title": "Lux AI Challenge Season 3",
4 | "description": "A Novel AI Programming Challenge about Lux",
5 | "version": "0.0.1",
6 | "agents": [2],
7 | "configuration": {
8 | "episodeSteps": 506,
9 | "seed": {
10 | "description": "Seed to use for episodes",
11 | "type": "integer"
12 | },
13 | "actTimeout": 3,
14 | "runTimeout": 1600,
15 | "env_cfg": {
16 | "description": "Environment configuration. Not to be filled out by user as it is randomly generated.",
17 | "type": "object"
18 | }
19 | },
20 | "reward": {
21 | "description": "Reward of the agent. Equal to number of games won.",
22 | "type": "integer",
23 | "default": 0
24 | },
25 | "observation": {
26 | "remainingOverageTime": 60,
27 | "reward": {
28 | "description": "Current reward of the agent. Equal to amount of lichen grown.",
29 | "type": "integer",
30 | "default": 0
31 | },
32 | "obs": {
33 | "description": "String containing the observations",
34 | "type": "string",
35 | "shared": false
36 | },
37 | "player": {
38 | "description": "Current player's index / team id",
39 | "type": "string",
40 | "defaults": "player_0"
41 | }
42 | },
43 | "action": {
44 | "description": "Actions",
45 | "type": "object"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/luxai_s3/__init__.py:
--------------------------------------------------------------------------------
1 | from .env import LuxAIS3Env
2 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/luxai_s3/globals.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | TERM_COLORS = True
4 | try:
5 | from termcolor import colored
6 |
7 | TERM_COLORS = (
8 | os.environ["LUX_COLORS"] == "False" if "LUX_COLORS" in os.environ else True
9 | )
10 | except:
11 | TERM_COLORS = False
12 | # print("termcolor not installed, skipping dependency")
13 | pass
14 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/luxai_s3/spaces.py:
--------------------------------------------------------------------------------
1 | import chex
2 | import jax
3 | import jax.numpy as jnp
4 | import numpy as np
5 | from gymnax.environments.spaces import Space
6 |
7 |
8 | class MultiDiscrete(Space):
9 | """Minimal jittable class for multi discrete gymnax spaces."""
10 |
11 | def __init__(self, low: np.ndarray, high: np.ndarray):
12 | self.low = low
13 | self.high = high
14 | self.dist = self.high - self.low
15 | assert low.shape == high.shape
16 | self.shape = low.shape
17 | self.dtype = jnp.int16
18 |
19 | def sample(self, rng: chex.PRNGKey) -> chex.Array:
20 | return (
21 | jax.random.uniform(rng, shape=self.shape, minval=0, maxval=1) * self.dist
22 | + self.low
23 | ).astype(self.dtype)
24 |
25 | def contains(self, x) -> jnp.ndarray:
26 | """Check whether specific object is within space."""
27 | # type_cond = isinstance(x, self.dtype)
28 | # shape_cond = (x.shape == self.shape)
29 | range_cond = jnp.logical_and(x >= 0, x < self.n)
30 | return range_cond
31 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/luxai_s3/utils.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 |
4 | def to_numpy(x):
5 | if isinstance(x, dict):
6 | return {k: to_numpy(v) for k, v in x.items()}
7 | elif isinstance(x, list):
8 | return np.array(x)
9 | elif isinstance(x, np.ndarray):
10 | return x
11 | else:
12 | return np.array(x)
13 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/kit.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | def to_json(obj):
3 | if isinstance(obj, np.ndarray):
4 | return obj.tolist()
5 | elif isinstance(obj, np.integer):
6 | return int(obj)
7 | elif isinstance(obj, np.floating):
8 | return float(obj)
9 | elif isinstance(obj, list) or isinstance(obj, tuple):
10 | return [to_json(s) for s in obj]
11 | elif isinstance(obj, dict):
12 | out = {}
13 | for k in obj:
14 | out[k] = to_json(obj[k])
15 | return out
16 | else:
17 | return obj
18 | def from_json(state):
19 | if isinstance(state, list):
20 | return np.array(state)
21 | elif isinstance(state, dict):
22 | out = {}
23 | for k in state:
24 | out[k] = from_json(state[k])
25 | return out
26 | else:
27 | return state
28 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/utils.py:
--------------------------------------------------------------------------------
1 | # direction (0 = center, 1 = up, 2 = right, 3 = down, 4 = left)
2 | def direction_to(src, target):
3 | ds = target - src
4 | dx = ds[0]
5 | dy = ds[1]
6 | if dx == 0 and dy == 0:
7 | return 0
8 | if abs(dx) > abs(dy):
9 | if dx > 0:
10 | return 2
11 | else:
12 | return 4
13 | else:
14 | if dy > 0:
15 | return 3
16 | else:
17 | return 1
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/test_agents/python/main.py:
--------------------------------------------------------------------------------
1 | import json
2 | import sys
3 | from argparse import Namespace
4 | if __package__ == "":
5 | from agent import Agent
6 | from lux.kit import from_json
7 | else:
8 | from .agent import Agent
9 | from .lux.kit import from_json
10 | ### DO NOT REMOVE THE FOLLOWING CODE ###
11 | agent_dict = dict() # store potentially multiple dictionaries as kaggle imports code directly
12 | agent_prev_obs = dict()
13 | def agent_fn(observation, configurations):
14 | """
15 | agent definition for kaggle submission.
16 | """
17 | global agent_dict
18 | obs = observation.obs
19 | if type(obs) == str:
20 | obs = json.loads(obs)
21 | step = observation.step
22 | player = observation.player
23 | remainingOverageTime = observation.remainingOverageTime
24 | if step == 0:
25 | agent_dict[player] = Agent(player, configurations["env_cfg"])
26 | agent = agent_dict[player]
27 | actions = agent.act(step, from_json(obs), remainingOverageTime)
28 | return dict(action=actions.tolist())
29 | if __name__ == "__main__":
30 |
31 | def read_input():
32 | """
33 | Reads input from stdin
34 | """
35 | try:
36 | return input()
37 | except EOFError as eof:
38 | raise SystemExit(eof)
39 | step = 0
40 | player_id = 0
41 | env_cfg = None
42 | i = 0
43 | while True:
44 | inputs = read_input()
45 | raw_input = json.loads(inputs)
46 | observation = Namespace(**dict(step=raw_input["step"], obs=raw_input["obs"], remainingOverageTime=raw_input["remainingOverageTime"], player=raw_input["player"], info=raw_input["info"]))
47 | if i == 0:
48 | env_cfg = raw_input["info"]["env_cfg"]
49 | player_id = raw_input["player"]
50 | i += 1
51 | actions = agent_fn(observation, dict(env_cfg=env_cfg))
52 | # send actions to engine
53 | print(json.dumps(actions))
--------------------------------------------------------------------------------
/kaggle_environments/envs/lux_ai_s3/test_lux.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from kaggle_environments import make
3 |
4 | def xtest_lux_completes():
5 | env = make("lux_ai_s3", debug=True)
6 | env.run(["random_agent", "random_agent"])
7 | json = env.toJSON()
8 | assert json["name"] == "lux_ai_s3"
9 | assert json["statuses"] == ["DONE", "DONE"]
10 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/mab/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/mab/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/mab/agents.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 |
4 | def random_agent(observation, configuration):
5 | return random.randrange(configuration.banditCount - 1)
6 |
7 |
8 | def round_robin_agent(observation, configuration):
9 | return observation.step % configuration.banditCount
10 |
11 |
12 | agents = {
13 | "random": random_agent,
14 | "round_robin": round_robin_agent
15 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/mab/mab.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mab",
3 | "title": "Adversarial Multi-armed Bandit",
4 | "description": "Adversarial Multi-armed Bandit",
5 | "version": "1.0.0",
6 | "agents": [2, 3, 4, 5, 6, 7, 8],
7 | "configuration": {
8 | "episodeSteps": 2000,
9 | "actTimeout": 0.25,
10 | "banditCount": {
11 | "description": "Number of bandits available to choose from. Max action is this number -1.",
12 | "type": "integer",
13 | "minimum": 2,
14 | "default": 100
15 | },
16 | "decayRate": {
17 | "description": "Rate that reward chance threshold increases per step that a bandit is chosen by an agent.",
18 | "type": "number",
19 | "minimum": 0,
20 | "default": 0.97
21 | },
22 | "sampleResolution": {
23 | "description": "Maximum value that can be returned by a bandit.",
24 | "type": "integer",
25 | "minimum": 1,
26 | "default": 100
27 | }
28 | },
29 | "reward": {
30 | "description": "The total reward each player has accumulated from the bandits across all steps.",
31 | "type": "number",
32 | "minimum": 0,
33 | "default": 0
34 | },
35 | "observation": {
36 | "remainingOverageTime": 60,
37 | "agentIndex": {
38 | "description": "The current agent's index within observation.lastActions.",
39 | "type": "integer",
40 | "defaults": [0, 1, 2, 3, 4, 5, 6, 7]
41 | },
42 | "reward": {
43 | "description": "Current reward of the agent.",
44 | "type": "number",
45 | "minimum": 0,
46 | "default": 0
47 | },
48 | "lastActions": {
49 | "description": "Bandits chosen by each agent on the last step. None on the first step.",
50 | "type": "array",
51 | "shared": true,
52 | "items": {
53 | "type": "number",
54 | "minimum": 0
55 | },
56 | "default": []
57 | },
58 | "thresholds": {
59 | "description": "Probability values for each machine payout on this step. Hidden from agents at runtime.",
60 | "type": "array",
61 | "shared": true,
62 | "hidden": true,
63 | "items": {
64 | "type": "number",
65 | "minimum": 0
66 | }
67 | }
68 | },
69 | "action": {
70 | "description": "Choice of bandit for the step (min bandit = 0, max bandit = configuration.banditCount - 1)",
71 | "type": "integer",
72 | "minimum": 0
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/open_spiel/test_open_spiel.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from kaggle_environments import make
3 | import open_spiel as open_spiel_env
4 |
5 |
6 | def test_envs_load():
7 | envs = open_spiel_env._register_open_spiel_envs()
8 | print(len(envs))
9 |
10 |
11 | def test_tic_tac_toe_playthrough():
12 | envs = open_spiel_env._register_open_spiel_envs(["tic_tac_toe"])
13 | print(envs)
14 | env = make("open_spiel_tic_tac_toe", debug=True)
15 | env.run(["random", "random"])
16 | json = env.toJSON()
17 | assert json["name"] == "open_spiel_tic_tac_toe"
18 | assert all([status == "DONE" for status in json["statuses"]])
--------------------------------------------------------------------------------
/kaggle_environments/envs/rps/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kaggle/kaggle-environments/51d191900612b7cf39fdaff206971d47db0321ae/kaggle_environments/envs/rps/__init__.py
--------------------------------------------------------------------------------
/kaggle_environments/envs/rps/agents.py:
--------------------------------------------------------------------------------
1 | import random
2 | from .utils import get_score
3 |
4 |
5 | def rock(observation, configuration):
6 | return 0
7 |
8 |
9 | def paper(observation, configuration):
10 | return 1
11 |
12 |
13 | def scissors(observation, configuration):
14 | return 2
15 |
16 |
17 | def copy_opponent(observation, configuration):
18 | if observation.step > 0:
19 | return observation.lastOpponentAction
20 | else:
21 | return random.randrange(0, configuration.signs)
22 |
23 |
24 | last_react_action = None
25 |
26 |
27 | def reactionary(observation, configuration):
28 | global last_react_action
29 | if observation.step == 0:
30 | last_react_action = random.randrange(0, configuration.signs)
31 | elif get_score(last_react_action, observation.lastOpponentAction) <= 1:
32 | last_react_action = (observation.lastOpponentAction + 1) % configuration.signs
33 |
34 | return last_react_action
35 |
36 |
37 | last_counter_action = None
38 |
39 |
40 | def counter_reactionary(observation, configuration):
41 | global last_counter_action
42 | if observation.step == 0:
43 | last_counter_action = random.randrange(0, configuration.signs)
44 | elif get_score(last_counter_action, observation.lastOpponentAction) == 1:
45 | last_counter_action = (last_counter_action + 2) % configuration.signs
46 | else:
47 | last_counter_action = (observation.lastOpponentAction + 1) % configuration.signs
48 |
49 | return last_counter_action
50 |
51 |
52 | action_histogram = {}
53 |
54 |
55 | def statistical(observation, configuration):
56 | global action_histogram
57 | if observation.step == 0:
58 | action_histogram = {}
59 | return
60 | action = observation.lastOpponentAction
61 | if action not in action_histogram:
62 | action_histogram[action] = 0
63 | action_histogram[action] += 1
64 | mode_action = None
65 | mode_action_count = None
66 | for k, v in action_histogram.items():
67 | if mode_action_count is None or v > mode_action_count:
68 | mode_action = k
69 | mode_action_count = v
70 | continue
71 |
72 | return (mode_action + 1) % configuration.signs
73 |
74 |
75 | agents = {
76 | "rock": rock,
77 | "paper": paper,
78 | "scissors": scissors,
79 | "copy_opponent": copy_opponent,
80 | "reactionary": reactionary,
81 | "counter_reactionary": counter_reactionary,
82 | "statistical": statistical
83 | }
--------------------------------------------------------------------------------
/kaggle_environments/envs/rps/helpers.py:
--------------------------------------------------------------------------------
1 | import json
2 | from os import path
3 | from kaggle_environments.helpers import *
4 |
5 |
6 | class Observation(Observation):
7 | """
8 | Observation primarily used as a helper to construct the State from the raw observation.
9 | This provides bindings for the observation type described at https://github.com/Kaggle/kaggle-environments/blob/master/kaggle_environments/envs/rps/rps.json
10 | """
11 | @property
12 | def last_opponent_action(self) -> int:
13 | """Move the opponent took on the last turn."""
14 | return self["halite"]
15 |
16 |
17 | class Configuration(Configuration):
18 | """
19 | Configuration provides access to tunable parameters in the environment.
20 | This provides bindings for the configuration type described at https://github.com/Kaggle/kaggle-environments/blob/master/kaggle_environments/envs/rps/rps.json
21 | """
22 | @property
23 | def signs(self) -> int:
24 | """Number of choices each step (3 for the normal rock, paper, scissors)"""
25 | return self["signs"]
26 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/rps/rps.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rps",
3 | "title": "Rock Paper Scissors",
4 | "description": "Repeated Rock Paper Scissors",
5 | "version": "1.0.0",
6 | "agents": [2],
7 | "configuration": {
8 | "signs": {
9 | "description": "Number of choices each step (Rock = 0, Paper = 1, Scissors = 2, etc).",
10 | "type": "integer",
11 | "minimum": 3,
12 | "maximum": 5,
13 | "default": 3
14 | },
15 | "episodeSteps": {
16 | "description": "Maximum number of steps the environment can run. Total is this number -1.",
17 | "type": "integer",
18 | "minimum": 2,
19 | "default": 1000
20 | },
21 | "tieRewardThreshold": {
22 | "description": "Minimum reward needed to achieve a win rather than a tie.",
23 | "type": "integer",
24 | "minimum": 1,
25 | "maximum": 1000,
26 | "default": 20
27 | },
28 | "agentTimeout": {
29 | "description": "Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.",
30 | "type": "number",
31 | "minimum": 0,
32 | "default": 60
33 | },
34 | "actTimeout": 1
35 | },
36 | "reward": {
37 | "description": "-1 = Lost, 0 = Draw, 1 = Won",
38 | "enum": [-1, 0, 1],
39 | "default": 0
40 | },
41 | "observation": {
42 | "lastOpponentAction": {
43 | "description": "Symbol returned by opponent last step. None on the first step.",
44 | "type": "integer",
45 | "minimum": 0,
46 | "maximum": 4
47 | },
48 | "remainingOverageTime": 60,
49 | "reward": {
50 | "description": "Current reward of the agent.",
51 | "type": "integer",
52 | "minimum": -999,
53 | "maximum": 999,
54 | "default": 0
55 | }
56 | },
57 | "action": {
58 | "description": "Choice of sign for the step (Rock = 0, Paper = 1, Scissors = 2, etc)",
59 | "type": "integer",
60 | "minimum": 0,
61 | "maximum": 4
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/rps/rps.py:
--------------------------------------------------------------------------------
1 | import json
2 | from os import path
3 | from .agents import agents as all_agents
4 | from .utils import get_score
5 |
6 |
7 | def interpreter(state, env):
8 | player1 = state[0]
9 | player2 = state[1]
10 |
11 | # Specification can fully handle the reset.
12 | if env.done:
13 | return state
14 |
15 | def is_valid_action(player, sign_count):
16 | return (
17 | player.action is not None and
18 | isinstance(player.action, int) and
19 | 0 <= player.action < sign_count
20 | )
21 |
22 | # Check for validity of actions
23 | is_player1_valid = is_valid_action(player1, env.configuration.signs)
24 | is_player2_valid = is_valid_action(player2, env.configuration.signs)
25 | if not is_player2_valid:
26 | player2.status = "INVALID"
27 | player2.reward = 0
28 |
29 | if is_player1_valid:
30 | player1.status = "DONE"
31 | player1.reward = 1
32 | return state
33 |
34 | if not is_player1_valid:
35 | player1.status = "INVALID"
36 | player1.reward = 0
37 |
38 | if is_player2_valid:
39 | player2.status = "DONE"
40 | player2.reward = 1
41 | return state
42 | else:
43 | return state
44 |
45 | score = get_score(player1.action, player2.action)
46 | player1.observation.lastOpponentAction = player2.action
47 | player1.reward += score
48 | player2.observation.lastOpponentAction = player1.action
49 | player2.reward -= score
50 | player1.observation.reward = int(player1.reward)
51 | player2.observation.reward = int(player2.reward)
52 | remaining_steps = env.configuration.episodeSteps - player1.observation.step - 1
53 |
54 | # This is the last step
55 | if remaining_steps <= 1:
56 | player1.status = "DONE"
57 | player2.status = "DONE"
58 | # Player performance too similar, consider the match a tie.
59 | if abs(player1.reward) < env.configuration.tieRewardThreshold:
60 | player1.reward = 0
61 | player2.reward = 0
62 | return state
63 |
64 |
65 | def renderer(state, env):
66 | sign_names = ["Rock", "Paper", "Scissors", "Spock", "Lizard"]
67 | rounds_played = len(env.steps)
68 | board = ""
69 |
70 | # This line prints results each round, good for debugging
71 | for i in range(1, rounds_played):
72 | step = env.steps[i]
73 | right_move = step[0].observation.lastOpponentAction
74 | left_move = step[1].observation.lastOpponentAction
75 | board += f"Round {i}: {sign_names[left_move]} vs {sign_names[right_move]}, Score: {step[0].reward} to {step[1].reward}\n"
76 |
77 | board += f"Game ended on round {rounds_played - 1}, final score: {state[0].reward} to {state[0].reward}\n"
78 | return board
79 |
80 |
81 | dir_path = path.dirname(__file__)
82 | json_path = path.abspath(path.join(dir_path, "rps.json"))
83 | with open(json_path) as json_file:
84 | specification = json.load(json_file)
85 |
86 |
87 | def html_renderer():
88 | js_path = path.abspath(path.join(dir_path, "rps.js"))
89 | with open(js_path, encoding="utf-8") as js_file:
90 | return js_file.read()
91 |
92 |
93 | agents = all_agents
94 |
--------------------------------------------------------------------------------
/kaggle_environments/envs/rps/utils.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 |
4 | def get_score(left_move, right_move):
5 | # This method exists in this file so it can be consumed from rps.py and agents.py without a circular dependency
6 | delta = (
7 | right_move - left_move
8 | if (left_move + right_move) % 2 == 0
9 | else left_move - right_move
10 | )
11 | return 0 if delta == 0 else math.copysign(1, delta)
--------------------------------------------------------------------------------
/kaggle_environments/envs/tictactoe/tictactoe.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tictactoe",
3 | "title": "Tic Tac Toe",
4 | "description": "Classic Tic Tac Toe",
5 | "version": "1.0.0",
6 | "agents": [2],
7 | "configuration": {
8 | "episodeSteps": 10,
9 | "actTimeout": 1,
10 | "agentTimeout": {
11 | "description": "Obsolete field kept for backwards compatibility, please use observation.remainingOverageTime.",
12 | "type": "number",
13 | "minimum": 0,
14 | "default": 2
15 | }
16 | },
17 | "reward": {
18 | "description": "-1 = Lost, 0 = Draw/Ongoing, 1 = Won",
19 | "enum": [-1, 0, 1],
20 | "default": 0
21 | },
22 | "observation": {
23 | "board": {
24 | "description": "Serialized 3x3 grid. 0 = Empty, 1 = X, 2 = O",
25 | "type": "array",
26 | "shared": true,
27 | "default": [0, 0, 0, 0, 0, 0, 0, 0, 0],
28 | "minItems": 9,
29 | "maxItems": 9
30 | },
31 | "mark": {
32 | "description": "Mark for the agent to use",
33 | "defaults": [1, 2],
34 | "enum": [1, 2]
35 | },
36 | "remainingOverageTime": 2
37 | },
38 | "action": {
39 | "description": "Position to place a mark on the board.",
40 | "type": "integer",
41 | "minimum": 0,
42 | "maximum": 8
43 | },
44 | "status": {
45 | "defaults": ["ACTIVE", "INACTIVE"]
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/kaggle_environments/status_codes.json:
--------------------------------------------------------------------------------
1 | {
2 | "OK": {
3 | "code": 0,
4 | "status": 200
5 | },
6 | "CANCELLED": {
7 | "code": 1,
8 | "status": 499
9 | },
10 | "UNKNOWN": {
11 | "code": 2,
12 | "status": 500
13 | },
14 | "INVALID_ARGUMENT": {
15 | "code": 3,
16 | "status": 400
17 | },
18 | "DEADLINE_EXCEEDED": {
19 | "code": 4,
20 | "status": 504
21 | },
22 | "NOT_FOUND": {
23 | "code": 5,
24 | "status": 404
25 | },
26 | "ALREADY_EXISTS": {
27 | "code": 6,
28 | "status": 409
29 | },
30 | "PERMISSION_DENIED": {
31 | "code": 7,
32 | "status": 403
33 | },
34 | "UNAUTHENTICATED": {
35 | "code": 16,
36 | "status": 401
37 | },
38 | "RESOURCE_EXHAUSTED": {
39 | "code": 8,
40 | "status": 429
41 | },
42 | "FAILED_PRECONDITION": {
43 | "code": 9,
44 | "status": 400
45 | },
46 | "ABORTED": {
47 | "code": 10,
48 | "status": 409
49 | },
50 | "OUT_OF_RANGE": {
51 | "code": 11,
52 | "status": 400
53 | },
54 | "UNIMPLEMENTED": {
55 | "code": 12,
56 | "status": 501
57 | },
58 | "INTERNAL": {
59 | "code": 13,
60 | "status": 500
61 | },
62 | "UNAVAILABLE": {
63 | "code": 14,
64 | "status": 503
65 | },
66 | "DATA_LOSS": {
67 | "code": 15,
68 | "status": 500
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/package.sh:
--------------------------------------------------------------------------------
1 | rm -rf ./dist
2 | rm -rf ./build
3 | rm -rf ./kaggle_environments.egg-info
4 | # Delete pycache, pyc, and pyo files
5 | find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
6 | python3 setup.py sdist
7 | python3 setup.py bdist_wheel --universal
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | twine upload dist/*
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | gym
3 | ipython
4 | jsonschema
5 | numpy
6 | requests
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #
3 | # Copyright 2020 Kaggle Inc
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | # coding=utf-8
17 | from setuptools import setup, find_packages
18 | import codecs
19 | import os.path
20 |
21 | def read(rel_path):
22 | here = os.path.abspath(os.path.dirname(__file__))
23 | with codecs.open(os.path.join(here, rel_path), 'r') as fp:
24 | return fp.read()
25 |
26 | def get_version(rel_path):
27 | for line in read(rel_path).splitlines():
28 | if line.startswith('__version__'):
29 | delim = '"' if '"' in line else "'"
30 | return line.split(delim)[1]
31 | else:
32 | raise RuntimeError("Unable to find version string.")
33 |
34 | with open("README.md", "r") as f:
35 | long_description = f.read()
36 |
37 | setup(
38 | name='kaggle-environments',
39 | version=get_version("kaggle_environments/__init__.py"),
40 | description='Kaggle Environments',
41 | long_description=long_description,
42 | long_description_content_type='text/markdown',
43 | author='Kaggle',
44 | author_email='support@kaggle.com',
45 | url='https://github.com/Kaggle/kaggle-environments',
46 | keywords=['Kaggle'],
47 | entry_points={'console_scripts': [
48 | 'kaggle-environments = kaggle_environments.main:main']},
49 | install_requires=[
50 | "jsonschema >= 3.0.1",
51 | "Flask >= 1.1.2",
52 | "numpy >= 1.19.5",
53 | "requests >= 2.25.1",
54 | "pettingzoo == 1.24.0",
55 | "gymnasium == 0.29.0",
56 | "stable-baselines3 == 2.1.0",
57 | "transformers >= 4.33.1",
58 | "scipy >= 1.11.2",
59 | "shimmy >= 1.2.1",
60 | "Chessnut >= 0.4.1",
61 | "open_spiel >= 1.5.0",
62 | ],
63 | packages=find_packages(),
64 | include_package_data=True,
65 | python_requires='>=3.8',
66 | license='Apache 2.0')
67 |
--------------------------------------------------------------------------------