import robocode.control.*; import robocode.control.events.*; import robocode.control.snapshot.*; import java.io.*; import java.util.*; /** * Headless classic-Robocode battle runner that dumps per-turn robot state to JSONL. * * Usage: Capture * * The robot whose name matches enemyNamePattern is written as e* (the movement we want), * the other as s* (the shooter / bearing reference). * * Heading conversion (classic Robocode -> Tank Royale): * classic heading: 0 = North (+y), positive = clockwise * tank royale heading: 0 = East (+x), positive = counter-clockwise * => headingTank = (90 - headingClassic) mod 360 * Positions are identical (both origin bottom-left, x right, y up). */ public class Capture { public static class Row { int tick; // global, continuous across rounds double ex, ey, eh, es, ee; double sx, sy, sh, ss, se; } static List rows = new ArrayList<>(); static Map idxToName = new HashMap<>(); static int enemyIdx = -1, shooterIdx = -1; static int globalTick = 0; static Map roundTicks = new LinkedHashMap<>(); static List errors = new ArrayList<>(); static double tankHeading(double classicRad) { // IRobotSnapshot.getBodyHeading() returns RADIANS in the classic Robocode // convention (0 = north, positive = clockwise). double classicDeg = Math.toDegrees(classicRad); double t = (90.0 - classicDeg) % 360.0; if (t < 0) t += 360.0; return t; } static String f(double v) { return String.format(Locale.ROOT, "%.4f", v); } static boolean printedIndexMap = false; public static void main(String[] args) throws Exception { System.setProperty("java.awt.headless", "true"); if (args.length < 6) { System.err.println("usage: Capture