Skip to content

Latest commit

 

History

History
247 lines (190 loc) · 6.77 KB

File metadata and controls

247 lines (190 loc) · 6.77 KB

OSR-Engine 通用跑团规则引擎 - V2更新计划

更新目标:增强骰子系统,支持复杂数学运算(乘法、除法和括号表达式)

1. 当前限制分析

1.1 现有骰子系统限制

  • 仅支持加法运算(通过 split("+") 实现)
  • 不支持乘法、除法操作
  • 不支持括号表达式
  • 表达式解析逻辑简单,无法处理复杂优先级

1.2 代码分析

# 现有实现的关键限制
terms = re.split(r"\+", result_expr)  # 仅按加法分割

2. 更新计划

2.1 核心改进:表达式解析器重构

目标:实现完整的四则运算和括号支持,同时保持安全性

技术方案:使用 Shunting-yard 算法(调度场算法)实现中缀表达式到后缀表达式(逆波兰表示法)的转换,然后计算后缀表达式的值。

实现步骤

  1. 词法分析:将表达式分解为标记(tokens)
  2. 语法分析:使用 Shunting-yard 算法转换为后缀表达式
  3. 表达式求值:计算后缀表达式的最终结果

2.2 具体功能增强

2.2.1 数学运算支持

  • ✅ 加法(已支持)
  • ✅ 减法
  • ✅ 乘法
  • ✅ 除法(整除,向下取整)
  • ✅ 括号优先级处理

2.2.2 骰子表达式扩展

  • ✅ 基本骰子表达式(如 3d6, d20
  • ✅ 百分骰 d%
  • ✅ 骰子表达式作为复杂表达式的一部分(如 (2d6+4)*2

2.2.3 变量支持

  • ✅ 保留现有变量替换功能
  • ✅ 允许变量在复杂表达式中使用(如 level*d8+con_mod

2.2.4 安全性保障

  • ✅ 禁止危险字符和代码执行
  • ✅ 表达式长度限制
  • ✅ 运算复杂度限制(防止资源耗尽)

3. 代码实现详细设计

3.1 engine/dice.py 更新

核心函数重构

def roll(expr: str, variables: Optional[Dict[str, int]] = None) -> int:
    """
    解析并掷骰子表达式,支持四则运算和括号。
    
    支持的表达式示例:
    - 3d6+2
    - (2d6-1)*4
    - d20*(1+bonus/2)
    - level*d8+con_mod
    """
    # 安全性检查
    # 变量替换
    # 使用 Shunting-yard 算法解析表达式
    # 计算并返回结果

新增辅助函数

def tokenize(expr: str) -> List[Token]:
    """将表达式字符串分解为标记列表"""

def to_postfix(tokens: List[Token]) -> List[Token]:
    """将中缀表达式转换为后缀表达式(Shunting-yard算法)"""

def evaluate_postfix(postfix_tokens: List[Token]) -> int:
    """计算后缀表达式的值"""

def roll_dice(count: int, sides: int) -> int:
    """掷指定数量和面数的骰子"""

标记类型定义

class TokenType(Enum):
    NUMBER = "NUMBER"
    DICE = "DICE"
    PLUS = "PLUS"
    MINUS = "MINUS"
    MULTIPLY = "MULTIPLY"
    DIVIDE = "DIVIDE"
    LPAREN = "LPAREN"
    RPAREN = "RPAREN"

class Token:
    def __init__(self, type: TokenType, value: Any):
        self.type = type
        self.value = value

3.2 安全性设计

  1. 表达式验证

    • 长度限制(最大 1000 字符)
    • 字符白名单验证
    • 括号匹配检查
  2. 运算限制

    • 最大骰子数量限制(单个表达式中不超过 100 个骰子)
    • 最大计算步骤限制

4. 测试用例设计

4.1 基础测试

# 基本运算测试
def test_basic_operations():
    assert roll("2+3") == 5
    assert roll("5-2") == 3
    assert roll("3*4") == 12
    assert roll("8/2") == 4
    assert roll("7/2") == 3  # 整除,向下取整

# 骰子表达式测试
def test_dice_expressions():
    result = roll("3d6")
    assert 3 <= result <= 18
    
    result = roll("d%")  # 百分骰
    assert 1 <= result <= 100

4.2 复杂表达式测试

# 混合运算测试
def test_complex_expressions():
    # 使用种子确保可重复性
    random.seed(42)
    
    # 复杂表达式
    result = roll("(2d6+4)*2")  # (2d6=7+4=11)*2=22
    assert result == 22
    
    result = roll("d20+3*2")  # d20=17+6=23
    assert result == 23
    
    # 嵌套括号
    result = roll("((2+3)*4-6)/3")  # ((5)*4-6)/3 = (20-6)/3 = 14/3 = 4
    assert result == 4

4.3 变量测试

# 变量替换测试
def test_variable_substitution():
    vars = {"level": 3, "bonus": 2, "con": 14}
    
    result = roll("level*d8+bonus", vars)
    assert isinstance(result, int)
    
    # 复杂变量表达式
    result = roll("(level+1)*bonus", vars)
    assert result == (3+1)*2 == 8

4.4 异常处理测试

# 错误表达式测试
def test_error_handling():
    with pytest.raises(ValueError):
        roll("2d6+2d")  # 无效的骰子表达式
    
    with pytest.raises(ValueError):
        roll("2d6/0")  # 除零错误
    
    with pytest.raises(ValueError):
        roll("(2d6+3")  # 括号不匹配
    
    with pytest.raises(ValueError):
        roll("2d6+eval('1+1')")  # 安全性检查

5. 实现步骤

5.1 步骤 1:定义 Token 类型和词法分析器

  • 实现 Token 类和 TokenType 枚举
  • 开发 tokenize() 函数,将表达式字符串转换为标记列表
  • 测试词法分析正确性

5.2 步骤 2:实现 Shunting-yard 算法

  • 开发 to_postfix() 函数,处理操作符优先级和括号
  • 确保正确处理四则运算的优先级规则
  • 测试中缀到后缀表达式的转换

5.3 步骤 3:实现表达式求值

  • 开发 evaluate_postfix() 函数,计算后缀表达式
  • 实现 roll_dice() 函数处理骰子表达式
  • 测试表达式求值的正确性

5.4 步骤 4:整合并重构 roll() 函数

  • 更新 roll() 函数,集成新的解析和求值逻辑
  • 保留并增强变量替换功能
  • 强化安全性检查

5.5 步骤 5:编写完整测试套件

  • 实现所有测试用例
  • 确保覆盖率 ≥ 95%
  • 运行测试验证功能正确性

5.6 步骤 6:代码规范和性能优化

  • 运行 black, ruff, mypy 确保代码质量
  • 优化解析和计算性能
  • 检查潜在的安全问题

6. 兼容性注意事项

  • 确保向后兼容:现有代码中使用的简单表达式(如 3d6, d20+5)应继续正常工作
  • 变量替换逻辑保持一致
  • 错误处理机制保持兼容

7. 性能考虑

  • 对于复杂表达式,Shunting-yard 算法的时间复杂度为 O(n)
  • 骰子数量限制可以防止性能问题
  • 表达式长度限制可以避免过长的处理时间

8. 验证标准

  1. 功能完整性:所有四则运算和括号表达式正确计算
  2. 向后兼容:现有代码不受影响
  3. 安全性:无代码注入风险
  4. 性能:表达式计算迅速完成
  5. 测试覆盖:测试覆盖率 ≥ 95%
  6. 代码质量:通过 Black/Ruff/MyPy 检查

预期成果:一个功能强大、安全可靠的骰子表达式解析器,支持复杂的数学运算,为 OSR 跑团引擎提供更灵活的规则实现能力。