如何为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
关键说明
参数处理逻辑:
- 用
*args接收可变参数,判断参数数量和类型:单个字符串参数触发表达式解析,多参数则沿用原有逻辑。 - 参数不合法时抛出对应异常,确保输入有效性。
- 用
表达式解析支持:
- 兼容多种格式:
- 基础格式:
4d6、3d%、2d8+5、5d10-2 - 带保留规则的格式:
2kh4d6(掷4个d6保留最大2个)、3kl5d%+1(掷5个d%保留最小3个加1)
- 基础格式:
- 兼容多种格式:
原代码问题修正:
- 掷骰子范围:将原代码的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
相关产品推荐
相关产品推荐

