feat(ModularBot): pluggable bot with 4 guns, phantom meteor movement, radar harness
- Gun harness: virtual bullet tracker, rolling fitness, auto-selector - Guns: head-on, linear (extrapolation), circular (integrated formula), tsetlin machine (learning) - Movement: phantom meteor gravity engine (danger histograms, phantom bullets, fire detection) - Radar: harness + radar_lock adapter - Color-coded modules: turret/bullet color per gun, body per movement, scan per radar - Beats Target, SpinBot, Crazy, TrackFire in 10-round battles
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import dev.robocode.tankroyale.runner.*;
|
||||
import dev.robocode.tankroyale.client.model.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* BNNBot validation battle: BNNBot vs Target (1 round, embedded server).
|
||||
*
|
||||
* Env vars:
|
||||
* BNN_BOT_DIR — path to BNNBot directory (must contain BNNBot.json + BNNBot.sh)
|
||||
* SAMPLE_BOTS_DIR — path to sample bots archive
|
||||
* BNNBOT_CSV — forwarded to bot process: "1" enables CSV output
|
||||
* ENEMY_BOT — name of enemy bot subfolder under SAMPLE_BOTS_DIR (default: Target)
|
||||
* NUM_ROUNDS — number of rounds to run (default: 5)
|
||||
*
|
||||
* Usage: java -cp ".:$JAR" RunBNNBattle
|
||||
*/
|
||||
public class RunBNNBattle {
|
||||
|
||||
static final Map<Integer, String> idToName = new ConcurrentHashMap<>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
Logger.getLogger("dev.robocode.tankroyale").setLevel(Level.WARNING);
|
||||
|
||||
String bnnBotDir = requireEnv("BNN_BOT_DIR");
|
||||
String sampleBots = requireEnv("SAMPLE_BOTS_DIR");
|
||||
String enemyBot = System.getenv().getOrDefault("ENEMY_BOT", "Target");
|
||||
int numRounds = Integer.parseInt(System.getenv().getOrDefault("NUM_ROUNDS", "5"));
|
||||
|
||||
System.out.println("Enemy: " + enemyBot + " Rounds: " + numRounds);
|
||||
|
||||
try (var runner = BattleRunner.create(b -> b.embeddedServer().suppressServerOutput())) {
|
||||
var setup = BattleSetup.classic(s -> s.setNumberOfRounds(numRounds));
|
||||
var bots = List.of(
|
||||
BotEntry.of(bnnBotDir),
|
||||
BotEntry.of(sampleBots + "/" + enemyBot)
|
||||
);
|
||||
|
||||
var owner = new Object();
|
||||
try (var handle = runner.startBattleAsync(setup, bots)) {
|
||||
|
||||
handle.getOnGameStarted().on(owner, event -> {
|
||||
System.out.println("=== GAME STARTED ===");
|
||||
for (var p : event.getParticipants()) {
|
||||
idToName.put(p.getId(), p.getName());
|
||||
System.out.printf(" #%d %s%n", p.getId(), p.getName());
|
||||
}
|
||||
System.out.printf("%-6s %-12s %-10s%n", "Turn", "Name", "RadarDir");
|
||||
System.out.println("-".repeat(40));
|
||||
});
|
||||
|
||||
handle.getOnTickEvent().on(owner, event -> {
|
||||
int turn = event.getTurnNumber();
|
||||
for (var state : event.getBotStates())
|
||||
if (state.getName() != null) idToName.putIfAbsent(state.getId(), state.getName());
|
||||
});
|
||||
|
||||
handle.getOnRoundEnded().on(owner, event ->
|
||||
System.out.printf("%n=== ROUND %d ENDED (turn %d) ===%n",
|
||||
event.getRoundNumber(), event.getTurnNumber()));
|
||||
|
||||
var results = handle.awaitResults();
|
||||
System.out.printf("%n=== RESULTS (%d rounds) ===%n", results.getNumberOfRounds());
|
||||
for (var r : results.getResults())
|
||||
System.out.printf(" #%d %-25s %d pts%n", r.getRank(), r.getName(), r.getTotalScore());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String requireEnv(String name) {
|
||||
var v = System.getenv(name);
|
||||
if (v == null || v.isBlank()) {
|
||||
System.err.println("Error: " + name + " env var not set");
|
||||
System.exit(1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user