59 lines
2.4 KiB
Python
59 lines
2.4 KiB
Python
"""麻将胡了 · 数据模型(frozen dataclass,母本 olympus/models.py 同风格)。"""
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass, field
|
||
from typing import Dict, List, Optional, Tuple
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Win:
|
||
"""一笔奖 = 某符号的一条前缀链。"""
|
||
symbol: str
|
||
run: int # 链长 3/4/5(从第 1 轴起连续的轴数)
|
||
counts: Tuple[int, ...] # 链内各轴的格数(百搭计入)
|
||
ways: int # counts 的乘积
|
||
loc: Tuple[int, ...] # 本笔涉及的全部格位(1 基,含金色格与百搭)
|
||
pay_base: float # 赔付表[符号][链长] × ways,单位 = 倍投注总额
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Rotation:
|
||
"""一波 = 一次消除结算。"""
|
||
seq: int # 本旋内第几波(= 阶梯序号)
|
||
rotation_mul: int # 本波阶梯倍率
|
||
wins: Tuple[Win, ...]
|
||
base_mul: float # Σ pay_base
|
||
win_mul: float # base_mul × rotation_mul
|
||
converted: Tuple[Tuple[int, str], ...] # (格位1基, 原自然符号):金色就地转百搭
|
||
drops: Tuple[Tuple[int, int], ...] # (from1基, to1基)
|
||
fills: Tuple[Tuple[int, str], ...] # (格位1基, 新符号)
|
||
grid: Tuple[Optional[str], ...] # 本波结算+补位后的盘面(20 格短码)
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Spin:
|
||
"""一旋。"""
|
||
index: int # 0 = 基础旋(触发盘),>0 = 第 N 次免费旋转
|
||
is_fs: bool
|
||
rotations: Tuple[Rotation, ...]
|
||
mul: float # 本旋倍率
|
||
scatters: int # 本旋**落定盘面**上的胡数(补位产生的不算触发)
|
||
fs_awarded: int = 0 # 本旋触发的赠送旋数(0 = 没触发)
|
||
retrigger: bool = False
|
||
|
||
|
||
@dataclass
|
||
class Round:
|
||
"""一局 = 基础旋 + 免费旋转(可重触发),受 500x 封顶。"""
|
||
box_id: int
|
||
spins: List[Spin] = field(default_factory=list)
|
||
raw_mul: float = 0.0 # 封顶前的总倍率
|
||
actual_mul: float = 0.0 # min(raw_mul, 500) —— 落桶/发奖用这个
|
||
capped: bool = False
|
||
near_miss: bool = False # 基础旋恰好 2 个胡且第 5 轴无胡
|
||
free_spins: int = 0 # 本局发放的免费旋数
|
||
|
||
@property
|
||
def has_fs(self) -> bool:
|
||
return self.free_spins > 0
|