feat(@mc-ai): ✨ add trailing ai detection logic
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
69ca69ee06
commit
acaa6792f0
1 changed files with 41 additions and 8 deletions
|
|
@ -123,7 +123,7 @@ pub(crate) fn decide_movement(
|
|||
decide_military_action(
|
||||
unit, me, &enemy_units, &enemy_city_positions,
|
||||
own_mil_count, enemy_mil_count, weights, rng,
|
||||
state.difficulty_threshold_mult,
|
||||
state.difficulty_threshold_mult, is_trailing,
|
||||
)
|
||||
} else {
|
||||
None // deployed but no target: hold
|
||||
|
|
@ -142,6 +142,7 @@ pub(crate) fn decide_movement(
|
|||
weights,
|
||||
rng,
|
||||
state.difficulty_threshold_mult,
|
||||
is_trailing,
|
||||
);
|
||||
if primary.is_some() {
|
||||
primary
|
||||
|
|
@ -385,6 +386,35 @@ fn count_military(units: &[TacticalUnit]) -> usize {
|
|||
units.iter().filter(|u| is_military(u)).count()
|
||||
}
|
||||
|
||||
/// Whether `me` is the trailing AI on this turn.
|
||||
///
|
||||
/// `true` iff (a) at least one alive rival already has 2+ cities (gate that
|
||||
/// filters early-game equal-start ties where everyone has 1 city), AND
|
||||
/// (b) `me`'s total population is the minimum among all alive players
|
||||
/// (including `me`). Used by `decide_military_action` to gate sole-city
|
||||
/// turtling so only the genuine underdog goes defensive — without this gate
|
||||
/// every clan at 1 city turtles and the whole map stalls at tier_peak=1.
|
||||
fn compute_is_trailing(state: &TacticalState, me: &TacticalPlayerState) -> bool {
|
||||
let total_pop = |p: &TacticalPlayerState| -> u32 {
|
||||
p.cities.iter().map(|c| c.population).sum()
|
||||
};
|
||||
let my_pop = total_pop(me);
|
||||
let mut anyone_multi_city = false;
|
||||
let mut anyone_below_me = false;
|
||||
for (i, p) in state.players.iter().enumerate() {
|
||||
if i == me.index as usize || p.cities.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if p.cities.len() >= 2 {
|
||||
anyone_multi_city = true;
|
||||
}
|
||||
if total_pop(p) < my_pop {
|
||||
anyone_below_me = true;
|
||||
}
|
||||
}
|
||||
anyone_multi_city && !anyone_below_me
|
||||
}
|
||||
|
||||
fn count_own_military_at(me: &TacticalPlayerState, pos: (i32, i32)) -> usize {
|
||||
me.units
|
||||
.iter()
|
||||
|
|
@ -500,6 +530,7 @@ fn decide_military_action(
|
|||
weights: &ScoringWeights,
|
||||
_rng: &mut XorShift64,
|
||||
difficulty_threshold_mult: f32,
|
||||
is_trailing: bool,
|
||||
) -> Option<Action> {
|
||||
let hp_frac = unit.hp as f32 / unit.hp_max.max(1) as f32;
|
||||
let nearest_enemy = nearest_enemy_unit(unit.hex, enemy_units);
|
||||
|
|
@ -560,14 +591,16 @@ fn decide_military_action(
|
|||
} else {
|
||||
retreat_hp_fraction
|
||||
};
|
||||
// p1-29d — when we have exactly one city AND the enemy field outnumbers
|
||||
// our own, units stay much more cautious: retreat at full HP and never
|
||||
// press forward into a likely losing engagement. Composes additively on
|
||||
// top of the personality-axis-driven base so aggressive clans still
|
||||
// engage when they have parity, but a trailing AI no longer feeds the
|
||||
// leader's kill count before being able to mass a real defense force.
|
||||
// p1-29d — sole-city turtling for the *trailing* AI only (`is_trailing`
|
||||
// is computed by `decide_movement` from full TacticalState: lowest total
|
||||
// population AND at least one rival already multi-city). Without the
|
||||
// is_trailing gate, every clan at 1 city in early game qualifies and the
|
||||
// entire map turtles → no one expands → tier_peak=1 universal
|
||||
// (huge-map batch 20260516_191254). When the gate fires, retreat HP
|
||||
// threshold goes up by +0.30 (cap 0.90) so the trailing player stops
|
||||
// feeding the leader's kill count before massing a real defense.
|
||||
let sole_city_threatened =
|
||||
me.cities.len() == 1 && enemy_mil_count >= own_mil_count.max(1);
|
||||
is_trailing && me.cities.len() == 1 && enemy_mil_count >= own_mil_count.max(1);
|
||||
let base_retreat_hp = if sole_city_threatened {
|
||||
(base_retreat_hp + 0.30).min(0.90)
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue