royalegym 0.1.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- royalegym-0.1.12/LICENSE +21 -0
- royalegym-0.1.12/PKG-INFO +34 -0
- royalegym-0.1.12/README.md +40 -0
- royalegym-0.1.12/pyproject.toml +100 -0
- royalegym-0.1.12/royalegym/__init__.py +238 -0
- royalegym-0.1.12/royalegym/action.py +1109 -0
- royalegym-0.1.12/royalegym/done_condition.py +154 -0
- royalegym-0.1.12/royalegym/env.py +1288 -0
- royalegym-0.1.12/royalegym/evaluate.py +346 -0
- royalegym-0.1.12/royalegym/landing.py +439 -0
- royalegym-0.1.12/royalegym/mock_engine.py +1612 -0
- royalegym-0.1.12/royalegym/obs.py +2834 -0
- royalegym-0.1.12/royalegym/opponents.py +253 -0
- royalegym-0.1.12/royalegym/protocol.py +1806 -0
- royalegym-0.1.12/royalegym/py.typed +0 -0
- royalegym-0.1.12/royalegym/render.py +859 -0
- royalegym-0.1.12/royalegym/replay.py +531 -0
- royalegym-0.1.12/royalegym/reward.py +451 -0
- royalegym-0.1.12/royalegym/rust_engine.py +1620 -0
- royalegym-0.1.12/royalegym/selfplay.py +264 -0
- royalegym-0.1.12/royalegym/state_mutator.py +496 -0
- royalegym-0.1.12/royalegym/viser.py +461 -0
- royalegym-0.1.12/royalegym.egg-info/PKG-INFO +34 -0
- royalegym-0.1.12/royalegym.egg-info/SOURCES.txt +110 -0
- royalegym-0.1.12/royalegym.egg-info/dependency_links.txt +1 -0
- royalegym-0.1.12/royalegym.egg-info/requires.txt +34 -0
- royalegym-0.1.12/royalegym.egg-info/top_level.txt +1 -0
- royalegym-0.1.12/setup.cfg +4 -0
- royalegym-0.1.12/tests/test_ability_buttons.py +481 -0
- royalegym-0.1.12/tests/test_action_ground_truth.py +223 -0
- royalegym-0.1.12/tests/test_addressable_episodes.py +273 -0
- royalegym-0.1.12/tests/test_architecture_doc.py +147 -0
- royalegym-0.1.12/tests/test_building_footprint.py +1059 -0
- royalegym-0.1.12/tests/test_building_tap_arms.py +400 -0
- royalegym-0.1.12/tests/test_calibration_overrides.py +204 -0
- royalegym-0.1.12/tests/test_card_identity.py +288 -0
- royalegym-0.1.12/tests/test_card_status.py +308 -0
- royalegym-0.1.12/tests/test_card_table_stamp.py +535 -0
- royalegym-0.1.12/tests/test_ci_workflow.py +270 -0
- royalegym-0.1.12/tests/test_command_delay.py +224 -0
- royalegym-0.1.12/tests/test_cross_process_determinism.py +179 -0
- royalegym-0.1.12/tests/test_deck_curriculum.py +340 -0
- royalegym-0.1.12/tests/test_deploy_lockout.py +158 -0
- royalegym-0.1.12/tests/test_entitylist_ground_truth.py +318 -0
- royalegym-0.1.12/tests/test_env_action_mask.py +624 -0
- royalegym-0.1.12/tests/test_env_api.py +552 -0
- royalegym-0.1.12/tests/test_env_mask_property.py +437 -0
- royalegym-0.1.12/tests/test_env_mock_engine.py +650 -0
- royalegym-0.1.12/tests/test_env_obs.py +1776 -0
- royalegym-0.1.12/tests/test_env_protocol.py +442 -0
- royalegym-0.1.12/tests/test_env_render.py +560 -0
- royalegym-0.1.12/tests/test_evaluate.py +248 -0
- royalegym-0.1.12/tests/test_evo_cycle.py +58 -0
- royalegym-0.1.12/tests/test_evo_obs.py +272 -0
- royalegym-0.1.12/tests/test_examples.py +107 -0
- royalegym-0.1.12/tests/test_fair_fields.py +419 -0
- royalegym-0.1.12/tests/test_final_info_ground_truth.py +297 -0
- royalegym-0.1.12/tests/test_fresh_user_try_its.py +71 -0
- royalegym-0.1.12/tests/test_gym_ids.py +235 -0
- royalegym-0.1.12/tests/test_hero_obs.py +258 -0
- royalegym-0.1.12/tests/test_install_pointers.py +383 -0
- royalegym-0.1.12/tests/test_invisible_characters.py +184 -0
- royalegym-0.1.12/tests/test_landing.py +290 -0
- royalegym-0.1.12/tests/test_levels.py +140 -0
- royalegym-0.1.12/tests/test_mirror_memory.py +207 -0
- royalegym-0.1.12/tests/test_obs_builder_equality.py +324 -0
- royalegym-0.1.12/tests/test_obs_ground_truth.py +288 -0
- royalegym-0.1.12/tests/test_obs_responds_to_the_state.py +574 -0
- royalegym-0.1.12/tests/test_opponents.py +310 -0
- royalegym-0.1.12/tests/test_overtime_play_stops.py +128 -0
- royalegym-0.1.12/tests/test_overtime_tiebreak.py +304 -0
- royalegym-0.1.12/tests/test_packaging.py +300 -0
- royalegym-0.1.12/tests/test_parity_hardening.py +493 -0
- royalegym-0.1.12/tests/test_placement_invariant.py +169 -0
- royalegym-0.1.12/tests/test_player_deck.py +72 -0
- royalegym-0.1.12/tests/test_press_memory.py +227 -0
- royalegym-0.1.12/tests/test_press_runs.py +143 -0
- royalegym-0.1.12/tests/test_princess_centres.py +147 -0
- royalegym-0.1.12/tests/test_quickstart.py +102 -0
- royalegym-0.1.12/tests/test_random_deck_champions.py +97 -0
- royalegym-0.1.12/tests/test_readme_program.py +401 -0
- royalegym-0.1.12/tests/test_readme_try_it.py +64 -0
- royalegym-0.1.12/tests/test_refill_delay.py +70 -0
- royalegym-0.1.12/tests/test_reveal_mapping.py +43 -0
- royalegym-0.1.12/tests/test_reward_ground_truth.py +743 -0
- royalegym-0.1.12/tests/test_rewards.py +705 -0
- royalegym-0.1.12/tests/test_rust_engine.py +2297 -0
- royalegym-0.1.12/tests/test_rust_spells.py +640 -0
- royalegym-0.1.12/tests/test_saving_recorder.py +224 -0
- royalegym-0.1.12/tests/test_selfplay_pool.py +271 -0
- royalegym-0.1.12/tests/test_shared_oracle.py +156 -0
- royalegym-0.1.12/tests/test_shell_fences.py +149 -0
- royalegym-0.1.12/tests/test_site_examples.py +565 -0
- royalegym-0.1.12/tests/test_spatial_exact_storage.py +90 -0
- royalegym-0.1.12/tests/test_spawn_arrangement.py +272 -0
- royalegym-0.1.12/tests/test_spell_aim_after.py +206 -0
- royalegym-0.1.12/tests/test_spell_id_obs.py +183 -0
- royalegym-0.1.12/tests/test_stage_release.py +92 -0
- royalegym-0.1.12/tests/test_state_mutator_names.py +38 -0
- royalegym-0.1.12/tests/test_step_result_arity.py +171 -0
- royalegym-0.1.12/tests/test_trace_forms.py +96 -0
- royalegym-0.1.12/tests/test_trace_step_records.py +443 -0
- royalegym-0.1.12/tests/test_train_harness.py +776 -0
- royalegym-0.1.12/tests/test_troop_tower_taps.py +656 -0
- royalegym-0.1.12/tests/test_tunnel_and_mirror.py +306 -0
- royalegym-0.1.12/tests/test_unit_actions_obs.py +219 -0
- royalegym-0.1.12/tests/test_unit_hitpoints.py +48 -0
- royalegym-0.1.12/tests/test_unit_status_and_projectiles.py +468 -0
- royalegym-0.1.12/tests/test_unit_status_obs.py +355 -0
- royalegym-0.1.12/tests/test_vector_writer.py +313 -0
- royalegym-0.1.12/tests/test_viewer_frame_rate.py +187 -0
- royalegym-0.1.12/tests/test_viser.py +201 -0
royalegym-0.1.12/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RoyaleGym contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: royalegym
|
|
3
|
+
Version: 0.1.12
|
|
4
|
+
Summary: RoyaleGym: reinforcement-learning environments for Clash Royale, over the RoyaleSim battle engine
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: numpy>=2.0
|
|
9
|
+
Requires-Dist: gymnasium<2.0,>=1.3
|
|
10
|
+
Requires-Dist: pettingzoo<2.0,>=1.27
|
|
11
|
+
Requires-Dist: msgspec>=0.19
|
|
12
|
+
Provides-Extra: sim
|
|
13
|
+
Requires-Dist: royalesim>=0.1.10; extra == "sim"
|
|
14
|
+
Provides-Extra: learn
|
|
15
|
+
Requires-Dist: royalelearn[torch]>=0.5.4; extra == "learn"
|
|
16
|
+
Provides-Extra: viser
|
|
17
|
+
Requires-Dist: royaleviser>=0.1.1; extra == "viser"
|
|
18
|
+
Provides-Extra: imitate
|
|
19
|
+
Requires-Dist: royaleimitate[replays]>=0.2.6; extra == "imitate"
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Requires-Dist: royalesim>=0.1.10; extra == "all"
|
|
22
|
+
Requires-Dist: royalelearn[torch]>=0.5.4; extra == "all"
|
|
23
|
+
Requires-Dist: royaleviser[media]>=0.1.1; extra == "all"
|
|
24
|
+
Requires-Dist: royaleimitate[replays]>=0.2.6; extra == "all"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
27
|
+
Requires-Dist: hypothesis>=6.100; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
29
|
+
Provides-Extra: train
|
|
30
|
+
Requires-Dist: sb3-contrib>=2.3; extra == "train"
|
|
31
|
+
Provides-Extra: docs
|
|
32
|
+
Requires-Dist: mkdocs-material<10,>=9.7; extra == "docs"
|
|
33
|
+
Requires-Dist: mkdocstrings[python]<2,>=1.0; extra == "docs"
|
|
34
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<p align="center"><img src="docs/site/pages/assets/royalegym-mark.png" width="128" alt="The RoyaleGym logo: a blue crown shield with a white dumbbell on it, outlined in gold"></p>
|
|
2
|
+
|
|
3
|
+
<h1 align="center">RoyaleGym</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center"><a href="https://github.com/RoyaleGym/RoyaleGym/actions/workflows/suite.yml"><img alt="CI" src="https://github.com/RoyaleGym/RoyaleGym/actions/workflows/suite.yml/badge.svg"></a> <img alt="License" src="https://img.shields.io/github/license/RoyaleGym/RoyaleGym?style=flat-square&color=555"> <img alt="Python" src="https://img.shields.io/badge/python-3.12%20%7C%203.13%20%7C%203.14-3776AB?style=flat-square&logo=python&logoColor=white"> <a href="https://royalegym.github.io/RoyaleGym/"><img alt="Docs" src="https://img.shields.io/badge/docs-royalegym.github.io-8957e5?style=flat-square&logo=readthedocs&logoColor=white"></a> <a href="https://discord.gg/4D2BS5JBHP"><img alt="Discord" src="https://img.shields.io/discord/1551699576304705647?style=flat-square&logo=discord&logoColor=white&label=discord&color=5865F2"></a> <img alt="Last commit" src="https://img.shields.io/github/last-commit/RoyaleGym/RoyaleGym?style=flat-square&color=555"></p>
|
|
6
|
+
|
|
7
|
+
<p align="center"><img alt="APIs: Gymnasium and PettingZoo" src="https://img.shields.io/badge/APIs-Gymnasium%20%2B%20PettingZoo-0b7285?style=flat-square"> <img alt="Engine: Rust, deterministic" src="https://img.shields.io/badge/engine-Rust%2C%20deterministic-DEA584?style=flat-square&logo=rust&logoColor=white"> <img alt="Tick: 50 ms, 20 per second" src="https://img.shields.io/badge/tick-50%20ms%2C%2020%20per%20second-555?style=flat-square"> <img alt="Action space: 2305 moves" src="https://img.shields.io/badge/action%20space-2305%20moves-555?style=flat-square"></p>
|
|
8
|
+
|
|
9
|
+
**Make a Clash Royale bot in Python.** You write what your bot should want; this gives it the
|
|
10
|
+
battles, what it sees, the moves it can make, and a trainer.
|
|
11
|
+
|
|
12
|
+
<p align="center"><img src="docs/site/pages/media/whole-battle.gif" width="100%" alt="A whole battle between two random players, shown in the viewer"></p>
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
pip install "royalegym[all]" --find-links https://github.com/RoyaleGym/RoyaleGym/releases/expanded_assets/v0.1.11
|
|
17
|
+
|
|
18
|
+
Python 3.12, 3.13 or 3.14. No Rust, no game files. On Windows with an NVIDIA card, install PyTorch first
|
|
19
|
+
([Install](https://royalegym.github.io/RoyaleGym/install/), step 4).
|
|
20
|
+
|
|
21
|
+
## Try it
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from royalegym import make_env, play_battle
|
|
25
|
+
|
|
26
|
+
battle = play_battle(make_env(), blue="random", red="random", save_to="first_battle.msgpack")
|
|
27
|
+
print("winner", battle.winner, "crowns", battle.crowns)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Save it as `first_battle.py` and run `python first_battle.py` (a few seconds). `winner` is 0 for
|
|
31
|
+
Blue, 1 for Red and 2 for a draw. Then watch it: `royaleviser first_battle.msgpack`. To train a bot,
|
|
32
|
+
follow the [Quick Start](https://royalegym.github.io/RoyaleGym/quickstart/): it gives you `quickstart.py`.
|
|
33
|
+
|
|
34
|
+
## Next
|
|
35
|
+
|
|
36
|
+
- Quick Start, guides and FAQ: [the docs](https://royalegym.github.io/RoyaleGym/)
|
|
37
|
+
- How it works inside (Advanced): [architecture](https://royalegym.github.io/RoyaleGym/repos/royalegym/architecture/)
|
|
38
|
+
- Questions: [Discord](https://discord.gg/4D2BS5JBHP)
|
|
39
|
+
|
|
40
|
+
MIT licensed. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "royalegym"
|
|
7
|
+
version = "0.1.12"
|
|
8
|
+
description = "RoyaleGym: reinforcement-learning environments for Clash Royale, over the RoyaleSim battle engine"
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
dependencies = [
|
|
12
|
+
"numpy>=2.0",
|
|
13
|
+
"gymnasium>=1.3,<2.0",
|
|
14
|
+
"pettingzoo>=1.27,<2.0",
|
|
15
|
+
"msgspec>=0.19",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
# One install line for every piece: pip install "royalegym[all]".
|
|
20
|
+
# The engine (a prebuilt wheel; it carries its own data). The package imports without it
|
|
21
|
+
# (MockEngine is the pure-Python reference), and RustEngine() and make_env() say how to
|
|
22
|
+
# install it.
|
|
23
|
+
sim = ["royalesim>=0.1.10"]
|
|
24
|
+
# The learner, with PyTorch, which trains on a CPU.
|
|
25
|
+
learn = ["royalelearn[torch]>=0.5.4"]
|
|
26
|
+
# The viewer: watch a battle live or from a saved file.
|
|
27
|
+
viser = ["royaleviser>=0.1.1"]
|
|
28
|
+
# Imitation from replays.
|
|
29
|
+
imitate = ["royaleimitate[replays]>=0.2.6"]
|
|
30
|
+
# Every piece names a minimum, so `pip install --upgrade "royalegym[all]"` moves each one
|
|
31
|
+
# (pip upgrades a dependency only when a requirement forces it).
|
|
32
|
+
all = [
|
|
33
|
+
"royalesim>=0.1.10",
|
|
34
|
+
"royalelearn[torch]>=0.5.4",
|
|
35
|
+
"royaleviser[media]>=0.1.1",
|
|
36
|
+
"royaleimitate[replays]>=0.2.6",
|
|
37
|
+
]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=8.0",
|
|
40
|
+
"hypothesis>=6.100",
|
|
41
|
+
"ruff>=0.16",
|
|
42
|
+
]
|
|
43
|
+
train = [
|
|
44
|
+
"sb3-contrib>=2.3",
|
|
45
|
+
]
|
|
46
|
+
# The documentation site, built from docs/site with `mkdocs serve` or `mkdocs build`.
|
|
47
|
+
docs = [
|
|
48
|
+
"mkdocs-material>=9.7,<10",
|
|
49
|
+
"mkdocstrings[python]>=1.0,<2",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[tool.setuptools]
|
|
53
|
+
packages = ["royalegym"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.package-data]
|
|
56
|
+
# PEP 561: type checkers read an installed package's hints only when it ships this marker.
|
|
57
|
+
royalegym = ["py.typed"]
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
python_files = ["test_*.py"]
|
|
62
|
+
pythonpath = ["."]
|
|
63
|
+
addopts = "-ra --strict-markers"
|
|
64
|
+
markers = ["slow: long-running rollouts"]
|
|
65
|
+
filterwarnings = [
|
|
66
|
+
# pettingzoo's api test warns through gymnasium's logger on purpose for some checks
|
|
67
|
+
"ignore::DeprecationWarning:pettingzoo.*",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[tool.ruff]
|
|
71
|
+
line-length = 100
|
|
72
|
+
target-version = "py312"
|
|
73
|
+
src = ["royalegym", "tests", "examples"]
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF", "NPY", "PT"]
|
|
77
|
+
ignore = [
|
|
78
|
+
"RUF001", "RUF002", "RUF003", # ambiguous unicode in comments/docstrings
|
|
79
|
+
"SIM108", # ternaries are not always clearer
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint.per-file-ignores]
|
|
83
|
+
# An example unpacks the whole five-tuple a step returns even when it only reads the
|
|
84
|
+
# first entry, because seeing the shape IS what the example is for. Shortening it to
|
|
85
|
+
# `obs, *_ = env.step(...)` would lint better and teach worse.
|
|
86
|
+
"examples/*.py" = ["RUF059"]
|
|
87
|
+
# The quickstart imports its config objects in groups by what they do (the env, what the
|
|
88
|
+
# bot sees and does, what it is paid for, when a battle ends), so a reader sees which piece
|
|
89
|
+
# is which. One sorted block would teach the list and lose the grouping.
|
|
90
|
+
"examples/quickstart.py" = ["RUF059", "I001"]
|
|
91
|
+
# A VENDORED copy, kept byte-identical to the original in the cross-repo harness so the
|
|
92
|
+
# copies in the four public repos can be diffed against each other and against it. Every
|
|
93
|
+
# public repo carries its own, because a guard that lives only in the private repo cannot
|
|
94
|
+
# run for an outside contributor, who is the reader it protects. Reformatting it to this
|
|
95
|
+
# repo's line length would make that diff noisy for no behaviour change, so the line
|
|
96
|
+
# length is waived here and nothing else is.
|
|
97
|
+
"tests/_shell_fences.py" = ["E501"]
|
|
98
|
+
|
|
99
|
+
[tool.ruff.lint.isort]
|
|
100
|
+
known-first-party = ["royalegym", "royalesim"]
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""royalegym -- RL environments over a deterministic Clash Royale engine (RoyaleSim).
|
|
2
|
+
|
|
3
|
+
Components (each an ABC with swappable implementations):
|
|
4
|
+
ObsBuilder obs.py SpatialObsBuilder, EntityListObsBuilder
|
|
5
|
+
ActionParser action.py TileActionParser (Discrete 2305, + ability buttons
|
|
6
|
+
when asked), HalfTileActionParser
|
|
7
|
+
RewardFunction reward.py WinLoss, Crown, TowerHP, ElixirTrade, ElixirLeak, Combined;
|
|
8
|
+
IllegalAction and PlacementDepth ship unused, as templates
|
|
9
|
+
DoneCondition done_condition.py GameOver, FirstCrown (terminations); StepLimit,
|
|
10
|
+
TickLimit (truncations); Any, All (either role)
|
|
11
|
+
StateMutator state_mutator.py Default, MidGame, ScriptedBoard, Snapshot, Weighted
|
|
12
|
+
|
|
13
|
+
A DoneCondition is used in one of two roles, termination (the outcome is decided)
|
|
14
|
+
or truncation (the episode is cut); TerminationCondition and TruncationCondition
|
|
15
|
+
are the role-declaring subclasses, and the envs take termination_cond and
|
|
16
|
+
truncation_cond.
|
|
17
|
+
|
|
18
|
+
Environments (env.py): ClashParallelEnv (PettingZoo), ClashGymEnv (Gymnasium),
|
|
19
|
+
ClashSelfPlayVecEnv (vectorised self-play). Engine contract: protocol.Engine;
|
|
20
|
+
MockEngine is the pure-Python reference implementation; RustEngine
|
|
21
|
+
(rust_engine.py) drives the compiled Rust core through the same protocol.
|
|
22
|
+
|
|
23
|
+
Opponents: selfplay.py has the trivial two (noop, random); opponents.py adds four
|
|
24
|
+
scripted strategies and ``ladder()``, whose ordering is measured rather than assumed.
|
|
25
|
+
|
|
26
|
+
Comparing bots: evaluate.py plays two Opponents head to head on both seats and
|
|
27
|
+
reports a win rate with a Wilson interval, so "A is better" is a claim with an error
|
|
28
|
+
bar rather than a percentage. selfplay.py's OpponentPool keeps Elo across many such
|
|
29
|
+
results.
|
|
30
|
+
|
|
31
|
+
Replays: replay.py records and re-verifies traces; render.py turns one into a
|
|
32
|
+
self-contained HTML viewer (``python -m royalegym.render trace.msgpack -o out.html``).
|
|
33
|
+
render is deliberately NOT imported here: importing it from the package would make
|
|
34
|
+
``python -m royalegym.render`` load the module twice (runpy's RuntimeWarning).
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
38
|
+
|
|
39
|
+
from .action import ActionParser, HalfTileActionParser, PlacementOracle, TileActionParser
|
|
40
|
+
from .done_condition import (
|
|
41
|
+
AllCondition,
|
|
42
|
+
AnyCondition,
|
|
43
|
+
DoneCondition,
|
|
44
|
+
FirstCrownCondition,
|
|
45
|
+
GameOverCondition,
|
|
46
|
+
StepLimitCondition,
|
|
47
|
+
TerminalCondition,
|
|
48
|
+
TerminationCondition,
|
|
49
|
+
TickLimitCondition,
|
|
50
|
+
TruncationCondition,
|
|
51
|
+
)
|
|
52
|
+
from .env import (
|
|
53
|
+
STARTER_DECK,
|
|
54
|
+
ClashGymEnv,
|
|
55
|
+
ClashParallelEnv,
|
|
56
|
+
ClashSelfPlayVecEnv,
|
|
57
|
+
make_env,
|
|
58
|
+
make_gym_vec_env,
|
|
59
|
+
)
|
|
60
|
+
from .evaluate import Battle, MatchResult, SeatResult, evaluate, play_battle
|
|
61
|
+
from .mock_engine import MockEngine
|
|
62
|
+
from .obs import (
|
|
63
|
+
EntityListObsBuilder,
|
|
64
|
+
MatchClock,
|
|
65
|
+
MatchMemory,
|
|
66
|
+
ObsBuilder,
|
|
67
|
+
Reveal,
|
|
68
|
+
SpatialObsBuilder,
|
|
69
|
+
Variability,
|
|
70
|
+
fair_fields,
|
|
71
|
+
measure_variability,
|
|
72
|
+
)
|
|
73
|
+
from .opponents import (
|
|
74
|
+
DefendOpponent,
|
|
75
|
+
FirstAffordableOpponent,
|
|
76
|
+
PatientOpponent,
|
|
77
|
+
PushOpponent,
|
|
78
|
+
ladder,
|
|
79
|
+
)
|
|
80
|
+
from .protocol import Engine, EntityKind, MatchSetup, TowerSlot, Winner, to_own
|
|
81
|
+
from .replay import ReplayRecorder, load_trace, save_trace, verify_trace
|
|
82
|
+
from .reward import (
|
|
83
|
+
CombinedReward,
|
|
84
|
+
CrownReward,
|
|
85
|
+
ElixirLeakPenalty,
|
|
86
|
+
ElixirTradeReward,
|
|
87
|
+
IllegalActionPenalty,
|
|
88
|
+
PlacementDepthReward,
|
|
89
|
+
RewardFunction,
|
|
90
|
+
TowerHPReward,
|
|
91
|
+
WinLossReward,
|
|
92
|
+
default_reward,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# The Rust engine is optional: rust_engine.py imports without the compiled
|
|
96
|
+
# extension and RustEngine() raises ImportError naming the build command.
|
|
97
|
+
from .rust_engine import CORE_IMPORT_ERROR, RustEngine, core_available
|
|
98
|
+
from .selfplay import (
|
|
99
|
+
CallableOpponent,
|
|
100
|
+
NoopOpponent,
|
|
101
|
+
OpponentPool,
|
|
102
|
+
RandomLegalOpponent,
|
|
103
|
+
)
|
|
104
|
+
from .state_mutator import (
|
|
105
|
+
DeckCurriculumStateMutator,
|
|
106
|
+
DefaultStateMutator,
|
|
107
|
+
DefaultStateSetter,
|
|
108
|
+
MidGameStateMutator,
|
|
109
|
+
MidGameStateSetter,
|
|
110
|
+
ScriptedBoardStateMutator,
|
|
111
|
+
ScriptedBoardStateSetter,
|
|
112
|
+
SnapshotStateMutator,
|
|
113
|
+
SnapshotStateSetter,
|
|
114
|
+
StateMutator,
|
|
115
|
+
StateSetter,
|
|
116
|
+
WeightedStateMutator,
|
|
117
|
+
WeightedStateSetter,
|
|
118
|
+
deck_ids,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
#: ``gym.make`` ids. The plain one takes whatever engine you pass and defaults to the
|
|
122
|
+
#: mock WITH A WARNING, because a default that decides which engine a result came from
|
|
123
|
+
#: and does not say so is the one thing this package should never do. The other two name
|
|
124
|
+
#: their engine, so a reader can tell from the id what a number means, and neither warns.
|
|
125
|
+
GYM_ENV_ID = "royalegym/ClashRoyale-v0"
|
|
126
|
+
GYM_MOCK_ENV_ID = "royalegym/ClashRoyaleMock-v0"
|
|
127
|
+
GYM_RUST_ENV_ID = "royalegym/ClashRoyaleRust-v0"
|
|
128
|
+
|
|
129
|
+
#: id -> entry point. Registered at import, as gymnasium expects.
|
|
130
|
+
GYM_ENV_IDS = {
|
|
131
|
+
GYM_ENV_ID: "royalegym.env:ClashGymEnv",
|
|
132
|
+
GYM_MOCK_ENV_ID: "royalegym.env:mock_gym_env",
|
|
133
|
+
GYM_RUST_ENV_ID: "royalegym.env:rust_gym_env",
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _register() -> None:
|
|
138
|
+
import gymnasium
|
|
139
|
+
|
|
140
|
+
for env_id, entry_point in GYM_ENV_IDS.items():
|
|
141
|
+
if env_id not in gymnasium.registry:
|
|
142
|
+
gymnasium.register(id=env_id, entry_point=entry_point)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
_register()
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
__version__ = version("royalegym")
|
|
149
|
+
except PackageNotFoundError: # a source tree that was never installed
|
|
150
|
+
__version__ = "0+unknown"
|
|
151
|
+
|
|
152
|
+
__all__ = [
|
|
153
|
+
"CORE_IMPORT_ERROR",
|
|
154
|
+
"GYM_ENV_ID",
|
|
155
|
+
"GYM_ENV_IDS",
|
|
156
|
+
"GYM_MOCK_ENV_ID",
|
|
157
|
+
"GYM_RUST_ENV_ID",
|
|
158
|
+
"STARTER_DECK",
|
|
159
|
+
"ActionParser",
|
|
160
|
+
"AllCondition",
|
|
161
|
+
"AnyCondition",
|
|
162
|
+
"Battle",
|
|
163
|
+
"CallableOpponent",
|
|
164
|
+
"ClashGymEnv",
|
|
165
|
+
"ClashParallelEnv",
|
|
166
|
+
"ClashSelfPlayVecEnv",
|
|
167
|
+
"CombinedReward",
|
|
168
|
+
"CrownReward",
|
|
169
|
+
"DeckCurriculumStateMutator",
|
|
170
|
+
"DefaultStateMutator",
|
|
171
|
+
"DefaultStateSetter",
|
|
172
|
+
"DefendOpponent",
|
|
173
|
+
"DoneCondition",
|
|
174
|
+
"ElixirLeakPenalty",
|
|
175
|
+
"ElixirTradeReward",
|
|
176
|
+
"Engine",
|
|
177
|
+
"EntityKind",
|
|
178
|
+
"EntityListObsBuilder",
|
|
179
|
+
"FirstAffordableOpponent",
|
|
180
|
+
"FirstCrownCondition",
|
|
181
|
+
"GameOverCondition",
|
|
182
|
+
"HalfTileActionParser",
|
|
183
|
+
"IllegalActionPenalty",
|
|
184
|
+
"MatchClock",
|
|
185
|
+
"MatchMemory",
|
|
186
|
+
"MatchResult",
|
|
187
|
+
"MatchSetup",
|
|
188
|
+
"MidGameStateMutator",
|
|
189
|
+
"MidGameStateSetter",
|
|
190
|
+
"MockEngine",
|
|
191
|
+
"NoopOpponent",
|
|
192
|
+
"ObsBuilder",
|
|
193
|
+
"OpponentPool",
|
|
194
|
+
"PatientOpponent",
|
|
195
|
+
"PlacementDepthReward",
|
|
196
|
+
"PlacementOracle",
|
|
197
|
+
"PushOpponent",
|
|
198
|
+
"RandomLegalOpponent",
|
|
199
|
+
"ReplayRecorder",
|
|
200
|
+
"Reveal",
|
|
201
|
+
"RewardFunction",
|
|
202
|
+
"RustEngine",
|
|
203
|
+
"ScriptedBoardStateMutator",
|
|
204
|
+
"ScriptedBoardStateSetter",
|
|
205
|
+
"SeatResult",
|
|
206
|
+
"SnapshotStateMutator",
|
|
207
|
+
"SnapshotStateSetter",
|
|
208
|
+
"SpatialObsBuilder",
|
|
209
|
+
"StateMutator",
|
|
210
|
+
"StateSetter",
|
|
211
|
+
"StepLimitCondition",
|
|
212
|
+
"TerminalCondition",
|
|
213
|
+
"TerminationCondition",
|
|
214
|
+
"TickLimitCondition",
|
|
215
|
+
"TileActionParser",
|
|
216
|
+
"TowerHPReward",
|
|
217
|
+
"TowerSlot",
|
|
218
|
+
"TruncationCondition",
|
|
219
|
+
"Variability",
|
|
220
|
+
"WeightedStateMutator",
|
|
221
|
+
"WeightedStateSetter",
|
|
222
|
+
"WinLossReward",
|
|
223
|
+
"Winner",
|
|
224
|
+
"core_available",
|
|
225
|
+
"deck_ids",
|
|
226
|
+
"default_reward",
|
|
227
|
+
"evaluate",
|
|
228
|
+
"fair_fields",
|
|
229
|
+
"ladder",
|
|
230
|
+
"load_trace",
|
|
231
|
+
"make_env",
|
|
232
|
+
"make_gym_vec_env",
|
|
233
|
+
"measure_variability",
|
|
234
|
+
"play_battle",
|
|
235
|
+
"save_trace",
|
|
236
|
+
"to_own",
|
|
237
|
+
"verify_trace",
|
|
238
|
+
]
|