python案例如何结合士气指数做决策?

wen python案例 5

Python 实战案例

"士气指数"在游戏 AI、团队管理模拟、军事推演、球员状态评估等场景中很常见,下面我用一个可运行的 Python 案例,展示如何把士气指数从"一个数字"变成"决策引擎"。

python案例如何结合士气指数做决策?


核心思路:士气不是直接决策,而是"调制器"

很多人的误区是:

if 士气 > 80: 进攻
elif 士气 < 30: 撤退

这样太粗糙,更好的架构是:

士气指数 → 分层处理 → 调节决策权重 → 加权评分 → 输出决策

具体分三层:

层级 作用 输出
状态层 士气映射为状态(高涨/正常/低落/崩溃) 状态标签
权重层 状态调节各行动方案的权重 权重向量
决策层 加权评分 + 阈值/规则兜底 最终行动

完整案例:小队的战斗决策

from dataclasses import dataclass, field
from typing import List
# ---------- 1. 士气状态映射 ----------
def morale_to_state(morale: float) -> str:
    """士气 0-100 → 状态标签"""
    if morale >= 80:
        return "高涨"
    elif morale >= 55:
        return "正常"
    elif morale >= 30:
        return "低落"
    else:
        return "崩溃"
# ---------- 2. 状态 → 行动权重 ----------
# 权重系数调节各类行为的倾向
ACTION_WEIGHT_TABLE = {
    #           进攻  防守  撤退  支援  鼓舞
    "高涨": [1.4, 0.9, 0.2, 1.1, 1.3],
    "正常": [1.0, 1.0, 1.0, 1.0, 1.0],
    "低落": [0.6, 1.2, 1.0, 0.8, 1.4],   # 低落更想防守/鼓舞
    "崩溃": [0.2, 0.8, 1.8, 0.3, 1.5],   # 崩溃倾向撤退/鼓舞
}
ACTIONS = ["进攻", "防守", "撤退", "支援", "鼓舞"]
# ---------- 3. 情境评分(不考虑士气时的基础决策) ----------
@dataclass
class Situation:
    enemy_strength: float   # 敌方强度 0-100
    our_strength: float     # 我方强度 0-100
    ammo: float             # 弹药 0-1
    allies_nearby: bool     # 是否有友军支援
    objective_value: float  # 目标价值 0-1
    def base_scores(self) -> dict:
        adv = (self.our_strength - self.enemy_strength) / 100  # -1 ~ 1
        s = {}
        s["进攻"] = 50 + 40 * adv + 30 * (self.ammo - 0.5) + 20 * self.objective_value
        s["防守"] = 50 - 25 * adv + 15 * (self.ammo - 0.5)
        s["撤退"] = 40 - 50 * adv + 20 * (1 - self.ammo)
        s["支援"] = 40 + (30 if self.allies_nearby else -20)
        s["鼓舞"] = 30 + (20 if not self.allies_nearby else 0)
        return s
# ---------- 4. 决策引擎 ----------
@dataclass
class Commander:
    name: str
    morale: float = 60.0
    history: List[str] = field(default_factory=list)
    def decide(self, sit: Situation, verbose=True) -> str:
        state = morale_to_state(self.morale)
        weights = ACTION_WEIGHT_TABLE[state]
        base = sit.base_scores()
        # 加权求和
        final = {a: base[a] * w for a, w in zip(ACTIONS, weights)}
        # 规则兜底:崩溃状态下禁止主动进攻
        if state == "崩溃":
            final["进攻"] *= 0.3
        # 连败惩罚:连续撤退过多,士气额外衰减(体现负反馈)
        if self.history[-2:] == ["撤退", "撤退"]:
            final["撤退"] *= 0.7
        best = max(final, key=final.get)
        if verbose:
            print(f"[{self.name}] 士气={self.morale:.0f} 状态={state}")
            for a in ACTIONS:
                print(f"   {a}: 基础{base[a]:6.1f} × {dict(zip(ACTIONS,weights))[a]} = {final[a]:5.1f}")
            print(f"   → 决策:**{best}**\n")
        self.history.append(best)
        return best
    def update_morale(self, event: str):
        """事件驱动士气变化"""
        delta = {
            "胜利": +15, "失败": -20, "队友阵亡": -25,
            "获得补给": +10, "被鼓舞": +12,
        }.get(event, 0)
        self.morale = max(0, min(100, self.morale + delta))
# ---------- 5. 演练 ----------
if __name__ == "__main__":
    sit = Situation(enemy_strength=70, our_strength=55,
                    ammo=0.4, allies_nearby=False, objective_value=0.8)
    cmdr = Commander("Alpha小队", morale=85)
    cmdr.decide(sit)
    cmdr.update_morale("失败")
    cmdr.update_morale("队友阵亡")   # 士气 85 → 40
    cmdr.decide(sit)
    cmdr.update_morale("获得补给")
    cmdr.decide(sit)

输出大致如下:

[Alpha小队] 士气=85 状态=高涨
   进攻: 基础  44.0 × 1.4 =  61.6    ← 士气高涨,主动进攻
   ...
   → 决策:**进攻**
[Alpha小队] 士气=40 状态=低落
   进攻: 基础  44.0 × 0.6 =  26.4
   撤退: 基础  36.0 × 1.0 =  36.0
   → 决策:**撤退**            ← 士气低落+连败,转向保守
[Alpha小队] 士气=50 状态=低落
   → 决策:**防守**

让士气"活起来"的 4 个关键设计

士气不是单值,而是一个"分布"

真实场景里士气波动大,可以用概率分布代替确定值:

import numpy as np
def sample_morale(mu, sigma=8):
    return float(np.clip(np.random.normal(mu, sigma), 0, 100))
# 蒙特卡洛:跑 1000 次看决策分布
decisions = {}
for _ in range(1000):
    cmdr.morale = sample_morale(55)
    d = cmdr.decide(Situation(...), verbose=False)
    decisions[d] = decisions.get(d, 0) + 1
# → 得到"60%防守 / 25%进攻 / 15%撤退"这样更真实的分布

士气要有"惯性"和"记忆"

用指数平滑避免士气剧烈抖动:

self.morale = 0.7 * self.morale + 0.3 * new_signal

或者引入士气衰退——长期不鼓舞自动下滑:

def tick(self, hours=1):
    self.morale = max(0, self.morale - 0.5 * hours)

士气影响的不只是选择,还有"执行质量"

士气低落时,即使选了进攻也可能执行打折:

effectiveness = 0.5 + 0.5 * (self.morale / 100)   # 0.5~1.0 的执行系数
damage_dealt = base_damage * effectiveness

决策时要区分"高士气≠莽"

高士气应该减少迟疑而不是无脑进攻,可以这样做:

if state == "高涨":
    # 高涨时缩短决策延迟、提高执行速度
    reaction_time *= 0.7
    # 但保留风险评估
else:
    reaction_time *= 1.5

更通用的接口化设计(推荐)

把上面耦合的逻辑抽成可替换的策略接口,方便迁移到其他领域(团队管理、机器人、NPC AI):

from abc import ABC, abstractmethod
class MoralePolicy(ABC):
    @abstractmethod
    def weight(self, state: str) -> dict: ...
class DecisionEnv(ABC):
    @abstractmethod
    def base_scores(self) -> dict: ...
class MoraleDecisionEngine:
    def __init__(self, policy: MoralePolicy, env: DecisionEnv):
        self.policy = policy
        self.env = env
    def decide(self, morale: float) -> str:
        state = morale_to_state(morale)
        w = self.policy.weight(state)
        scores = {a: self.env.base_scores()[a] * w[a] for a in w}
        return max(scores, key=scores.get)

这样你可以:

  • 游戏里用 CombatPolicy(进攻/防守倾向)
  • 团队管理模拟里用 TeamPolicy(激励/加班/休假)
  • 机器人在危险环境下用 SafetyPolicy(探索/保守)

决策时机的几个坑

坑 后果 解法
士气值直接当权重,不做归一 数值尺度失真,被其他因素淹没 映射到 0.2~1.8 的调节系数
只看当前士气,忽略趋势 高涨刚开始回落就误判进攻 加入士气变化率 Δmorale/dt
士气崩溃仍按加权决策 可能出现"自杀式选择" 加规则兜底/硬约束
忽视士气反馈回路 撤退→士气更低→更想撤退(死循环) 撤退后强制降低撤退权重 + 加冷静期

总结一句话

士气指数不是"if 语句",而是"乘法系数 + 状态机 + 反馈环"。

  • 用状态映射把连续值变成离散档位 → 可解释
  • 用权重表让士气调制各方案得分 → 可调参
  • 用规则兜底防止极端情况 → 可安全
  • 用单调更新 + 惯性让士气有记忆 → 可仿真

需要我针对游戏 NPC、团队调度、还是部队推演哪个具体场景展开更细的参数调优吗?

上一篇python案例认为控球率与胜率成正相关吗?

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!