4f18c8ce07
There are no genuinely competitive adversaries for Tank Royale, and the in-repo ones were broken until recently. Classic Robocode 1.9.5.5 is obtainable (SourceForge, 20.4 MB) and its programmatic control API (robocode.control.RobocodeEngine + BattleAdaptor.onTurnEnded) can run real battles headless and expose per-turn robot state. So a legacy leader bot's MOVEMENT can be captured and used as a gun-testing fixture with no port. Captured unmodified DrussGT 3.1.4159 vs spinbot/ramfire/crazy/corners and a mirror match: 28,797 ticks, plus two trivial-bot contrasts. Conversion to the Tank Royale convention is validated to 0.000-0.001 deg by recomputing the direction implied by (heading, speed) and comparing it against the recorded per-tick displacement -- i.e. the data is proven to be genuine recorded motion rather than a mangled export. (A first attempt treated the snapshot API's headings as degrees; they are radians, ~95 deg off.) The statistics confirm it is really a wave surfer: perpendicular to the opponent 65-96% of ticks, radial ~0.001, 41-72% of ticks at full speed, reversing on 42-46% of ticks, holding range at a 283-526 px median. The straight-line contrast is radial-dominant (0.75) with ZERO reversals. Discovery: DrussGT detects predictable guns and switches to a bullet-shield stand-still mode, so captures against sample.Walls/TrackFire had to be rejected as non-movement. CAVEATS, recorded in DRUSSGT_FIXTURES.md: these are open-loop (replayed DrussGT never dodges OUR bullets) and perfect-information (the observer gives true positions every tick, unlike our stale live WorldState). Both make our guns look better than in live play, so use them for RELATIVE gun ranking, not absolute hit rates. Jars stay out of git; capture tooling is reproducible via capture.sh.
94 lines
5.2 KiB
Bash
Executable File
94 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Reproduce the classic-Robocode DrussGT movement fixtures in tools/fixtures/.
|
|
#
|
|
# This script downloads classic Robocode 1.9.5.5 and the third-party DrussGT jar
|
|
# into /tmp (NOT into the repository), runs headless battles with the Capture
|
|
# observer, and writes JSONL fixtures + round-boundary sidecars.
|
|
#
|
|
# Requirements: bash, curl, unzip, javac/java (Java 11+; tested on Java 21 with
|
|
# -Djava.security.manager=allow and --add-opens flags below).
|
|
#
|
|
# Usage: tools/robocode_fixture_capture/capture.sh [output_dir]
|
|
# (default output_dir = tools/fixtures)
|
|
#
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO="$(cd "$HERE/../.." && pwd)"
|
|
OUT="${1:-$REPO/tools/fixtures}"
|
|
WORK=/tmp/robocode
|
|
INSTALL="$WORK/install"
|
|
|
|
ROBOCODE_VER=1.9.5.5
|
|
ROBOCODE_SETUP_URL="https://sourceforge.net/projects/robocode/files/robocode/$ROBOCODE_VER/robocode-$ROBOCODE_VER-setup.jar/download"
|
|
DRUSSGT_URL="http://robocode-archive.strangeautomata.com/robots/jk.mega.DrussGT_3.1.4159.jar"
|
|
|
|
mkdir -p "$WORK/dl" "$WORK/work" "$OUT"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Classic Robocode (installer jar is a plain zip with the full install)
|
|
# ---------------------------------------------------------------------------
|
|
if [ ! -d "$INSTALL/libs" ]; then
|
|
echo "[capture] downloading classic Robocode $ROBOCODE_VER from SourceForge"
|
|
curl -sSL -o "$WORK/dl/robocode-$ROBOCODE_VER-setup.jar" "$ROBOCODE_SETUP_URL"
|
|
unzip -q -o "$WORK/dl/robocode-$ROBOCODE_VER-setup.jar" -d "$INSTALL"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. DrussGT (third-party, keep OUT of git)
|
|
# ---------------------------------------------------------------------------
|
|
if [ ! -f "$WORK/dl/DrussGT.jar" ]; then
|
|
echo "[capture] downloading DrussGT 3.1.4159"
|
|
curl -sSL -o "$WORK/dl/DrussGT.jar" "$DRUSSGT_URL"
|
|
fi
|
|
cp -f "$WORK/dl/DrussGT.jar" "$INSTALL/robots/jk.mega.DrussGT_3.1.4159.jar"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Trivial contrast bot, packaged as a jar so the repository indexes it
|
|
# ---------------------------------------------------------------------------
|
|
rm -rf "$WORK/work/trivialjar"
|
|
mkdir -p "$WORK/work/trivialjar/trivial"
|
|
javac -cp "$INSTALL/libs/robocode.jar" -d "$WORK/work/trivialjar" "$HERE/StraightLine.java"
|
|
cp "$HERE/StraightLine.properties" "$WORK/work/trivialjar/trivial/StraightLine.properties"
|
|
printf 'Manifest-Version: 1.0\nrobots: trivial.StraightLine\n\n' > "$WORK/work/trivialjar/MANIFEST.MF"
|
|
( cd "$WORK/work/trivialjar" && jar cfm "$INSTALL/robots/trivial.StraightLine.jar" \
|
|
MANIFEST.MF trivial/StraightLine.class trivial/StraightLine.properties )
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Capture program
|
|
# ---------------------------------------------------------------------------
|
|
javac -cp "$INSTALL/libs/*" -d "$WORK/work" "$HERE/Capture.java"
|
|
rm -f "$INSTALL/robots/robot.database" # force repository re-scan
|
|
|
|
run_capture() { # enemy shooter rounds out label note
|
|
echo "[capture] $1 vs $2 ($3 rounds) -> $4"
|
|
( cd "$INSTALL" && java -Djava.security.manager=allow \
|
|
--add-opens=java.base/sun.net.www.protocol.jar=ALL-UNNAMED \
|
|
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
|
|
--add-opens=java.desktop/sun.awt=ALL-UNNAMED \
|
|
-cp "$WORK/work:$INSTALL/libs/*" -Xmx512M \
|
|
Capture "$1" "$2" "$3" "$4" "$5" "$6" ) | grep -E 'rows=|rounds ticks|errors' || true
|
|
}
|
|
|
|
NOTE_D="e*=DrussGT 3.1.4159 (jk.mega.DrussGT) on classic Robocode 1.9.5.5; s*=opponent. tick is global/continuous across all rounds, so positions jump at round boundaries (see drussgt_meta/*.rounds.json sidecar). es/ss are SIGNED velocity (classic getVelocity, px/tick; negative = reversing). Heading conversion: classic snapshot headings are radians (0=north, clockwise) -> deg=toDegrees(raw); tank=(90-deg) mod 360 (0=east, CCW). Positions x/y are unchanged (same axes). Captured headless via RobocodeEngine TurnEndedEvent (perfect info, no fog)."
|
|
|
|
run_capture jk.mega.DrussGT sample.SpinBot 20 "$OUT/drussgt_vs_spinbot.jsonl" DrussGT "$NOTE_D"
|
|
run_capture jk.mega.DrussGT sample.RamFire 20 "$OUT/drussgt_vs_ramfire.jsonl" DrussGT "$NOTE_D"
|
|
run_capture jk.mega.DrussGT sample.Crazy 20 "$OUT/drussgt_vs_crazy.jsonl" DrussGT "$NOTE_D"
|
|
run_capture jk.mega.DrussGT sample.Corners 20 "$OUT/drussgt_vs_corners.jsonl" DrussGT "$NOTE_D"
|
|
run_capture jk.mega.DrussGT jk.mega.DrussGT 2 "$OUT/drussgt_vs_drussgt.jsonl" DrussGT "$NOTE_D"
|
|
run_capture sample.SittingDuck sample.SittingDuck 1 "$OUT/contrast_stationary_sittingduck.jsonl" SittingDuck \
|
|
"e*=sample.SittingDuck (stationary). s*=sample.SittingDuck. Contrast fixture: zero movement by construction."
|
|
run_capture trivial.StraightLine sample.SittingDuck 1 "$OUT/contrast_straightline.jsonl" StraightLine \
|
|
"e*=trivial.StraightLine (constant-speed straight legs, 180-degree turns at walls). s*=sample.SittingDuck. Contrast fixture."
|
|
|
|
# Move sidecars out of the *.jsonl namespace
|
|
mkdir -p "$OUT/drussgt_meta"
|
|
for f in "$OUT"/*.jsonl.rounds.json; do
|
|
[ -e "$f" ] && mv -f "$f" "$OUT/drussgt_meta/"
|
|
done
|
|
|
|
echo "[capture] done. Validate with:"
|
|
echo " python3 $HERE/analyze.py $OUT/drussgt_vs_*.jsonl $OUT/contrast_*.jsonl"
|