feat(SAC_LSTM_Bot): mirror-twin sparring partner + readiness check (#54)
- make_twin.sh: generates self-contained SacTwin dir in the sample-bots archive (own json/sh identity, own weights dir seeded from a frozen sac_best.zip copy, own round_counter) so RunTraining.java resolves it like any sample bot; re-running resets the twin to the frozen baseline. - src/SAC_LSTM_Bot.nim: SACLSTM_BOT_JSON env overrides the baked-in bot json (loadBotInfo gives json total precedence, #49) so the same binary boots under the twin's name. - sac_train.sh: chunk loop is a while, not for-over-seq — a crash on the FINAL chunk previously fell through ((chunk--);continue on an exhausted seq list) and exited 0 with budget incomplete; observed live vs SacTwin. Readiness dry-run (#54): weighted pool Corners:1,SacTwin:3 picked the twin in 3/4 chunks; all battles counter-checked; deterministic eval parsed; main sac_best.zip/counter untouched by twin (twin counter advanced independently); crash-restart proven end-to-end incl. final-chunk retry.
This commit is contained in:
Executable
+56
@@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# make_twin.sh — #54 mirror-twin sparring partner generator.
|
||||||
|
#
|
||||||
|
# Builds a self-contained `SacTwin` bot dir inside the sample-bots archive so
|
||||||
|
# RunTraining.java resolves it like any sample bot ($SAMPLE_BOTS_DIR/<name>).
|
||||||
|
# The twin is the SAME binary as SAC_LSTM_Bot but with:
|
||||||
|
# - distinct identity (SacTwin.json; SACLSTM_BOT_JSON overrides the baked-in
|
||||||
|
# src json — loadBotInfo gives json total precedence over env, #49 lesson)
|
||||||
|
# - its OWN weights dir, seeded from a FROZEN copy of weights/sac_best.zip
|
||||||
|
# (no checkpoint write races with the main bot)
|
||||||
|
# - its OWN round_counter.txt (main liveness guard untouched)
|
||||||
|
#
|
||||||
|
# Re-running resets the twin to the frozen baseline (reproducible opponent).
|
||||||
|
#
|
||||||
|
# Usage: ./make_twin.sh [target-archive-dir]
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
TARGET="${1:-${SAMPLE_BOTS_DIR:-/home/davide/Projects/tank-royale/sample-bots/java/build/archive}}/SacTwin"
|
||||||
|
BIN="$SCRIPT_DIR/SAC_LSTM_Bot" # nimble build -d:release output
|
||||||
|
SEED="$SCRIPT_DIR/weights/sac_best.zip" # frozen baseline
|
||||||
|
|
||||||
|
[ -x "$BIN" ] || { echo ">>> $BIN missing — run 'nimble build -d:release' first"; exit 1; }
|
||||||
|
[ -f "$SEED" ] || { echo ">>> $SEED missing — need at least one eval'd checkpoint"; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$TARGET/weights"
|
||||||
|
cp "$BIN" "$TARGET/SAC_LSTM_Bot"
|
||||||
|
|
||||||
|
cat > "$TARGET/SacTwin.json" <<EOF
|
||||||
|
{
|
||||||
|
"name": "SacTwin",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"authors": ["Davide Cappellini"],
|
||||||
|
"description": "Mirror-twin sparring partner of SAC_LSTM_Bot (#54), generated by make_twin.sh — own weights dir, frozen seed",
|
||||||
|
"homepage": "",
|
||||||
|
"countryCodes": ["IT"],
|
||||||
|
"gameTypes": ["classic", "melee", "1v1"],
|
||||||
|
"platform": "Nim",
|
||||||
|
"programmingLang": "Nim"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TARGET/SacTwin.sh" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
# Twin launcher (#54): identity + weights fully decoupled from the main bot.
|
||||||
|
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
export SACLSTM_BOT_JSON="$DIR/SacTwin.json"
|
||||||
|
export SACLSTM_WEIGHTS_PATH="$DIR/weights/sac_latest.zip"
|
||||||
|
exec "$DIR/SAC_LSTM_Bot"
|
||||||
|
EOF
|
||||||
|
chmod +x "$TARGET/SacTwin.sh" "$TARGET/SAC_LSTM_Bot"
|
||||||
|
|
||||||
|
cp "$SEED" "$TARGET/weights/sac_latest.zip"
|
||||||
|
cp "$SEED" "$TARGET/weights/sac_best.zip"
|
||||||
|
echo 0 > "$TARGET/weights/round_counter.txt"
|
||||||
|
echo ">>> twin ready: $TARGET (seeded from $(stat -c %y "$SEED" | cut -d. -f1) snapshot of sac_best.zip)"
|
||||||
@@ -101,7 +101,11 @@ eval_checkpoint() {
|
|||||||
|
|
||||||
NUM_CHUNKS=$(( (TOTAL_ROUNDS + CHUNK_SIZE - 1) / CHUNK_SIZE ))
|
NUM_CHUNKS=$(( (TOTAL_ROUNDS + CHUNK_SIZE - 1) / CHUNK_SIZE ))
|
||||||
fails=0
|
fails=0
|
||||||
for chunk in $(seq 1 "$NUM_CHUNKS"); do
|
chunk=1
|
||||||
|
# while, not `for chunk in $(seq ...)`: a crash on the FINAL chunk must rerun
|
||||||
|
# it (#54 — seq list is exhausted by then, so ((chunk--));continue fell through
|
||||||
|
# and the harness exited 0 with the budget incomplete).
|
||||||
|
while (( chunk <= NUM_CHUNKS )); do
|
||||||
ROUNDS=$CHUNK_SIZE
|
ROUNDS=$CHUNK_SIZE
|
||||||
(( TOTAL_ROUNDS - (chunk - 1) * CHUNK_SIZE < CHUNK_SIZE )) && \
|
(( TOTAL_ROUNDS - (chunk - 1) * CHUNK_SIZE < CHUNK_SIZE )) && \
|
||||||
ROUNDS=$(( TOTAL_ROUNDS - (chunk - 1) * CHUNK_SIZE ))
|
ROUNDS=$(( TOTAL_ROUNDS - (chunk - 1) * CHUNK_SIZE ))
|
||||||
@@ -120,6 +124,7 @@ for chunk in $(seq 1 "$NUM_CHUNKS"); do
|
|||||||
fi
|
fi
|
||||||
fails=0
|
fails=0
|
||||||
(( chunk % EVAL_INTERVAL == 0 )) && eval_checkpoint
|
(( chunk % EVAL_INTERVAL == 0 )) && eval_checkpoint
|
||||||
|
((chunk += 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
echo ">>> training complete: $NUM_CHUNKS chunks. Logs:"
|
echo ">>> training complete: $NUM_CHUNKS chunks. Logs:"
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ import SAC_LSTM_Bot/actions
|
|||||||
import SAC_LSTM_Bot/rewards
|
import SAC_LSTM_Bot/rewards
|
||||||
import SAC_LSTM_Bot/integration
|
import SAC_LSTM_Bot/integration
|
||||||
|
|
||||||
const botJsonPath = currentSourcePath().parentDir / "SAC_LSTM_Bot.json"
|
# Identity json: baked-in src json by default; SACLSTM_BOT_JSON lets a mirror
|
||||||
|
# twin (#54) boot the same binary under its own name (loadBotInfo gives the
|
||||||
|
# json total precedence over env, so the twin must point at its own file).
|
||||||
|
let botJsonPath = getEnv("SACLSTM_BOT_JSON",
|
||||||
|
currentSourcePath().parentDir / "SAC_LSTM_Bot.json")
|
||||||
|
|
||||||
# ── Colors (Recurrent Royalty palette) ───────────────────────────────────────
|
# ── Colors (Recurrent Royalty palette) ───────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user