Python案例:判断这次犯规该不该吃牌?
下面我用一个足球裁判辅助系统的案例,演示如何用 Python 根据规则判断犯规是否该出示黄牌或红牌。

规则建模
根据 IFAB(国际足联理事会)规则,简化判断逻辑:
| 犯规类型 | 判罚 |
|---|---|
| 普通战术犯规 | 黄牌 |
| 破坏明显得分机会(DOGSO) | 红牌 |
| 严重犯规/暴力行为 | 红牌 |
| 禁区内普通犯规 | 点球 + 视情况给牌 |
| 首次轻微犯规 | 口头警告 |
代码实现
from enum import Enum
from dataclasses import dataclass
class Card(Enum):
NONE = "无牌"
YELLOW = "黄牌"
RED = "红牌"
@dataclass
class Foul:
"""一次犯规的信息"""
foul_type: str # 犯规类型
in_penalty_area: bool # 是否在禁区内
is_dogso: bool # 是否破坏明显得分机会
is_violent: bool # 是否暴力行为
is_first_minor: bool # 是否首次轻微犯规
player_has_yellow: bool # 该球员是否已有黄牌
def judge_card(foul: Foul) -> tuple[Card, str]:
"""判断该犯规应出示什么牌,并返回理由"""
# 1. 暴力行为 / 严重犯规 → 直接红牌
if foul.is_violent:
return Card.RED, "暴力行为或严重犯规,直接红牌罚下"
# 2. 破坏明显得分机会(DOGSO)
if foul.is_dogso:
# 若为禁区内且属争抢球权的犯规,改判点球+黄牌("双罚"规则)
if foul.in_penalty_area and foul.foul_type == "争抢球":
return Card.YELLOW, "禁区内DOGSO但属争抢球,判点球+黄牌"
return Card.RED, "破坏明显得分机会,红牌罚下"
# 3. 首次轻微犯规 → 仅口头警告
if foul.is_first_minor:
return Card.NONE, "首次轻微犯规,口头警告即可"
# 4. 其他应警告的犯规 → 黄牌
if foul.foul_type in ("战术犯规", "非体育行为", "持续犯规", "抗议"):
return Card.YELLOW, f"{foul.foul_type},出示黄牌"
# 5. 已有黄牌再犯黄牌级犯规 → 两黄变一红
if foul.player_has_yellow:
return Card.RED, "两黄变一红,罚下"
return Card.NONE, "普通犯规,无需出牌"
# ===== 测试案例 =====
cases = [
Foul("战术犯规", False, False, False, False, False),
Foul("争抢球", True, True, False, False, False), # 禁区内DOGSO争抢球
Foul("拉拽", False, True, False, False, False), # 禁区外DOGSO
Foul("肘击", False, False, True, False, False), # 暴力行为
Foul("轻微推人", False, False, False, True, False),# 首次轻微
Foul("战术犯规", False, False, False, False, True),# 已有黄牌
]
for i, c in enumerate(cases, 1):
card, reason = judge_card(c)
print(f"案例{i}: {c.foul_type:6s} → 【{card.value}】 {reason}")
运行结果
案例1: 战术犯规 → 【黄牌】 战术犯规,出示黄牌
案例2: 争抢球 → 【黄牌】 禁区内DOGSO但属争抢球,判点球+黄牌
案例3: 拉拽 → 【红牌】 破坏明显得分机会,红牌罚下
案例4: 肘击 → 【红牌】 暴力行为或严重犯规,直接红牌罚下
案例5: 轻微推人 → 【无牌】 首次轻微犯规,口头警告即可
案例6: 战术犯规 → 【红牌】 两黄变一红,罚下
关键设计思路
- 优先级排序:暴力 > DOGSO > 首次轻微 > 常规黄牌,顺序不能乱。
- 特例处理:禁区内"争抢球"造成的 DOGSO 是黄牌而非红牌(足球规则特有)。
- 状态依赖:是否已有一张黄牌,会改变判罚结果。
- 可解释性:返回
(判罚, 理由),方便裁判复核。
可扩展方向
- 加入
VAR回看逻辑 - 记录比赛时间,判断"最后一名防守球员"
- 用决策树/规则引擎替代 if-else
- 用
pydantic做输入校验
需要我做成 Web 界面、带图形化决策树,还是接入真实比赛数据版本?