#!/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"