diff --git a/codeclash/arenas/robocode/robocode.py b/codeclash/arenas/robocode/robocode.py index 1c59527..262b791 100644 --- a/codeclash/arenas/robocode/robocode.py +++ b/codeclash/arenas/robocode/robocode.py @@ -18,8 +18,12 @@ class RoboCodeArena(CodeArena): name: str = "RoboCode" - 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. -Your program decides how to move, aim, and fire in a deterministic, turn-based arena to outlast other bots. + description: str = f"""Robocode is a programming game where your code IS the tank. This is classic +Robocode (the `robocode.*` API compiled against robocode.jar) — NOT Robocode Tank Royale. +Your bot is a Java class that `extends robocode.Robot` (or `robocode.AdvancedRobot` for non-blocking +control): its `run()` method drives the tank in a loop (e.g. `ahead(100)`, `turnGunRight(90)`, +`fire(3)`), and it reacts to events like `onScannedRobot(ScannedRobotEvent)`, `onHitByBullet(...)`, +and `onHitWall(...)`. Move, aim the gun, sweep the radar, and fire to outlast other bots. Your bot logic must be written in Java and located in the `robots/custom/` directory. Keep the main bot class named `{str(RC_FILE)}`, but you can include additional Java files if you'd like.""" default_args: dict = { diff --git a/codeclash/tournaments/ladder.py b/codeclash/tournaments/ladder.py index 6083e5a..95ad7c3 100644 --- a/codeclash/tournaments/ladder.py +++ b/codeclash/tournaments/ladder.py @@ -27,6 +27,15 @@ logger = get_logger("ladder") +def _player_slug(branch_init: str) -> str: + """ + Turn a ``human//`` init branch into a bare, filesystem-safe player name: + strip the ``human/`` prefix and join the rest with ``__`` (e.g. ``human/aleksiy325/snek-two`` + -> ``aleksiy325__snek-two``). + """ + return branch_init.replace("human/", "").replace("/", "__") + + def resolve_ladder_rules(ladder_rules: dict, rounds: int) -> tuple[int, int]: """Validate the required ``ladder_rules`` block and return ``(min_round_wins, win_last_k)``. @@ -88,9 +97,9 @@ def build_ladder(config: dict, workers: int = 1) -> None: for i in range(num_players): for j in range(i + 1, num_players): player1 = copy.deepcopy(players[i]) - player1["name"] = player1["branch_init"] + player1["name"] = _player_slug(player1["branch_init"]) player2 = copy.deepcopy(players[j]) - player2["name"] = player2["branch_init"] + player2["name"] = _player_slug(player2["branch_init"]) pvp_config = {**copy.deepcopy(config), "players": [player1, player2]} vs = f"PvpTournament.{player1['name']}_vs_{player2['name']}".replace("/", "_") output_dir = LOCAL_LOG_DIR / "ladder" / config["game"]["name"] / vs @@ -199,7 +208,7 @@ def run(self) -> dict: opponent_rank = 0 for idx, opponent in enumerate(self.ladder): opponent_rank = len(self.ladder) - idx - opponent["name"] = opponent["branch_init"].replace("human/", "").replace("/", "_") + opponent["name"] = _player_slug(opponent["branch_init"]) if "branch_init" in self.player and idx > 0: # After first opponent, remove branch_init so the player continues from the # previous tournament's codebase. diff --git a/configs/ladder/README.md b/configs/ladder/README.md index 86348f2..49955f8 100644 --- a/configs/ladder/README.md +++ b/configs/ladder/README.md @@ -21,6 +21,20 @@ open-source Gomoku/Gobang AIs ported into the arena's single-file `get_move(boar lihongxun945, blackstone, blupig) reimplemented in stdlib Python — alongside a strategic starter. AlphaZero/CNN bots were skipped (need trained weights). +### RoboCode (newly added) + +The [CC:RoboCode](https://github.com/CodeClash-ai/RoboCode) repo hosts 116 human bots on `human/robocode/*` +branches (bot code lives only on the branches, not in this repo). This arena is **classic Robocode** +(`robocode.*` API compiled against `robocode.jar`), so importing open-source bots is mostly a +mechanical copy-in + rename rather than a strategy rewrite: each bot's Java class(es) are placed in +`robots/custom/`, the main class renamed to `MyTank`, `package custom;`. The set spans the shipped +sample bots (SittingDuck/Walls/Corners/…) through famous RoboWiki/PEZ micro-mini bots (Aristocles, +Pugilist, HawkOnFire) up to a single-file **DrussGT** (a world-class bot) as the top rung; a few use +Robocode's sanctioned `getDataFile` persistence (degrades gracefully without cross-battle saves). +Diamond/BeepBoop remain as future top rungs (nested-package multi-file → need flattening). Each import +was verified to **compile and play a real battle**; every bot's source repo/author/license is recorded +as a header comment in its branch files. + ## Config layout Each arena has a few kinds of config in this folder: diff --git a/configs/ladder/make_robocode.yaml b/configs/ladder/make_robocode.yaml new file mode 100644 index 0000000..c44fdef --- /dev/null +++ b/configs/ladder/make_robocode.yaml @@ -0,0 +1,258 @@ +# Round-robin over the human classic-Robocode bots (imported from ~30 open-source repos; each bot's +# origin URL/author/license is recorded as a header comment in its human/* branch files), used to +# RANK them via Elo/Bradley-Terry -> see robocode.yaml. rounds:0 = dummy players play baseline +# battles (no code edits). N bots -> N*(N-1)/2 pairs; each pair plays sims_per_round rounds (batched +# 10 at a time, sim_concurrency parallel). Bots live on CodeClash-ai/RoboCode human/* branches; Docker required. +# COST (measured on an 8-core box: a pair is ~11.8s fixed overhead + ~9.7s per 100 sims, so at +# sims_per_round=300 a single pair is ~41s solo and ~25s/pair of throughput under --workers 6). +# 116 bots -> 6670 pairs -> ~46 core-hours -> ~2 days on an 8-core box (-w 6). Resumable: skips +# already-logged pairs, so a killed run can be re-launched. Scale --workers with cores (~cores-2). +# Run: uv run codeclash ladder make configs/ladder/make_robocode.yaml --workers 6 +tournament: + rounds: 0 +game: + name: RoboCode + sims_per_round: 300 + sim_concurrency: 5 + # Ranking only needs per-battle scores (results_*.txt), not replays. Recording every sim writes + # ~8.7MB of compressed replay XML per pair (~59GB over 6670 pairs) and pins a gzip core on every + # log copy, so disable it here. + record_ratio: 0 + args: + nodisplay: true + nosound: true +players: +- agent: dummy + branch_init: human/kinnla/antiwalls +- agent: dummy + branch_init: human/pez/aristocles +- agent: dummy + branch_init: human/vftheodoro/barbiescript +- agent: dummy + branch_init: human/johan_adriaans/berendbotje +- agent: dummy + branch_init: human/pez/blackwidow +- agent: dummy + branch_init: human/pez/blackwidow_mini +- agent: dummy + branch_init: human/winstliu/bobthebuilder +- agent: dummy + branch_init: human/lucasgch/bt7274 +- agent: dummy + branch_init: human/namnguyenthanhwork/cham +- agent: dummy + branch_init: human/looklazy/chilibot +- agent: dummy + branch_init: human/pez/chironex_micro +- agent: dummy + branch_init: human/pez/chironex_mini +- agent: dummy + branch_init: human/robo_code/corners +- agent: dummy + branch_init: human/txeverson/crawler +- agent: dummy + branch_init: human/robo_code/crazy +- agent: dummy + branch_init: human/philipmjohnson/dacruzer +- agent: dummy + branch_init: human/trex22/deepthought +- agent: dummy + branch_init: human/pseminatore/dodgebot_jnk +- agent: dummy + branch_init: human/logancsc/dodgebot2 +- agent: dummy + branch_init: human/vikdov/dominatorx +- agent: dummy + branch_init: human/pez/droidpoet +- agent: dummy + branch_init: human/admiralrasmussen/drussgt +- agent: dummy + branch_init: human/andrekorol/exterminador +- agent: dummy + branch_init: human/robo_code/fire +- agent: dummy + branch_init: human/pez/frankie +- agent: dummy + branch_init: human/linuxuser0/genetic +- agent: dummy + branch_init: human/pez/gf1 +- agent: dummy + branch_init: human/josephjeon/gntest +- agent: dummy + branch_init: human/pez/gouldingi +- agent: dummy + branch_init: human/kylebennett/gruffalo +- agent: dummy + branch_init: human/pez/haikupoet +- agent: dummy + branch_init: human/pez/haikuwalls +- agent: dummy + branch_init: human/admiralrasmussen/hawkonfire +- agent: dummy + branch_init: human/zhiwei121/hero_pm +- agent: dummy + branch_init: human/kylebennett/hugbot +- agent: dummy + branch_init: human/mcd8604/hunter +- agent: dummy + branch_init: human/pez/hypoleach +- agent: dummy + branch_init: human/alpian/ianstank +- agent: dummy + branch_init: human/pez/icarus +- agent: dummy + branch_init: human/wouterjoosse/infinitylock +- agent: dummy + branch_init: human/it_economics/ite_bomax +- agent: dummy + branch_init: human/it_economics/ite_claptrap +- agent: dummy + branch_init: human/it_economics/ite_cliffbot2 +- agent: dummy + branch_init: human/it_economics/ite_ctbot +- agent: dummy + branch_init: human/it_economics/ite_florian2 +- agent: dummy + branch_init: human/it_economics/ite_m9 +- agent: dummy + branch_init: human/it_economics/ite_simple +- agent: dummy + branch_init: human/it_economics/ite_terminator +- agent: dummy + branch_init: human/joaomcarvalho/jeujdapeu +- agent: dummy + branch_init: human/dankraemer/juggernaut +- agent: dummy + branch_init: human/u_0x65_e/kokomo +- agent: dummy + branch_init: human/pez/leach +- agent: dummy + branch_init: human/pez/leachpmc +- agent: dummy + branch_init: human/pez/littlebrother +- agent: dummy + branch_init: human/pez/littleevilbrother +- agent: dummy + branch_init: human/pez/mako +- agent: dummy + branch_init: human/tibola/markiv +- agent: dummy + branch_init: human/zcjerry229/markrobo +- agent: dummy + branch_init: human/pez/marshmallow +- agent: dummy + branch_init: human/mgalushka/maximbot +- agent: dummy + branch_init: human/gjgomez/mb2 +- agent: dummy + branch_init: human/denssle/megaborsten +- agent: dummy + branch_init: human/team488/meow +- agent: dummy + branch_init: human/andrekorol/myfirstkiller +- agent: dummy + branch_init: human/robo_code/myfirstrobot +- agent: dummy + branch_init: human/luke_f_w/nagisphere +- agent: dummy + branch_init: human/andr3eee1/npcomplete +- agent: dummy + branch_init: human/iagomonteiro13579/npcsniper +- agent: dummy + branch_init: human/andrekorol/oppswantmedead +- agent: dummy + branch_init: human/pez/paolo +- agent: dummy + branch_init: human/kcanida/pikachu +- agent: dummy + branch_init: human/pez/poet +- agent: dummy + branch_init: human/pmontp19/propiavancat +- agent: dummy + branch_init: human/pez/pugilist +- agent: dummy + branch_init: human/gabriel_lw/quadwall +- agent: dummy + branch_init: human/robo_code/ramfire +- agent: dummy + branch_init: human/robo_code/regullarmonk +- agent: dummy + branch_init: human/g_otn/reimu +- agent: dummy + branch_init: human/sacdalance/robrrrat +- agent: dummy + branch_init: human/miradoconsulting/roleksii +- agent: dummy + branch_init: human/avsthiago/sadbot +- agent: dummy + branch_init: human/alexbay218/shreker +- agent: dummy + branch_init: human/robo_code/sittingduck +- agent: dummy + branch_init: human/pez/smallpoet +- agent: dummy + branch_init: human/robo_code/spinbot +- agent: dummy + branch_init: human/jonharder/starterbot +- agent: dummy + branch_init: human/mgalushka/supercorners +- agent: dummy + branch_init: human/mgalushka/supercrazy +- agent: dummy + branch_init: human/mgalushka/supermercutio +- agent: dummy + branch_init: human/mgalushka/superramfire +- agent: dummy + branch_init: human/mgalushka/superspinbot +- agent: dummy + branch_init: human/mgalushka/supertracker +- agent: dummy + branch_init: human/mgalushka/superwalls +- agent: dummy + branch_init: human/pez/swiffer +- agent: dummy + branch_init: human/tannerrogalsky/tannerbot1 +- agent: dummy + branch_init: human/alpian/tarektank +- agent: dummy + branch_init: human/technischeinformatica/tearsofsteel +- agent: dummy + branch_init: human/pranav_prakash/thecarver +- agent: dummy + branch_init: human/barriosnahuel/tirolio +- agent: dummy + branch_init: human/pez/tityus +- agent: dummy + branch_init: human/robo_code/tracker +- agent: dummy + branch_init: human/robo_code/trackfire +- agent: dummy + branch_init: human/muzardo/trianglehunter +- agent: dummy + branch_init: human/rafaeljdesa/ultron +- agent: dummy + branch_init: human/ur4n0_235/ur4no +- agent: dummy + branch_init: human/robo_code/velocirobot +- agent: dummy + branch_init: human/john_paul_r/vergere +- agent: dummy + branch_init: human/pez/vertileach +- agent: dummy + branch_init: human/pez/vertimicro +- agent: dummy + branch_init: human/robo_code/walls +- agent: dummy + branch_init: human/pez/wallspoet +- agent: dummy + branch_init: human/pez/wallspoetas +- agent: dummy + branch_init: human/pez/wallspoethaiku +- agent: dummy + branch_init: human/admiralrasmussen/wavesurfing +- agent: dummy + branch_init: human/alexjamesmacpherson/wilde +- agent: dummy + branch_init: human/joaocarpim/wrecker +prompts: + game_description: RoboCode ladder