# Real Battle All-40 Scoring Experiments

> Superseded: these results were generated before the simulator preserved explicit zero-size
> battalion slots. Saved-game configs with empty slots could therefore receive extra full-capacity
> units. Regenerate this matrix after the zero-size battalion fix before comparing scoring changes.

These runs use all 40 saved battle creation payloads from `game_389ffb1901903118.zip`.
Each config was extracted from `new_battle_proto` plus the nearest prior Eagle `GameState`
snapshot. The matrix uses `max_rounds = 31`, `random_seed = 1`, AI setup placement, and forced
single-option commands.

Shardok has no draw result for these siege battles: if the attacker has not won after 31 rounds,
the defender wins. The simulator now records those cutoffs as `max_rounds_reached` defender wins
instead of `draw` / `Game incomplete`.

Raw rows are recorded in `real_battle_all40_scoring_matrix.csv`.

## Full Matrix Results

| Variant | Attacker wins | Defender wins | Max-round defender wins | Runtime |
| --- | ---: | ---: | ---: | ---: |
| `STANDARD` attacker vs `STANDARD` defender | 11 | 29 | 15 | 8.7 min |
| `NORMALIZED` attacker vs `STANDARD` defender | 1 | 39 | 23 | 8.7 min |
| `MCTS_OPTIMIZED` attacker vs `STANDARD` defender | 10 | 30 | 14 | 8.7 min |

`STANDARD` here is the current branch implementation, including the attacker-side change that keeps
unit value relevant through the end of the battle instead of decaying it by rounds remaining.

`NORMALIZED` is much worse for ID attacker scoring on this real set. It converts 10 baseline
attacker wins into defender wins and is not a promising direction for attacker scoring.

`MCTS_OPTIMIZED` is closer to neutral but still slightly worse than current `STANDARD` for ID
attacker scoring on this set. It loses battle `6705`, which current `STANDARD` wins, and does not
add any attacker wins.

## Outcome Changes Versus Baseline

### `NORMALIZED` Attacker

- `6248`: attacker last-player-standing win -> defender last-player-standing win
- `6408`: attacker last-player-standing win -> defender max-round win
- `6705`: attacker last-player-standing win -> defender last-player-standing win
- `8217`: attacker last-player-standing win -> defender max-round win
- `8394`: attacker last-player-standing win -> defender max-round win
- `11297`: attacker last-player-standing win -> defender last-player-standing win
- `11469`: attacker last-player-standing win -> defender max-round win
- `11662`: attacker last-player-standing win -> defender max-round win
- `11942`: attacker last-player-standing win -> defender max-round win
- `12136`: attacker last-player-standing win -> defender last-player-standing win

Other changes only alter how the defender wins, not who wins.

### `MCTS_OPTIMIZED` Attacker

- `6705`: attacker last-player-standing win -> defender last-player-standing win

Other changes only alter how the defender wins, not who wins.

## Close-Battle Follow-up

The closest current-baseline defender wins by surviving troop margin were:

- `11941`: defender max-round win, attacker 165 troops vs defender 299
- `1472`: defender max-round win, attacker 57 troops vs defender 378
- `307`: defender last-player-standing win with 324 defender troops left
- `7212`: defender max-round win, attacker 1156 troops vs defender 1800
- `10229`: defender max-round win, attacker 56 troops vs defender 727

Before correcting the no-draw rule, earlier max-20 data made several cutoffs look like draws. Those
rows are superseded for effectiveness comparisons by the max-31 matrix above.

## Scoring Tweak Tested

The scoring tweak included in this branch removes the attacker-side late-battle unit-value decay in
`StandardAIScoreCalculator::CombineAttackerScores`.

Rationale:

- Defender hold-castle scoring already removed this decay because it made tactical actions look
  worse than waiting when behind on unit value.
- The close real battles showed attackers failing to convert material/position before the round
  limit.
- Keeping unit value meaningful late in the battle should make the attacker continue seeking
  decisive tactical progress instead of undervaluing combat.

On the original five close production-length cases, this tweak preserved existing attacker wins and
flipped `11941` from defender win to attacker win:

| Battle | Production max-40 | No attacker unit decay |
| --- | --- | --- |
| `306` | attacker win, 239 attacker troops left | attacker win, 239 attacker troops left |
| `11469` | attacker win, 2166 attacker troops left | attacker win, 2160 attacker troops left |
| `11941` | defender win, 131 defender troops left | attacker win, 1052 attacker troops left |
| `6705` | attacker win, 2062 attacker troops left | attacker win, 2393 attacker troops left |
| `307` | defender win, 324 defender troops left | defender win, 324 defender troops left |

Detailed rows are recorded in `real_battle_closest_max40_no_attacker_unit_decay.csv`.

The final-round flee tweak was also tested and is recorded in
`real_battle_closest_final_round_flee_compare.csv` and
`real_battle_closest_final_round_flee_plus_no_decay.csv`. It did not outperform the cleaner
production-length no-decay result, so it is not included as a code change.
