feat(tools): the real DrussGT now plays and wins Tank Royale battles
The unmodified DrussGT.jar connects, wave-surfs, fires and beats every adversary we have. 5 rounds each, all rounds won: SpinBot 542-16, Corners 823-4, Crazy 604-0, RamFire 900-0, ModularBot 506-72. It is genuinely surfing, not drifting or stalling. Movement statistics against the classic captures, same metrics, same analyzer: opp perp TR/classic reversing TR/cl median range TR/cl SpinBot 0.967 / 0.962 0.466 / 0.464 462 / 402 Corners 0.894 / 0.920 0.462 / 0.419 520 / 504 Crazy 0.841 / 0.829 0.527 / 0.439 370 / 378 RamFire 0.762 / 0.651 0.533 / 0.417 326 / 283 ModularBot 0.956 / - 0.466 / - 453 / - Every round starts moving within 3-11 ticks and runs at 75-82% full speed. Implemented: the classic remaining-quantity motion model (delegated to the TR Bot's own Nat-Pavasant model - identical constants: accel 1, decel -2, max 8, body turn 10-0.75|v|, gun 20, radar 45 - so getDistanceRemaining and getTurnRemaining are exactly self-consistent with what is emulated); event synthesis with classic ordering; bullet identity via object identity; gun heat; rounds; radar cadence; firing translation; and the ThreadManager landmine is killed by installing a no-op IThreadManagerBase in ContainerBase.instance (verified: without it 'RobotException: ThreadManager cannot be null!' kills the bot thread; with it the write succeeds). Also adds TrBattleCapture, an observer that dumps per-tick state in the SAME JSONL fixture format as the classic capture, so legacy bots can be captured from Tank Royale battles too. HONEST DIVERGENCES (README section 5.9): the TR server moves along the PRE-turn heading and then turns, while classic aligns displacement with the POST-turn heading, so the analyzer's conversion error is ~1.5 deg rather than 0.000 deg; distanceRemaining decrements by target speed rather than actual distance; collision clamping differs; BulletMissedEvent can fire less often because age-expiry has no TR event; bulletId is a local temp id; StatusEvent/onPaint/SkippedTurnEvent are never delivered. Physics fidelity diverges by construction - expect to retune. EnergyDomeWorker (the bullet shield) is off by default: its precise bullet-detection warm-up makes round 1 up to 79% stationary vs 35% in classic. Rounds 2+ match classic closely with it on, but the pure surfer is the consistent path. DRUSSGT_SHIELD=1 re-enables it. Jars remain out of git.
This commit is contained in:
+210
-32
@@ -1,4 +1,4 @@
|
||||
# Robocode shim spike — running the real DrussGT as a Tank Royale bot
|
||||
# Robocode shim — running the real DrussGT as a Tank Royale bot
|
||||
|
||||
**Question:** can the *unmodified* legacy DrussGT jar be driven from a shim, and
|
||||
which is cheaper — (A) re-implement `robocode.*` or (B) reuse the genuine
|
||||
@@ -10,8 +10,14 @@ delegates to a `peer` interface, and that seam is public. DrussGT compiles with
|
||||
its own event handlers and emits 200 ticks of movement intents + 169 fire
|
||||
requests through our peer.
|
||||
|
||||
This is an **API-coverage / architecture spike**, not a working bot. No physics
|
||||
is implemented; the peer's world model is stubbed.
|
||||
This was an **API-coverage / architecture spike** and is now a **working
|
||||
bridge**: the real, unmodified DrussGT jar connects to a Tank Royale server,
|
||||
plays real battles, wave-surfs and fires. The physics/engine semantics are
|
||||
supplied by the shim (`ClassicPeer` + `DrussGTBridge`) and documented in §5;
|
||||
the measured movement statistics against classic-Robocode captures are in §5.8.
|
||||
|
||||
> **Status:** COMPLETE (Java-only). See §5 for what was implemented, §5.8 for the
|
||||
> verification evidence, and §5.9 for the honest list of physics divergences.
|
||||
|
||||
---
|
||||
|
||||
@@ -330,30 +336,190 @@ class jk.mega.dMove.Scan implements java.lang.Cloneable {
|
||||
|
||||
---
|
||||
|
||||
## 5. Remaining work to go from "compiles" to "runs a battle"
|
||||
## 5. The bridge is implemented (Java-only, working)
|
||||
|
||||
Everything below is now the *inverse* problem: the API is complete, but the
|
||||
**engine semantics** behind it are not implemented.
|
||||
The five remaining-work items are done. The bridge is `DrussGTBridge` (a Tank
|
||||
Royale `Bot`) + `ClassicPeer` (the genuine-jar peer) + `BotHost` (child
|
||||
classloader) + `ThreadManagerFix`.
|
||||
|
||||
| # | Item | Status | Notes |
|
||||
| # | Item | Status | What was done |
|
||||
|---|---|---|---|
|
||||
| 1 | Coordinate rotation at the boundary | **[MEASURED]** | Pure function; conversion `trRad = PI/2 - classicRad` already validated to 0.000–0.001° against recorded DrussGT motion (`tools/fixtures/DRUSSGT_FIXTURES.md`). Implemented in `TankRoyaleBridge`. Cheap. |
|
||||
| 2 | Async tick ↔ synchronous `execute()` bridge | **[MEASURED]** | Implemented in `ClassicPeer.provideTurn/awaitExecutedTurns`; proven by the 200-tick smoke run. Real integration still needs a Tank Royale Java websocket/JSON client to *produce* those ticks. |
|
||||
| 3 | `RobocodeFileOutputStream` engine dependency | **[MEASURED]** | `javap -c` shows it resolves `IThreadManagerBase` via `ContainerBase`. Outside the engine it throws `RobotException` and kills the bot thread. Reached only from `DrussGT.contain()`. Fix: register a no-op `IThreadManagerBase` in `ContainerBase`, or replace `contain`'s writer (can't — bot is unmodified), or accept that any bot exception is fatal. This bit us in testing. |
|
||||
| 4 | Classic motion model (`setAhead` distance vs TR speed) | **[MEASURED] + [ESTIMATE]** | DrussGT calls `getDistanceRemaining()` (ours) and `setAhead(d)`; Tank Royale wants a *target speed* + *turn rate*. The bridge must integrate a classic motion model (`ACCELERATION=1`, `DECELERATION=2`, `MAX_VELOCITY=8`, turn rate `10-0.75·|v|`) in front of TR, or approximate. DrussGT *also* has its own `MovePredictor` using classic accel/decel, so divergence is baked in regardless. [ESTIMATE: 1–3 days] |
|
||||
| 5 | Event synthesis & order | **[MEASURED]** | All classic event constructors are public and confirmed by javap. `ClassicPeer.dispatch` already routes ScannedRobot/HitByBullet/BulletHit/BulletHitBullet/BulletMissed/HitRobot/HitWall/RobotDeath/Win/Death/Status/SkippedTurn/Custom. Still to do: emit them from TR events and honour classic priority ordering. |
|
||||
| 6 | `getGunHeat()` / gun cooling | **[MEASURED]** | `DrussMoveGT` tracks enemy gun heat itself from `getGunCoolingRate()` (classic value 0.1). `ClassicPeer` returns a configurable value; the bridge must model *our* heat with the same decrement so `getGunHeat`/`getGunTurnRemaining` are consistent. |
|
||||
| 7 | `Bullet` identity / own-bullet tracking | **[ESTIMATE]** | DrussGT keeps `Bullet` objects from `setFireBullet` and matches them in `onBulletHit`/`HitByBulletEvent.getBullet()` (uses `equals`). The bridge must map TR bullet ids to stable classic `Bullet` instances. |
|
||||
| 8 | Firing translation | **[ESTIMATE]** | `setFire(power)`/`setFireBullet` → TR fire command; `setFireBullet` must return a `Bullet` synchronously. |
|
||||
| 9 | Rounds / counts | **[ESTIMATE]** | `getRoundNum`, `getNumRounds`, `getOthers`, `getNumSentries` map to TR round info; `DrussMoveGT` gates flattener learning on `getRoundNum() > 1 / > 4 / < 15`, so these must be real, not constants. |
|
||||
| 10 | Radar / scan cadence | **[ESTIMATE]** | Classic `ScannedRobotEvent` cadence is a swept radar; TR provides its own scan events. Must be synthesised with correct `bearing`/`distance` so `DrussMoveGT.onScannedRobot` sees true geometry. |
|
||||
| 11 | `onPaint` / AWT | **[MEASURED]** | `ClassicPeer.getGraphics()` returns `null`; DrussGT's `onPaint(Graphics2D)` (157 lines, debug only) can be skipped. `setColors`/`Color` are accepted and ignored. |
|
||||
| 12 | `getAllEvents()` on death | **[ESTIMATE]** | `DrussGT.contain`/`onDeath` replays events; peer already returns the turn's accumulated events. |
|
||||
| 13 | Class-loading topology | **[MEASURED]** | Must load DrussGT with a child `URLClassLoader` whose parent holds `robocode.jar`, so `IBasicRobot` is the same class. Implemented in `BotHost`. |
|
||||
| 14 | Physics fidelity | **[ESTIMATE]** | Even with a perfect bridge, TR's `maxTurn = 10 - 0.75·|speed|`, ±1 ramp and bullet model differ from classic. Exact trajectory match is impossible; aim for "same decisions, diverging trajectories". |
|
||||
| 1 | Coordinate rotation | **DONE** | Every TR angle is converted on read (`tankRadToClassicRad`) and every classic intent on write (`toDegrees` of the classic signed value). See `TankRoyaleBridge`. |
|
||||
| 2 | `RobocodeFileOutputStream` / ThreadManager | **DONE** | `ThreadManagerFix.install()` registers a no-op `IThreadManagerBase` in `ContainerBase.instance`, so `DrussGT.contain()` writes a normal file instead of throwing `RobotException: ThreadManager cannot be null!` and killing the thread. Proven by `ThreadManagerFixTest`. |
|
||||
| 3 | Classic motion model | **DONE** | The peer's captured `setAhead`/`setTurn*` are forwarded to the TR `Bot`'s own classic motion model (`setForward`/`setTurnRight`/`setTurnGunRight`/`setTurnRadarRight`), which is Nat Pavasant's optimal-velocity model using the same constants (`ACCELERATION=1`, `DECELERATION=-2`, `MAX_SPEED=8`, body turn `10-0.75·|v|`, gun `20`, radar `45`). `getDistanceRemaining()`/`getTurnRemaining()` delegate to the same model, so they are exactly consistent with what is emulated. |
|
||||
| 4 | Event synthesis & ordering | **DONE** | TR events are mapped to classic events and delivered synchronously; TR's event queue priorities are the classic priorities, so ordering matches. `ScannedRobotEvent`, `HitByBulletEvent`, `BulletHitEvent`, `BulletHitBulletEvent`, `BulletMissedEvent`, `HitRobotEvent`, `HitWallEvent`, `RobotDeathEvent`, `WinEvent`, `DeathEvent`. `SkippedTurnEvent` is deliberately never delivered. |
|
||||
| 5 | Physics / state / bullets / rounds / radar | **DONE** | Energy, position, headings, speed, gun heat and cooling rate are read live from the TR bot; `getRoundNum()=roundNumber-1`, `getNumRounds`, `getOthers`, `getTime()=turnNumber`. Bullet identity is tracked: the `Bullet` returned by `setFireBullet` is the *same instance* later handed back in `BulletHit*` events, so DrussGT's `Bullet.equals` (which compares class + `bulletId`) and identity checks both work. Radar/gun adjust flags are forwarded. |
|
||||
|
||||
### 5.1 How the tick contract works
|
||||
|
||||
DrussGT's own `run()` is executed **on the Tank Royale bot thread** (this is
|
||||
exactly where the official `robocode-api-bridge` runs a legacy robot). Its
|
||||
`execute()` calls back into `ClassicPeer.TickHost.onExecute()`, which:
|
||||
|
||||
1. applies the captured intents (`setAhead` → `setForward`, …) to the TR bot,
|
||||
2. calls the TR `Bot.go()`.
|
||||
|
||||
`go()` sends the intent, waits for the next tick and then dispatches that tick's
|
||||
events. Our `DrussGTBridge` overrides the TR event handlers and forwards each
|
||||
one to the classic listeners via `ClassicPeer.deliver`. Because the TR `Bot`
|
||||
model dispatches the *new* turn's events before `run()`'s next iteration, the
|
||||
classic contract "events for turn N are delivered before the turn-N run() body"
|
||||
holds, as does the classic "new robot instance per round, static state survives"
|
||||
lifetime (a fresh DrussGT is instantiated each round).
|
||||
|
||||
### 5.2 Classic motion model mapping (exact)
|
||||
|
||||
| classic (peer) | Tank Royale |
|
||||
|---|---|
|
||||
| `setAhead(d)` / `setMove(d)` | `setForward(d)` |
|
||||
| `setTurnRightRadians(r)` | `setTurnRight(toDegrees(r))` |
|
||||
| `setTurnGunRightRadians(r)` | `setTurnGunRight(toDegrees(r))` |
|
||||
| `setTurnRadarRightRadians(r)` | `setTurnRadarRight(toDegrees(r))` |
|
||||
| `setMaxVelocity(v)` / `setMaxTurnRate(r)` | `setMaxSpeed(v)` / `setMaxTurnRate(r)` |
|
||||
| `setAdjustGunForRobotTurn` | `setAdjustGunForBodyTurn` |
|
||||
| `setAdjustRadarForRobotTurn` / `setAdjustRadarForGunTurn` | `setAdjustRadarForBodyTurn` / `setAdjustRadarForGunTurn` |
|
||||
| `setFireBullet(p)` | `setFire(p)` + create/return a `robocode.Bullet` |
|
||||
| `execute()` | `go()` |
|
||||
| `getDistanceRemaining()` | `getDistanceRemaining()` |
|
||||
| `getTurnRemaining()` / gun / radar | `-toRadians(getTurnRemaining())` … (TR positive = left) |
|
||||
|
||||
A command is only forwarded when DrussGT actually issued it that turn (dirty
|
||||
flags), because classic remaining-quantities persist until overwritten.
|
||||
|
||||
### 5.3 Bullet identity
|
||||
|
||||
At `setFireBullet(p)` the bridge calls the TR `setFire(p)`; if accepted it
|
||||
creates a plain `robocode.Bullet` (never a subclass — `Bullet.equals` compares
|
||||
`getClass()`), stores it in `unmatchedFired`, and returns it. When the TR
|
||||
`BulletFiredEvent` arrives the nearest unmatched bullet is bound to the TR
|
||||
`bulletId`. Later `BulletHitBotEvent` / `BulletHitBulletEvent` /
|
||||
`BulletHitWallEvent` look the id up and pass **the same instance** to DrussGT, so
|
||||
`e.getBullet().equals(w.bullet)` in `DrussGunDC.onBulletHitBullet` is true.
|
||||
Position/`isActive` are updated by reflection (best effort).
|
||||
|
||||
### 5.4 Shield (EnergyDome) handling
|
||||
|
||||
DrussGT's `EnergyDomeWorker` ("shield") is a separate *precise* subsystem that
|
||||
detects enemy bullets from per-scan energy drops. Its first-round warm-up is
|
||||
sensitive to exact classic timing. The proven path (also used by `SmokeTest`) is
|
||||
to run the **pure wave surfer** (`DrussMoveGT`): the bridge sets
|
||||
`DrussGT.shieldEnabled = false` via `BotHost.disableShield()` unless
|
||||
`DRUSSGT_SHIELD=1`. This is the configuration the statistics in §5.8 use.
|
||||
|
||||
### 5.5 Event mapping details / gotchas honoured
|
||||
|
||||
* `ScannedRobotEvent(name, energy, bearing, distance, heading, velocity)` — the
|
||||
documented, non-intuitive argument order; `bearing` is the classic body-relative
|
||||
bearing and `heading` the enemy's classic absolute heading.
|
||||
* `BulletHitWallEvent` (TR) → `BulletMissedEvent` (classic).
|
||||
* `BotDeathEvent` → `RobotDeathEvent`; `WonRoundEvent` → `WinEvent`; TR
|
||||
`DeathEvent` → classic `DeathEvent`.
|
||||
* `HitWallEvent` bearing is computed from the nearest wall normal.
|
||||
* `onPaint`/AWT, `StatusEvent`, `SkippedTurnEvent`, `onCustomEvent` are not
|
||||
delivered (DrussGT does not use them; `getGraphics()` returns `null`).
|
||||
|
||||
### 5.6 Class-loading topology
|
||||
|
||||
`BotHost` loads `jk.mega.DrussGT` in a child `URLClassLoader` whose parent is the
|
||||
shim's loader (which holds the genuine `robocode.jar`), so `IBasicRobot` is the
|
||||
same type the peer implements. One DrussGT class is loaded per JVM, so the static
|
||||
KD-trees persist across rounds exactly like classic.
|
||||
|
||||
### 5.7 How to run it
|
||||
|
||||
```bash
|
||||
export ROBOCODE_JAR=/tmp/robocode/install/libs/robocode.jar
|
||||
export TR_BOT_API_JAR=$HOME/Downloads/sample-bots-java-1.0.2/lib/robocode-tankroyale-bot-api-1.0.2.jar
|
||||
export DRUSSGT_JAR=/tmp/drussgt/DrussGT.jar
|
||||
./build.sh
|
||||
./run_smoke.sh # standalone 200-tick proof
|
||||
java -cp "out:$ROBOCODE_JAR" robocode_shim.ThreadManagerFixTest # item 3 proof
|
||||
|
||||
# real battle + movement fixture (embedded server, boots the bot dir):
|
||||
./run_bridge_battle.sh /home/davide/Projects/tank-royale/sample-bots/java/build/archive/SpinBot 5
|
||||
```
|
||||
|
||||
`make_botdir.sh [DIR]` generates the Tank Royale bot directory (a `<DIR>.json`
|
||||
identity file and a `<DIR>.sh` launcher that runs `robocode_shim.DrussGTBridge`).
|
||||
`TrBattleCapture` is the observer: it runs the battle through the Tank Royale
|
||||
battle-runner API and dumps every bot's per-turn state in the *same* JSONL
|
||||
fixture format as `tools/robocode_fixture_capture/Capture.java`, so
|
||||
`analyze.py` runs on both unchanged.
|
||||
|
||||
### 5.8 Verification — it is really DrussGT, not a stub
|
||||
|
||||
All runs: embedded Tank Royale server, `maxSpeed`, shield disabled (pure surfer),
|
||||
5 rounds each, against the same sample bots whose classic captures are in
|
||||
`tools/fixtures/`. Stats computed by `tools/robocode_fixture_capture/analyze.py`
|
||||
on the TR capture (5 rounds) and the 20-round classic fixture.
|
||||
|
||||
**Battle outcomes** (DrussGT first, total score over 5 rounds):
|
||||
|
||||
| opponent | DrussGT | opponent | rounds won | bullets fired / hits / misses |
|
||||
|---|---:|---:|---:|---:|
|
||||
| SpinBot | **542** | 16 | 5/5 | 327 / 39 / 277 |
|
||||
| Corners | **823** | 4 | 5/5 | 79 / 36 / 31 |
|
||||
| Crazy | **604** | 0 | 5/5 | 332 / 45 / 274 |
|
||||
| RamFire | **900** | 0 | 5/5 | 54 / 38 / 12 |
|
||||
| ModularBot (Nim, real) | **506** | 72 | 5/5 | 491 / 56 / 418 (+5 bullet-bullet; took 18 hits) |
|
||||
|
||||
**Movement statistics** (TR vs the matching classic capture):
|
||||
|
||||
| opponent | metric | TR (bridge) | classic fixture |
|
||||
|---|---|---:|---:|
|
||||
| SpinBot | perp frac / radial frac | **0.967 / 0.000** | 0.962 / 0.001 |
|
||||
| | full speed ≥7.5 / rest <0.5 / reversing | 0.781 / 0.017 / 0.466 | 0.701 / 0.067 / 0.464 |
|
||||
| | median range (px) | 462 | 402 |
|
||||
| Corners | perp / radial | **0.894 / 0.002** | 0.920 / 0.004 |
|
||||
| | full / rest / reversing | 0.754 / 0.028 / 0.462 | 0.586 / 0.092 / 0.419 |
|
||||
| | median range | 520 | 504 |
|
||||
| Crazy | perp / radial | **0.841 / 0.003** | 0.829 / 0.010 |
|
||||
| | full / rest / reversing | 0.811 / 0.017 / 0.527 | 0.668 / 0.137 / 0.439 |
|
||||
| | median range | 370 | 378 |
|
||||
| RamFire | perp / radial | **0.762 / 0.002** | 0.651 / 0.013 |
|
||||
| | full / rest / reversing | 0.747 / 0.043 / 0.533 | 0.723 / 0.046 / 0.417 |
|
||||
| | median range | 326 | 283 |
|
||||
| ModularBot | perp / radial | **0.956 / 0.000** | — |
|
||||
|
||||
The perpendicular-to-opponent fraction, the near-zero radial fraction and the
|
||||
~42–53% reversal rate are the signature of DrussGT's wave surfer and match the
|
||||
classic captures closely. The TR run is slightly faster / shorter-ranged because
|
||||
the shield is off and the rounds are shorter (5 vs 20). Per-round, every round
|
||||
now starts moving within 3–11 ticks and runs at 75–82% full speed. **This is not
|
||||
a straight line, not a standstill, and not a crash.**
|
||||
|
||||
### 5.9 Known physics divergences (honest list)
|
||||
|
||||
1. **Move/turn ordering.** The TR server calls `moveToNewPosition()` using the
|
||||
*pre-turn* heading and only then applies the turn, whereas the classic capture
|
||||
aligns each tick's displacement with the *post-turn* heading
|
||||
(`analyze.py` conversion error 0.000° classic vs ~1.5° TR). Trajectories
|
||||
therefore diverge even with identical intents.
|
||||
2. **Distance bookkeeping.** The TR `Bot` motion model decrements
|
||||
`distanceRemaining` by the *target* speed (Nat Pavasant's over-drive method);
|
||||
classic decrements by the distance actually travelled, and collision/wall
|
||||
clamping differs.
|
||||
3. **No exact trajectory equivalence.** Bullet speeds/damage match
|
||||
(`20-3p`, `4p (+2(p-1) if p>1)`), gun heat matches (`1+p/5`, cool 0.1/turn),
|
||||
turn rates match — but the integration order above means "same decisions,
|
||||
diverging trajectories" is the ceiling.
|
||||
4. **First-round shield warm-up.** With the shield *enabled*
|
||||
(`DRUSSGT_SHIELD=1`) round 1 can be 79% stationary vs 35% in classic, because
|
||||
the shield's precise bullet detection is timing-sensitive. Disabled by
|
||||
default.
|
||||
5. **`BulletMissedEvent`.** TR emits `BulletHitWallEvent` on wall hits; bullets
|
||||
that expire by age may not produce an event, so `onBulletMissed` can fire less
|
||||
often than classic. DrussGT does not use it.
|
||||
6. **`bulletId`.** The classic `Bullet`'s `bulletId` is a local temporary id, not
|
||||
the TR server id; identity is preserved by object identity, not by id.
|
||||
7. **`onPaint`/AWT, `StatusEvent`, `SkippedTurnEvent`, custom events** are not
|
||||
delivered. DrussGT does not rely on them (`onPaint` is debug-only).
|
||||
8. **Tick phase.** TR `getTurnNumber()` is 1-based like classic `getTime()`, but
|
||||
the observer snapshot phase differs by the move/turn ordering above; per-tick
|
||||
state read by the bot is always the current turn's.
|
||||
|
||||
There are **no remaining API unknowns**: the compiler resolved everything, and
|
||||
the smoke test exercised the full event → decision → intent path.
|
||||
the bridge now runs full battles, surf and fire.
|
||||
|
||||
---
|
||||
|
||||
@@ -362,34 +528,46 @@ the smoke test exercised the full event → decision → intent path.
|
||||
```text
|
||||
tools/robocode_shim/
|
||||
README.md this report
|
||||
build.sh compile the shim (ClassicPeer/BotHost/Bridge/SmokeTest)
|
||||
build.sh compile the shim + capture
|
||||
compile_drussgt.sh ACCEPTANCE TEST: javac the real DrussGT sources
|
||||
run_smoke.sh load + drive the real jar, assert intents
|
||||
run_smoke.sh load + drive the real jar, assert intents (standalone)
|
||||
make_botdir.sh generate a Tank Royale bot dir that boots the bridge
|
||||
run_bridge_battle.sh run a real TR battle + movement statistics
|
||||
.gitignore out/ and *.jar never committed
|
||||
src/robocode_shim/
|
||||
ClassicPeer.java IAdvancedRobotPeer impl + execute() tick bridge
|
||||
BotHost.java URLClassLoader + setPeer + run() thread
|
||||
TankRoyaleBridge.java angle conversion + documented tick contract (skeleton)
|
||||
SmokeTest.java the runtime proof
|
||||
ClassicPeer.java IAdvancedRobotPeer impl + world/tick seams
|
||||
BotHost.java URLClassLoader + setPeer + per-round instances
|
||||
TankRoyaleBridge.java exact angle conversion
|
||||
ThreadManagerFix.java no-op IThreadManagerBase in ContainerBase
|
||||
ThreadManagerFixTest.java proof of the above
|
||||
DrussGTBridge.java the Tank Royale Bot that hosts DrussGT
|
||||
SmokeTest.java the standalone runtime proof
|
||||
TrBattleCapture.java observer: battle -> classic JSONL fixture format
|
||||
out/ build output (gitignored)
|
||||
```
|
||||
|
||||
```bash
|
||||
export ROBOCODE_JAR=/tmp/robocode/install/libs/robocode.jar
|
||||
export TR_BOT_API_JAR=$HOME/Downloads/sample-bots-java-1.0.2/lib/robocode-tankroyale-bot-api-1.0.2.jar
|
||||
export DRUSSGT_JAR=/tmp/drussgt/DrussGT.jar
|
||||
./build.sh
|
||||
./compile_drussgt.sh
|
||||
./run_smoke.sh
|
||||
./run_bridge_battle.sh /home/davide/Projects/tank-royale/sample-bots/java/build/archive/SpinBot 5
|
||||
```
|
||||
|
||||
## 7. Third-party jars
|
||||
|
||||
Per the task constraints, **no third-party jar is copied into the repo.**
|
||||
`robocode.jar` (Robocode 1.9.5.5) stays at
|
||||
`/tmp/robocode/install/libs/robocode.jar` and `DrussGT.jar` at
|
||||
`/tmp/drussgt/DrussGT.jar`; the scripts reference them via `ROBOCODE_JAR` /
|
||||
`DRUSSGT_JAR`. `tools/robocode_shim/.gitignore` additionally blocks `*.jar` and
|
||||
`out/` in case a jar is ever dropped here by mistake.
|
||||
`/tmp/robocode/install/libs/robocode.jar`, `DrussGT.jar` at
|
||||
`/tmp/drussgt/DrussGT.jar`, the Tank Royale Java bot API at
|
||||
`~/Downloads/sample-bots-java-1.0.2/lib/robocode-tankroyale-bot-api-1.0.2.jar`
|
||||
and the Tank Royale battle runner at
|
||||
`/home/davide/Projects/tank-royale/runner/examples/lib/robocode-tankroyale-runner.jar`;
|
||||
the scripts reference them via `ROBOCODE_JAR`, `DRUSSGT_JAR`, `TR_BOT_API_JAR`
|
||||
and `TR_RUNNER_JAR`. `tools/robocode_shim/.gitignore` additionally blocks
|
||||
`*.jar` and `out/` in case a jar is ever dropped here by mistake.
|
||||
|
||||
## 8. Gotchas discovered (for whoever wires the bridge)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user