You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Python骰子类实现双参数集:单独参数或骰子表达式

实现支持表达式解析的Python骰子类

现有一个Python骰子类代码,希望扩展功能:当仅传入一个字符串参数(如4d6+3)时自动解析为骰子表达式,传入多个参数时保留原有参数传入的逻辑。

原代码

import random as rand
import heapq

class die:
    def __init__(self, num:int, die:int | str, mod:int=0, keep:int=None):
        keep = keep if keep != None else num
        if keep > num:  keep = num
        self.num, self.die, self.mod, self.keep = num, die, mod, keep
    def __repr__(self) -> str:
        mod = f"+{self.mod}" if self.mod > 0 else f"-{abs(self.mod)}" if self.mod < 0 else ''
        keep = f"{f"{self.keep}kh" if self.keep > 0 else f"{abs(self.keep)}kl" if self.keep < 0 else ''}"
        return f"{keep}{self.num}d{self.die}{mod}"
    def roll(self) -> int:
        log = []
        die = range(0, self.num)
        for _ in die:
            log += [rand.randint(0, (10 if self.die == '%' else int(self.die)) * (10 if self.die == '%' else 1))]
        if self.keep > 0:
            log = [log] + [heapq.nlargest(self.keep, log)]
        elif self.keep < 0:
            log = [log] + [heapq.nsmallest(abs(self.keep), log)]
        final = sum(log[1], self.mod)
        return final
#Sorry if my code is hard to read.

实现方案

通过修改__init__方法的参数处理逻辑,结合正则表达式解析骰子表达式来实现需求,同时修正原代码中的部分逻辑错误。

修改后的完整代码

import random as rand
import heapq
import re

class die:
    def __init__(self, *args):
        # 处理单参数表达式情况
        if len(args) == 1 and isinstance(args[0], str):
            expr = args[0]
            # 正则匹配支持带keep的骰子表达式(如2kh4d6+3、3kl5d%-2)
            pattern = re.compile(r'^(?P<keep>(-?\d+[khl])?)?(?P<num>\d+)d(?P<die>\d+|%)(?P<mod>[+-]\d+)?$')
            match = pattern.match(expr)
            if not match:
                raise ValueError(f"无效的骰子表达式: {expr}")
            
            keep_str = match.group('keep')
            num = int(match.group('num'))
            die_type = match.group('die')
            mod_str = match.group('mod')
            
            # 解析keep参数
            keep = num
            if keep_str:
                keep_num = int(keep_str[:-2])
                keep_type = keep_str[-2:]
                keep = keep_num if keep_type == 'kh' else -keep_num
                # 确保keep值不超出骰子数量
                if abs(keep) > num:
                    keep = num if keep > 0 else -num
            
            # 解析修正值参数
            mod = int(mod_str) if mod_str else 0
            
            self.num, self.die, self.mod, self.keep = num, die_type, mod, keep
        
        # 处理多参数原有逻辑
        else:
            if len(args) < 2:
                raise TypeError("至少需要传入num和die两个参数,或一个合法的骰子表达式")
            num, die_type = args[0], args[1]
            mod = args[2] if len(args) >=3 else 0
            keep = args[3] if len(args) >=4 else None
            
            keep = keep if keep is not None else num
            if keep > num:
                keep = num
            self.num, self.die, self.mod, self.keep = num, die_type, mod, keep
    
    def __repr__(self) -> str:
        mod = f"+{self.mod}" if self.mod > 0 else f"-{abs(self.mod)}" if self.mod < 0 else ''
        keep_str = f"{self.keep}kh" if self.keep > 0 else f"{abs(self.keep)}kl" if self.keep < 0 else ''
        return f"{keep_str}{self.num}d{self.die}{mod}"
    
    def roll(self) -> int:
        log = []
        # 修正骰子范围:符合常规规则(d6为1-6,d%为1-100)
        die_max = 100 if self.die == '%' else int(self.die)
        for _ in range(self.num):
            log.append(rand.randint(1, die_max))
        
        # 处理保留骰子逻辑
        if self.keep > 0:
            kept = heapq.nlargest(self.keep, log)
        elif self.keep < 0:
            kept = heapq.nsmallest(abs(self.keep), log)
        else:
            kept = log
        
        # 修正求和逻辑:原代码sum用法错误
        final = sum(kept) + self.mod
        return final

关键说明

  1. 参数处理逻辑:

    • 用*args接收可变参数,判断参数数量和类型:单个字符串参数触发表达式解析,多参数则沿用原有逻辑。
    • 参数不合法时抛出对应异常,确保输入有效性。
  2. 表达式解析支持:

    • 兼容多种格式:
      • 基础格式:4d6、3d%、2d8+5、5d10-2
      • 带保留规则的格式:2kh4d6(掷4个d6保留最大2个)、3kl5d%+1(掷5个d%保留最小3个加1)
  3. 原代码问题修正:

    • 掷骰子范围:将原代码的0起始改为1起始,符合常规骰子规则。
    • 求和逻辑:修正sum函数的错误用法,改为正确的累加方式。
    • 代码可读性:简化掷骰记录的处理逻辑,提升代码清晰度。

使用示例

# 用表达式初始化
d1 = die("2kh4d6+3")
print(d1)  # 输出: 2kh4d6+3
print(d1.roll())  # 输出保留最大2个4d6的和加3

# 用原有参数初始化
d2 = die(3, 8, -2, 2)
print(d2)  # 输出: 2kh3d8-2
print(d2.roll())  # 输出保留最大2个3d8的和减2

内容的提问来源于stack exchange,提问作者Mildly Intelligent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 09:53:14