feat(@projects/@magic-civilization): ✨ add asymmetric difficulty mode
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
5c0e39fffe
commit
a155802049
4 changed files with 55 additions and 5 deletions
|
|
@ -38,7 +38,7 @@ done
|
|||
# MODE + positional args resolved early so the resource-policy block can
|
||||
# peek at the seed count (which differs per mode — for `clan` it's $2
|
||||
# because $1 is the clan_id; for smoke/gpu-walltime it's $1).
|
||||
MODE="${1:?usage: apricot-run.sh <smoke|clan|difficulty|gpu-walltime> [args]}"
|
||||
MODE="${1:?usage: apricot-run.sh <smoke|clan|difficulty|difficulty-asym|gpu-walltime> [args]}"
|
||||
shift || true
|
||||
|
||||
# ── Resource policy for PARALLEL + RAYON_NUM_THREADS ─────────────────
|
||||
|
|
@ -49,9 +49,10 @@ shift || true
|
|||
# core. Better: PARALLEL = number of seeds (one instance each), and
|
||||
# RAYON_NUM_THREADS = nproc / PARALLEL so the box is saturated evenly.
|
||||
case "${MODE}" in
|
||||
clan) _seed_count_peek="${2:-10}" ;; # $1 is clan_id, $2 is seeds
|
||||
difficulty) _seed_count_peek="${2:-10}" ;; # $1 is tier, $2 is seeds
|
||||
*) _seed_count_peek="${1:-10}" ;; # smoke, gpu-walltime
|
||||
clan) _seed_count_peek="${2:-10}" ;; # $1 is clan_id, $2 is seeds
|
||||
difficulty) _seed_count_peek="${2:-10}" ;; # $1 is tier, $2 is seeds
|
||||
difficulty-asym) _seed_count_peek="${3:-10}" ;; # $1 p0 tier, $2 p1 tier, $3 seeds
|
||||
*) _seed_count_peek="${1:-10}" ;; # smoke, gpu-walltime
|
||||
esac
|
||||
|
||||
NPROC="$(ssh "${APRICOT}" nproc 2>/dev/null || echo 8)"
|
||||
|
|
@ -197,6 +198,18 @@ case "${MODE}" in
|
|||
AI_USE_MCTS=true AI_DIFFICULTY='${DIFF_TIER}' ${GPU_ENV} PARALLEL=${PARALLEL} \
|
||||
bash tools/autoplay-batch.sh ${SEEDS} ${TURNS} ${RESULTS_ABS}/difficulty-${DIFF_TIER} 2>&1 | tail -30"
|
||||
;;
|
||||
difficulty-asym)
|
||||
P0_TIER="${1:?usage: apricot-run.sh difficulty-asym <p0-tier> <p1-tier> [seeds] [turns]}"
|
||||
P1_TIER="${2:?usage: apricot-run.sh difficulty-asym <p0-tier> <p1-tier> [seeds] [turns]}"
|
||||
SEEDS="${3:-10}"; TURNS="${4:-300}"
|
||||
GPU_ENV="AI_GPU_ROLLOUT=${AI_GPU_ROLLOUT:-false}"
|
||||
echo "[$(date +%H:%M:%S)] difficulty-asym p0=${P0_TIER} p1=${P1_TIER}: ${SEEDS} seeds T${TURNS}"
|
||||
ssh "${APRICOT}" "set -euo pipefail; cd '${SCRATCH_ABS}' && \
|
||||
AI_USE_MCTS=true AI_DIFFICULTY_P0='${P0_TIER}' AI_DIFFICULTY_P1='${P1_TIER}' \
|
||||
${GPU_ENV} PARALLEL=${PARALLEL} \
|
||||
bash tools/autoplay-batch.sh ${SEEDS} ${TURNS} \
|
||||
${RESULTS_ABS}/difficulty-asym-${P0_TIER}-vs-${P1_TIER} 2>&1 | tail -30"
|
||||
;;
|
||||
gpu-walltime)
|
||||
SEEDS="${1:-10}"; TURNS="${2:-300}"
|
||||
echo "[$(date +%H:%M:%S)] GPU wall-time comparison: ${SEEDS} seeds T${TURNS}"
|
||||
|
|
|
|||
|
|
@ -525,6 +525,10 @@ func _process(_delta: float) -> void:
|
|||
GameState.game_settings["difficulty"] = diff_env
|
||||
print("AutoPlay: AI_DIFFICULTY=%s applied" % diff_env)
|
||||
GameState.apply_ai_difficulty()
|
||||
# Per-player difficulty overrides for asymmetric matchups (p0-24).
|
||||
# AI_DIFFICULTY_P0=<tier> and AI_DIFFICULTY_P1=<tier> each override
|
||||
# that player's production/research multipliers independently.
|
||||
_apply_per_player_difficulty_overrides()
|
||||
_state = "wait_loading"
|
||||
_frame = 0
|
||||
if _frame > 120:
|
||||
|
|
@ -791,6 +795,32 @@ func _fix_start_positions_if_needed() -> void:
|
|||
])
|
||||
|
||||
|
||||
func _apply_per_player_difficulty_overrides() -> void:
|
||||
var diff_data: Dictionary = DataLoader.get_data("difficulty")
|
||||
if diff_data == null:
|
||||
return
|
||||
var levels: Dictionary = {}
|
||||
for entry: Dictionary in diff_data.get("ai_difficulty", []):
|
||||
levels[str(entry.get("id", ""))] = entry.get("ai_modifiers", {})
|
||||
for p_idx: int in range(GameState.players.size()):
|
||||
var key: String = "AI_DIFFICULTY_P%d" % p_idx
|
||||
var tier: String = EnvConfig.get_var(key, "")
|
||||
if tier.is_empty():
|
||||
continue
|
||||
var mods: Dictionary = levels.get(tier, {})
|
||||
if mods.is_empty():
|
||||
print("AutoPlay: WARNING: unknown difficulty tier '%s' for %s" % [tier, key])
|
||||
continue
|
||||
GameState.ai_per_player_production_mult[p_idx] = float(mods.get("production_mult", 1.0))
|
||||
GameState.ai_per_player_research_mult[p_idx] = float(mods.get("research_mult", 1.0))
|
||||
print(
|
||||
"AutoPlay: %s=%s → player %d prod=%.2f research=%.2f"
|
||||
% [key, tier, p_idx,
|
||||
GameState.ai_per_player_production_mult[p_idx],
|
||||
GameState.ai_per_player_research_mult[p_idx]]
|
||||
)
|
||||
|
||||
|
||||
func _apply_difficulty_starting_bonuses() -> void:
|
||||
var gold_bonus: int = GameState.ai_starting_gold_bonus
|
||||
var extra_units: int = GameState.ai_extra_starting_units
|
||||
|
|
|
|||
|
|
@ -359,7 +359,10 @@ static func build_tile_yields_json(
|
|||
static func _calculate_science_income(player: RefCounted) -> int:
|
||||
var sci_modifier: float = 1.0
|
||||
if player is PlayerScript and not player.is_human:
|
||||
sci_modifier = GameState.ai_research_modifier
|
||||
var per_player: float = float(
|
||||
GameState.ai_per_player_research_mult.get(player.index, 0.0)
|
||||
)
|
||||
sci_modifier = per_player if per_player > 0.0 else GameState.ai_research_modifier
|
||||
var science: int = int(player.science_per_turn * sci_modifier)
|
||||
var game_map: RefCounted = GameState.get_game_map()
|
||||
if game_map == null:
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@ _run_local() {
|
|||
"--env=AUTO_PLAY_DIR=$game_dir"
|
||||
"--env=AP_RUN_ID=${STAMP}_seed$(printf '%03d' "$seed")"
|
||||
"--env=AI_DIFFICULTY=${AI_DIFFICULTY:-}"
|
||||
"--env=AI_DIFFICULTY_P0=${AI_DIFFICULTY_P0:-}"
|
||||
"--env=AI_DIFFICULTY_P1=${AI_DIFFICULTY_P1:-}"
|
||||
"--env=AI_PIN_PERSONALITY=${AI_PIN_PERSONALITY:-}"
|
||||
"--env=MAP_SIZE=${MAP_SIZE:-}"
|
||||
"--env=NUM_PLAYERS=${NUM_PLAYERS:-}"
|
||||
|
|
@ -239,6 +241,8 @@ _run_remote() {
|
|||
AUTO_PLAY_DIR='$remote_game_dir' \
|
||||
AP_RUN_ID="${STAMP}_seed$(printf '%03d' "$seed")" \
|
||||
AI_DIFFICULTY='${AI_DIFFICULTY:-}' \
|
||||
AI_DIFFICULTY_P0='${AI_DIFFICULTY_P0:-}' \
|
||||
AI_DIFFICULTY_P1='${AI_DIFFICULTY_P1:-}' \
|
||||
AI_PIN_PERSONALITY='${AI_PIN_PERSONALITY:-}' \
|
||||
MAP_SIZE='${MAP_SIZE:-}' \
|
||||
NUM_PLAYERS='${NUM_PLAYERS:-}' \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue