Skip to content

Commit afe9efd

Browse files
john-b-yangclaude
andauthored
Add RoboCode CC:Ladder (#115)
* Add RoboCode CC:Ladder (116 imported classic-Robocode bots + build tooling) - 116 open-source classic Robocode bots imported to CodeClash-ai/RoboCode human/robocode/* branches (source of truth, not committed here) from ~30 repos: shipped sample bots + mgalushka Super* variants; the full RoboWiki/PEZ collection (micro/mini/nano/femto + Marshmallow/GF1/Swiffer); flat multi-file bots (Mb2, BerendBotje, MaximBot, TheCarver, BobTheBuilder, StarterBot, npcomplete); flattened subpackage bots (ur4no, kokomo); single-file DrussGT/HawkOnFire (strong top rungs); and ~35 more from a broad GitHub sweep. All copy-in (0 reimplementations) -- verbatim, only repackaged to the arena package + main class renamed to MyTank (helpers flattened where needed). yngwie/chomsky skipped (unresolvable external deps). - Each of the 116 verified to COMPILE and play a real battle in the arena image (stage 2, 116/116). - Provenance: every port file carries a source-URL/author/license header; scripts/ladder/SOURCES.md is the committed manifest (slug -> GitHub URL). See stamp_sources.py. - Fix arena description: it mislabeled itself Tank Royale but the engine is classic Robocode. - make_robocode.yaml: round-robin (100 rounds, ~2h local at -w6) for Elo; README note. - scripts/ladder/: build tooling (copy-in porting guide, structural validator, compile+battle smoke, push script, provenance stamper, reference bot); ports/ regenerated, not committed. * Fix ladder player names for RoboCode; bump make_robocode sims to 300 `ladder make` set the per-player name to the raw branch_init (e.g. `human/robocode/walls`), which the RoboCode arena turns into an on-disk dir, a Java package via `sed s/custom/<name>/`, and a robot-selector token. Slashes broke the sed (terminating the s/// command) and produced invalid robot names, so battles loaded 0 robots and get_results crashed on max() of an empty score dict. Sanitizing to `robocode_<bot>` still failed: RoboCode reserves the `robocode` package namespace for its engine, so its robot classloader refuses any robot whose package starts with it (ClassNotFoundException at battle time). Add `_player_slug()` (shared by make + run) that strips the `human/` prefix and a leading path segment equal to the game name, yielding a bare `<bot>` package (e.g. `human/robocode/walls` -> `walls`). Non-RoboCode branches (`human/<author>/<bot>`, `human/<bot>`) are unaffected -- their leading segment never matches the game name, so slugs are identical to before. Bump make_robocode.yaml sims_per_round 100 -> 300 for lower Elo variance (~41s/pair solo, ~25s/pair throughput under -w 6; still far under the 5-min/pair budget) and refresh the cost comment with measured numbers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Disable replay recording in make_robocode (record_ratio: 0) The round-robin only needs per-battle scores to fit Elo; recording every sim wrote ~8.7MB of compressed replay XML per pair (~59GB over 6670 pairs, risking disk exhaustion mid-run) and pinned a gzip core on each log copy. Scores come from results_*.txt, which is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix "/" bug in agent naming * nit --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 441403b commit afe9efd

4 files changed

Lines changed: 290 additions & 5 deletions

File tree

codeclash/arenas/robocode/robocode.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@
1818

1919
class RoboCodeArena(CodeArena):
2020
name: str = "RoboCode"
21-
description: str = f"""Robocode (Tank Royale) is a programming game where your code is the tank: each turn your bot sends intents—speed plus body/gun/radar turn rates and firepower—based on the game state it perceives via radar.
22-
Your program decides how to move, aim, and fire in a deterministic, turn-based arena to outlast other bots.
21+
description: str = f"""Robocode is a programming game where your code IS the tank. This is classic
22+
Robocode (the `robocode.*` API compiled against robocode.jar) — NOT Robocode Tank Royale.
23+
Your bot is a Java class that `extends robocode.Robot` (or `robocode.AdvancedRobot` for non-blocking
24+
control): its `run()` method drives the tank in a loop (e.g. `ahead(100)`, `turnGunRight(90)`,
25+
`fire(3)`), and it reacts to events like `onScannedRobot(ScannedRobotEvent)`, `onHitByBullet(...)`,
26+
and `onHitWall(...)`. Move, aim the gun, sweep the radar, and fire to outlast other bots.
2327
Your bot logic must be written in Java and located in the `robots/custom/` directory.
2428
Keep the main bot class named `{str(RC_FILE)}`, but you can include additional Java files if you'd like."""
2529
default_args: dict = {

codeclash/tournaments/ladder.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727
logger = get_logger("ladder")
2828

2929

30+
def _player_slug(branch_init: str) -> str:
31+
"""
32+
Turn a ``human/<author>/<bot>`` init branch into a bare, filesystem-safe player name:
33+
strip the ``human/`` prefix and join the rest with ``__`` (e.g. ``human/aleksiy325/snek-two``
34+
-> ``aleksiy325__snek-two``).
35+
"""
36+
return branch_init.replace("human/", "").replace("/", "__")
37+
38+
3039
def resolve_ladder_rules(ladder_rules: dict, rounds: int) -> tuple[int, int]:
3140
"""Validate the required ``ladder_rules`` block and return ``(min_round_wins, win_last_k)``.
3241
@@ -88,9 +97,9 @@ def build_ladder(config: dict, workers: int = 1) -> None:
8897
for i in range(num_players):
8998
for j in range(i + 1, num_players):
9099
player1 = copy.deepcopy(players[i])
91-
player1["name"] = player1["branch_init"]
100+
player1["name"] = _player_slug(player1["branch_init"])
92101
player2 = copy.deepcopy(players[j])
93-
player2["name"] = player2["branch_init"]
102+
player2["name"] = _player_slug(player2["branch_init"])
94103
pvp_config = {**copy.deepcopy(config), "players": [player1, player2]}
95104
vs = f"PvpTournament.{player1['name']}_vs_{player2['name']}".replace("/", "_")
96105
output_dir = LOCAL_LOG_DIR / "ladder" / config["game"]["name"] / vs
@@ -199,7 +208,7 @@ def run(self) -> dict:
199208
opponent_rank = 0
200209
for idx, opponent in enumerate(self.ladder):
201210
opponent_rank = len(self.ladder) - idx
202-
opponent["name"] = opponent["branch_init"].replace("human/", "").replace("/", "_")
211+
opponent["name"] = _player_slug(opponent["branch_init"])
203212
if "branch_init" in self.player and idx > 0:
204213
# After first opponent, remove branch_init so the player continues from the
205214
# previous tournament's codebase.

configs/ladder/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ open-source Gomoku/Gobang AIs ported into the arena's single-file `get_move(boar
2121
lihongxun945, blackstone, blupig) reimplemented in stdlib Python — alongside a strategic starter.
2222
AlphaZero/CNN bots were skipped (need trained weights).
2323

24+
### RoboCode (newly added)
25+
26+
The [CC:RoboCode](https://github.com/CodeClash-ai/RoboCode) repo hosts 116 human bots on `human/robocode/*`
27+
branches (bot code lives only on the branches, not in this repo). This arena is **classic Robocode**
28+
(`robocode.*` API compiled against `robocode.jar`), so importing open-source bots is mostly a
29+
mechanical copy-in + rename rather than a strategy rewrite: each bot's Java class(es) are placed in
30+
`robots/custom/`, the main class renamed to `MyTank`, `package custom;`. The set spans the shipped
31+
sample bots (SittingDuck/Walls/Corners/…) through famous RoboWiki/PEZ micro-mini bots (Aristocles,
32+
Pugilist, HawkOnFire) up to a single-file **DrussGT** (a world-class bot) as the top rung; a few use
33+
Robocode's sanctioned `getDataFile` persistence (degrades gracefully without cross-battle saves).
34+
Diamond/BeepBoop remain as future top rungs (nested-package multi-file → need flattening). Each import
35+
was verified to **compile and play a real battle**; every bot's source repo/author/license is recorded
36+
as a header comment in its branch files.
37+
2438
## Config layout
2539

2640
Each arena has a few kinds of config in this folder:

configs/ladder/make_robocode.yaml

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Round-robin over the human classic-Robocode bots (imported from ~30 open-source repos; each bot's
2+
# origin URL/author/license is recorded as a header comment in its human/* branch files), used to
3+
# RANK them via Elo/Bradley-Terry -> see robocode.yaml. rounds:0 = dummy players play baseline
4+
# battles (no code edits). N bots -> N*(N-1)/2 pairs; each pair plays sims_per_round rounds (batched
5+
# 10 at a time, sim_concurrency parallel). Bots live on CodeClash-ai/RoboCode human/* branches; Docker required.
6+
# COST (measured on an 8-core box: a pair is ~11.8s fixed overhead + ~9.7s per 100 sims, so at
7+
# sims_per_round=300 a single pair is ~41s solo and ~25s/pair of throughput under --workers 6).
8+
# 116 bots -> 6670 pairs -> ~46 core-hours -> ~2 days on an 8-core box (-w 6). Resumable: skips
9+
# already-logged pairs, so a killed run can be re-launched. Scale --workers with cores (~cores-2).
10+
# Run: uv run codeclash ladder make configs/ladder/make_robocode.yaml --workers 6
11+
tournament:
12+
rounds: 0
13+
game:
14+
name: RoboCode
15+
sims_per_round: 300
16+
sim_concurrency: 5
17+
# Ranking only needs per-battle scores (results_*.txt), not replays. Recording every sim writes
18+
# ~8.7MB of compressed replay XML per pair (~59GB over 6670 pairs) and pins a gzip core on every
19+
# log copy, so disable it here.
20+
record_ratio: 0
21+
args:
22+
nodisplay: true
23+
nosound: true
24+
players:
25+
- agent: dummy
26+
branch_init: human/kinnla/antiwalls
27+
- agent: dummy
28+
branch_init: human/pez/aristocles
29+
- agent: dummy
30+
branch_init: human/vftheodoro/barbiescript
31+
- agent: dummy
32+
branch_init: human/johan_adriaans/berendbotje
33+
- agent: dummy
34+
branch_init: human/pez/blackwidow
35+
- agent: dummy
36+
branch_init: human/pez/blackwidow_mini
37+
- agent: dummy
38+
branch_init: human/winstliu/bobthebuilder
39+
- agent: dummy
40+
branch_init: human/lucasgch/bt7274
41+
- agent: dummy
42+
branch_init: human/namnguyenthanhwork/cham
43+
- agent: dummy
44+
branch_init: human/looklazy/chilibot
45+
- agent: dummy
46+
branch_init: human/pez/chironex_micro
47+
- agent: dummy
48+
branch_init: human/pez/chironex_mini
49+
- agent: dummy
50+
branch_init: human/robo_code/corners
51+
- agent: dummy
52+
branch_init: human/txeverson/crawler
53+
- agent: dummy
54+
branch_init: human/robo_code/crazy
55+
- agent: dummy
56+
branch_init: human/philipmjohnson/dacruzer
57+
- agent: dummy
58+
branch_init: human/trex22/deepthought
59+
- agent: dummy
60+
branch_init: human/pseminatore/dodgebot_jnk
61+
- agent: dummy
62+
branch_init: human/logancsc/dodgebot2
63+
- agent: dummy
64+
branch_init: human/vikdov/dominatorx
65+
- agent: dummy
66+
branch_init: human/pez/droidpoet
67+
- agent: dummy
68+
branch_init: human/admiralrasmussen/drussgt
69+
- agent: dummy
70+
branch_init: human/andrekorol/exterminador
71+
- agent: dummy
72+
branch_init: human/robo_code/fire
73+
- agent: dummy
74+
branch_init: human/pez/frankie
75+
- agent: dummy
76+
branch_init: human/linuxuser0/genetic
77+
- agent: dummy
78+
branch_init: human/pez/gf1
79+
- agent: dummy
80+
branch_init: human/josephjeon/gntest
81+
- agent: dummy
82+
branch_init: human/pez/gouldingi
83+
- agent: dummy
84+
branch_init: human/kylebennett/gruffalo
85+
- agent: dummy
86+
branch_init: human/pez/haikupoet
87+
- agent: dummy
88+
branch_init: human/pez/haikuwalls
89+
- agent: dummy
90+
branch_init: human/admiralrasmussen/hawkonfire
91+
- agent: dummy
92+
branch_init: human/zhiwei121/hero_pm
93+
- agent: dummy
94+
branch_init: human/kylebennett/hugbot
95+
- agent: dummy
96+
branch_init: human/mcd8604/hunter
97+
- agent: dummy
98+
branch_init: human/pez/hypoleach
99+
- agent: dummy
100+
branch_init: human/alpian/ianstank
101+
- agent: dummy
102+
branch_init: human/pez/icarus
103+
- agent: dummy
104+
branch_init: human/wouterjoosse/infinitylock
105+
- agent: dummy
106+
branch_init: human/it_economics/ite_bomax
107+
- agent: dummy
108+
branch_init: human/it_economics/ite_claptrap
109+
- agent: dummy
110+
branch_init: human/it_economics/ite_cliffbot2
111+
- agent: dummy
112+
branch_init: human/it_economics/ite_ctbot
113+
- agent: dummy
114+
branch_init: human/it_economics/ite_florian2
115+
- agent: dummy
116+
branch_init: human/it_economics/ite_m9
117+
- agent: dummy
118+
branch_init: human/it_economics/ite_simple
119+
- agent: dummy
120+
branch_init: human/it_economics/ite_terminator
121+
- agent: dummy
122+
branch_init: human/joaomcarvalho/jeujdapeu
123+
- agent: dummy
124+
branch_init: human/dankraemer/juggernaut
125+
- agent: dummy
126+
branch_init: human/u_0x65_e/kokomo
127+
- agent: dummy
128+
branch_init: human/pez/leach
129+
- agent: dummy
130+
branch_init: human/pez/leachpmc
131+
- agent: dummy
132+
branch_init: human/pez/littlebrother
133+
- agent: dummy
134+
branch_init: human/pez/littleevilbrother
135+
- agent: dummy
136+
branch_init: human/pez/mako
137+
- agent: dummy
138+
branch_init: human/tibola/markiv
139+
- agent: dummy
140+
branch_init: human/zcjerry229/markrobo
141+
- agent: dummy
142+
branch_init: human/pez/marshmallow
143+
- agent: dummy
144+
branch_init: human/mgalushka/maximbot
145+
- agent: dummy
146+
branch_init: human/gjgomez/mb2
147+
- agent: dummy
148+
branch_init: human/denssle/megaborsten
149+
- agent: dummy
150+
branch_init: human/team488/meow
151+
- agent: dummy
152+
branch_init: human/andrekorol/myfirstkiller
153+
- agent: dummy
154+
branch_init: human/robo_code/myfirstrobot
155+
- agent: dummy
156+
branch_init: human/luke_f_w/nagisphere
157+
- agent: dummy
158+
branch_init: human/andr3eee1/npcomplete
159+
- agent: dummy
160+
branch_init: human/iagomonteiro13579/npcsniper
161+
- agent: dummy
162+
branch_init: human/andrekorol/oppswantmedead
163+
- agent: dummy
164+
branch_init: human/pez/paolo
165+
- agent: dummy
166+
branch_init: human/kcanida/pikachu
167+
- agent: dummy
168+
branch_init: human/pez/poet
169+
- agent: dummy
170+
branch_init: human/pmontp19/propiavancat
171+
- agent: dummy
172+
branch_init: human/pez/pugilist
173+
- agent: dummy
174+
branch_init: human/gabriel_lw/quadwall
175+
- agent: dummy
176+
branch_init: human/robo_code/ramfire
177+
- agent: dummy
178+
branch_init: human/robo_code/regullarmonk
179+
- agent: dummy
180+
branch_init: human/g_otn/reimu
181+
- agent: dummy
182+
branch_init: human/sacdalance/robrrrat
183+
- agent: dummy
184+
branch_init: human/miradoconsulting/roleksii
185+
- agent: dummy
186+
branch_init: human/avsthiago/sadbot
187+
- agent: dummy
188+
branch_init: human/alexbay218/shreker
189+
- agent: dummy
190+
branch_init: human/robo_code/sittingduck
191+
- agent: dummy
192+
branch_init: human/pez/smallpoet
193+
- agent: dummy
194+
branch_init: human/robo_code/spinbot
195+
- agent: dummy
196+
branch_init: human/jonharder/starterbot
197+
- agent: dummy
198+
branch_init: human/mgalushka/supercorners
199+
- agent: dummy
200+
branch_init: human/mgalushka/supercrazy
201+
- agent: dummy
202+
branch_init: human/mgalushka/supermercutio
203+
- agent: dummy
204+
branch_init: human/mgalushka/superramfire
205+
- agent: dummy
206+
branch_init: human/mgalushka/superspinbot
207+
- agent: dummy
208+
branch_init: human/mgalushka/supertracker
209+
- agent: dummy
210+
branch_init: human/mgalushka/superwalls
211+
- agent: dummy
212+
branch_init: human/pez/swiffer
213+
- agent: dummy
214+
branch_init: human/tannerrogalsky/tannerbot1
215+
- agent: dummy
216+
branch_init: human/alpian/tarektank
217+
- agent: dummy
218+
branch_init: human/technischeinformatica/tearsofsteel
219+
- agent: dummy
220+
branch_init: human/pranav_prakash/thecarver
221+
- agent: dummy
222+
branch_init: human/barriosnahuel/tirolio
223+
- agent: dummy
224+
branch_init: human/pez/tityus
225+
- agent: dummy
226+
branch_init: human/robo_code/tracker
227+
- agent: dummy
228+
branch_init: human/robo_code/trackfire
229+
- agent: dummy
230+
branch_init: human/muzardo/trianglehunter
231+
- agent: dummy
232+
branch_init: human/rafaeljdesa/ultron
233+
- agent: dummy
234+
branch_init: human/ur4n0_235/ur4no
235+
- agent: dummy
236+
branch_init: human/robo_code/velocirobot
237+
- agent: dummy
238+
branch_init: human/john_paul_r/vergere
239+
- agent: dummy
240+
branch_init: human/pez/vertileach
241+
- agent: dummy
242+
branch_init: human/pez/vertimicro
243+
- agent: dummy
244+
branch_init: human/robo_code/walls
245+
- agent: dummy
246+
branch_init: human/pez/wallspoet
247+
- agent: dummy
248+
branch_init: human/pez/wallspoetas
249+
- agent: dummy
250+
branch_init: human/pez/wallspoethaiku
251+
- agent: dummy
252+
branch_init: human/admiralrasmussen/wavesurfing
253+
- agent: dummy
254+
branch_init: human/alexjamesmacpherson/wilde
255+
- agent: dummy
256+
branch_init: human/joaocarpim/wrecker
257+
prompts:
258+
game_description: RoboCode ladder

0 commit comments

Comments
 (0)