28 lines
1.0 KiB
Python
28 lines
1.0 KiB
Python
"""Combat = score comparison. Relative score difference -> win probability -> damage."""
|
|
|
|
import math
|
|
import random
|
|
|
|
|
|
def win_probability(score_a: float, score_b: float, cfg: dict) -> float:
|
|
mean = (score_a + score_b) / 2
|
|
if mean <= 0:
|
|
return 0.5
|
|
d = (score_a - score_b) / mean
|
|
return 1 / (1 + math.exp(-d / cfg["combat"]["tau"]))
|
|
|
|
|
|
def resolve(score_a: float, score_b: float, cfg: dict, rng: random.Random) -> bool:
|
|
"""True if A wins. Adds noise on top of the probability."""
|
|
noise = rng.gauss(0, cfg["combat"]["variance"])
|
|
return rng.random() < min(max(win_probability(score_a, score_b, cfg) + noise, 0.02), 0.98)
|
|
|
|
|
|
def damage(stage: int, winner_score: float, loser_score: float, winner_units: int, cfg: dict) -> int:
|
|
d = cfg["damage"]
|
|
base = d["stage_base"][min(stage - 1, len(d["stage_base"]) - 1)]
|
|
mean = (winner_score + loser_score) / 2 or 1
|
|
margin = abs(winner_score - loser_score) / mean
|
|
surviving = max(1, round(winner_units * min(margin, 1.0)))
|
|
return base + d["per_surviving_unit"] * surviving
|