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.
Files changed (112) hide show
  1. royalegym-0.1.12/LICENSE +21 -0
  2. royalegym-0.1.12/PKG-INFO +34 -0
  3. royalegym-0.1.12/README.md +40 -0
  4. royalegym-0.1.12/pyproject.toml +100 -0
  5. royalegym-0.1.12/royalegym/__init__.py +238 -0
  6. royalegym-0.1.12/royalegym/action.py +1109 -0
  7. royalegym-0.1.12/royalegym/done_condition.py +154 -0
  8. royalegym-0.1.12/royalegym/env.py +1288 -0
  9. royalegym-0.1.12/royalegym/evaluate.py +346 -0
  10. royalegym-0.1.12/royalegym/landing.py +439 -0
  11. royalegym-0.1.12/royalegym/mock_engine.py +1612 -0
  12. royalegym-0.1.12/royalegym/obs.py +2834 -0
  13. royalegym-0.1.12/royalegym/opponents.py +253 -0
  14. royalegym-0.1.12/royalegym/protocol.py +1806 -0
  15. royalegym-0.1.12/royalegym/py.typed +0 -0
  16. royalegym-0.1.12/royalegym/render.py +859 -0
  17. royalegym-0.1.12/royalegym/replay.py +531 -0
  18. royalegym-0.1.12/royalegym/reward.py +451 -0
  19. royalegym-0.1.12/royalegym/rust_engine.py +1620 -0
  20. royalegym-0.1.12/royalegym/selfplay.py +264 -0
  21. royalegym-0.1.12/royalegym/state_mutator.py +496 -0
  22. royalegym-0.1.12/royalegym/viser.py +461 -0
  23. royalegym-0.1.12/royalegym.egg-info/PKG-INFO +34 -0
  24. royalegym-0.1.12/royalegym.egg-info/SOURCES.txt +110 -0
  25. royalegym-0.1.12/royalegym.egg-info/dependency_links.txt +1 -0
  26. royalegym-0.1.12/royalegym.egg-info/requires.txt +34 -0
  27. royalegym-0.1.12/royalegym.egg-info/top_level.txt +1 -0
  28. royalegym-0.1.12/setup.cfg +4 -0
  29. royalegym-0.1.12/tests/test_ability_buttons.py +481 -0
  30. royalegym-0.1.12/tests/test_action_ground_truth.py +223 -0
  31. royalegym-0.1.12/tests/test_addressable_episodes.py +273 -0
  32. royalegym-0.1.12/tests/test_architecture_doc.py +147 -0
  33. royalegym-0.1.12/tests/test_building_footprint.py +1059 -0
  34. royalegym-0.1.12/tests/test_building_tap_arms.py +400 -0
  35. royalegym-0.1.12/tests/test_calibration_overrides.py +204 -0
  36. royalegym-0.1.12/tests/test_card_identity.py +288 -0
  37. royalegym-0.1.12/tests/test_card_status.py +308 -0
  38. royalegym-0.1.12/tests/test_card_table_stamp.py +535 -0
  39. royalegym-0.1.12/tests/test_ci_workflow.py +270 -0
  40. royalegym-0.1.12/tests/test_command_delay.py +224 -0
  41. royalegym-0.1.12/tests/test_cross_process_determinism.py +179 -0
  42. royalegym-0.1.12/tests/test_deck_curriculum.py +340 -0
  43. royalegym-0.1.12/tests/test_deploy_lockout.py +158 -0
  44. royalegym-0.1.12/tests/test_entitylist_ground_truth.py +318 -0
  45. royalegym-0.1.12/tests/test_env_action_mask.py +624 -0
  46. royalegym-0.1.12/tests/test_env_api.py +552 -0
  47. royalegym-0.1.12/tests/test_env_mask_property.py +437 -0
  48. royalegym-0.1.12/tests/test_env_mock_engine.py +650 -0
  49. royalegym-0.1.12/tests/test_env_obs.py +1776 -0
  50. royalegym-0.1.12/tests/test_env_protocol.py +442 -0
  51. royalegym-0.1.12/tests/test_env_render.py +560 -0
  52. royalegym-0.1.12/tests/test_evaluate.py +248 -0
  53. royalegym-0.1.12/tests/test_evo_cycle.py +58 -0
  54. royalegym-0.1.12/tests/test_evo_obs.py +272 -0
  55. royalegym-0.1.12/tests/test_examples.py +107 -0
  56. royalegym-0.1.12/tests/test_fair_fields.py +419 -0
  57. royalegym-0.1.12/tests/test_final_info_ground_truth.py +297 -0
  58. royalegym-0.1.12/tests/test_fresh_user_try_its.py +71 -0
  59. royalegym-0.1.12/tests/test_gym_ids.py +235 -0
  60. royalegym-0.1.12/tests/test_hero_obs.py +258 -0
  61. royalegym-0.1.12/tests/test_install_pointers.py +383 -0
  62. royalegym-0.1.12/tests/test_invisible_characters.py +184 -0
  63. royalegym-0.1.12/tests/test_landing.py +290 -0
  64. royalegym-0.1.12/tests/test_levels.py +140 -0
  65. royalegym-0.1.12/tests/test_mirror_memory.py +207 -0
  66. royalegym-0.1.12/tests/test_obs_builder_equality.py +324 -0
  67. royalegym-0.1.12/tests/test_obs_ground_truth.py +288 -0
  68. royalegym-0.1.12/tests/test_obs_responds_to_the_state.py +574 -0
  69. royalegym-0.1.12/tests/test_opponents.py +310 -0
  70. royalegym-0.1.12/tests/test_overtime_play_stops.py +128 -0
  71. royalegym-0.1.12/tests/test_overtime_tiebreak.py +304 -0
  72. royalegym-0.1.12/tests/test_packaging.py +300 -0
  73. royalegym-0.1.12/tests/test_parity_hardening.py +493 -0
  74. royalegym-0.1.12/tests/test_placement_invariant.py +169 -0
  75. royalegym-0.1.12/tests/test_player_deck.py +72 -0
  76. royalegym-0.1.12/tests/test_press_memory.py +227 -0
  77. royalegym-0.1.12/tests/test_press_runs.py +143 -0
  78. royalegym-0.1.12/tests/test_princess_centres.py +147 -0
  79. royalegym-0.1.12/tests/test_quickstart.py +102 -0
  80. royalegym-0.1.12/tests/test_random_deck_champions.py +97 -0
  81. royalegym-0.1.12/tests/test_readme_program.py +401 -0
  82. royalegym-0.1.12/tests/test_readme_try_it.py +64 -0
  83. royalegym-0.1.12/tests/test_refill_delay.py +70 -0
  84. royalegym-0.1.12/tests/test_reveal_mapping.py +43 -0
  85. royalegym-0.1.12/tests/test_reward_ground_truth.py +743 -0
  86. royalegym-0.1.12/tests/test_rewards.py +705 -0
  87. royalegym-0.1.12/tests/test_rust_engine.py +2297 -0
  88. royalegym-0.1.12/tests/test_rust_spells.py +640 -0
  89. royalegym-0.1.12/tests/test_saving_recorder.py +224 -0
  90. royalegym-0.1.12/tests/test_selfplay_pool.py +271 -0
  91. royalegym-0.1.12/tests/test_shared_oracle.py +156 -0
  92. royalegym-0.1.12/tests/test_shell_fences.py +149 -0
  93. royalegym-0.1.12/tests/test_site_examples.py +565 -0
  94. royalegym-0.1.12/tests/test_spatial_exact_storage.py +90 -0
  95. royalegym-0.1.12/tests/test_spawn_arrangement.py +272 -0
  96. royalegym-0.1.12/tests/test_spell_aim_after.py +206 -0
  97. royalegym-0.1.12/tests/test_spell_id_obs.py +183 -0
  98. royalegym-0.1.12/tests/test_stage_release.py +92 -0
  99. royalegym-0.1.12/tests/test_state_mutator_names.py +38 -0
  100. royalegym-0.1.12/tests/test_step_result_arity.py +171 -0
  101. royalegym-0.1.12/tests/test_trace_forms.py +96 -0
  102. royalegym-0.1.12/tests/test_trace_step_records.py +443 -0
  103. royalegym-0.1.12/tests/test_train_harness.py +776 -0
  104. royalegym-0.1.12/tests/test_troop_tower_taps.py +656 -0
  105. royalegym-0.1.12/tests/test_tunnel_and_mirror.py +306 -0
  106. royalegym-0.1.12/tests/test_unit_actions_obs.py +219 -0
  107. royalegym-0.1.12/tests/test_unit_hitpoints.py +48 -0
  108. royalegym-0.1.12/tests/test_unit_status_and_projectiles.py +468 -0
  109. royalegym-0.1.12/tests/test_unit_status_obs.py +355 -0
  110. royalegym-0.1.12/tests/test_vector_writer.py +313 -0
  111. royalegym-0.1.12/tests/test_viewer_frame_rate.py +187 -0
  112. royalegym-0.1.12/tests/test_viser.py +201 -0
@@ -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
+ ]