From ec4566c3d17370c778a1e6cd6b22ed85263731a0 Mon Sep 17 00:00:00 2001 From: HsiangNianian Date: Sat, 2 Aug 2025 11:30:27 +0800 Subject: refactor(v3): publish v3 branch --- tests/examples/ndice/src/dicer.py | 360 -------------------------------------- tests/examples/ndice/src/ndice.py | 156 ----------------- 2 files changed, 516 deletions(-) delete mode 100644 tests/examples/ndice/src/dicer.py delete mode 100644 tests/examples/ndice/src/ndice.py (limited to 'tests/examples/ndice/src') diff --git a/tests/examples/ndice/src/dicer.py b/tests/examples/ndice/src/dicer.py deleted file mode 100644 index 74bb3714..00000000 --- a/tests/examples/ndice/src/dicer.py +++ /dev/null @@ -1,360 +0,0 @@ -from multilogging import multilogger -from typing import List - -import abc -import re -import random - - -ZERO = 0 -EMPTY_STRING = "" -EMPTY_LIST = [] - -logger = multilogger(name="DicerGirl", payload="Dicer") - - -class BaseDice: - def __init__(self, roll_string: str = EMPTY_STRING) -> None: - self.roll_string = roll_string - self.db = EMPTY_STRING - self.outcome = ZERO - self.display = EMPTY_LIST - - def __repr__(self) -> str: - return self.db.upper() - - @abc.abstractmethod - def parse(self) -> "BaseDice": - raise NotImplementedError - - @abc.abstractmethod - def roll(self) -> int: - """对骰子进行投掷并给出结果""" - raise NotImplementedError - - -class DigitDice(BaseDice): - """数字骰""" - - def __init__(self, roll_string: str = EMPTY_STRING) -> None: - super().__init__(roll_string=roll_string) - if not roll_string.isdigit(): - raise ValueError - - self.parse() - - def parse(self) -> "DigitDice": - self.a = int(self.roll_string) - self.b = 1 - self.db = f"{self.a}" - return self - - def roll(self) -> int: - self.outcome = self.a - self.display = [self.a] - return self.outcome - - -class Dice(BaseDice): - """多面骰""" - - def __init__(self, roll_string: str = "", explode: bool = False) -> None: - super().__init__(roll_string=roll_string) - self.dices = EMPTY_LIST - self.great = False - self.explode = explode - self.parse() - - def parse(self) -> "Dice": - self.dices = [] - split = re.split(r"[dD]", self.roll_string) - - if split[0]: - self.a = int(split[0]) - else: - self.a = 1 - - if split[1]: - self.b = int(split[1]) - else: - self.b = 100 - - self.db = f"{self.a}D{self.b}" - self.dices += [f"D{self.b}"] * self.a - return self - - def roll(self) -> int: - self.results = [] - self.display = [] - - for _ in range(self.a): - result = random.randint(1, self.b) - - if result == 1 and self.explode: - result -= 1 - - if self.explode and self.b == 8: - self.dices.append("D10") - result2 = random.randint(1, 10) - if result2 == 1: - result -= 1 - result += result2 - if result2 == 10: - self.dices.append("D12") - result3 = random.randint(1, 12) - if result3 == 1: - result -= 1 - result += result3 - if result3 == 12: - self.dices.append("D20") - result4 = random.randint(1, 20) - if result4 == 1: - result -= 1 - result += result4 - if result4 == 20: - self.great = True - - self.results.append(result) - self.display.append(result) - - self.outcome = sum(self.results) - return self.outcome - - -class AwardDice(BaseDice): - """奖励骰""" - - def __init__(self, roll_string: str = "") -> None: - super().__init__(roll_string=roll_string) - self.parse() - - def parse(self) -> "AwardDice": - split = re.split(r"[bB]", self.roll_string) - - if split[0]: - self.a = int(split[0]) - else: - self.a = 1 - - self.b = int(split[1]) - self.db = f"{self.a}B{self.b}" - return self - - def roll(self) -> int: - self.results = [] - self.display = [] - - for _ in range(self.a): - ten = [] - for _ in range(self.b): - outcome = Dice("1d10").roll() - outcome = outcome if outcome != 10 else 0 - ten.append(outcome) - - result = Dice("1d100").roll() - ten.append(result // 10) - minten = min(ten) - ten.remove(result // 10) - outcome = minten * 10 + (result % 10) - self.results.append(outcome) - self.display.append([result, ten]) - - self.outcome = sum(self.results) - return self.outcome - - -class PunishDice(BaseDice): - """惩罚骰""" - - def __init__(self, roll_string: str = "") -> None: - super().__init__(roll_string=roll_string) - self.parse() - - def parse(self) -> "PunishDice": - split = re.split(r"[pP]", self.roll_string) - - if split[0]: - self.a = int(split[0]) - else: - self.a = 1 - - self.b = int(split[1]) - self.db = f"{self.a}P{self.b}" - return self - - def roll(self) -> int: - self.results = [] - self.display = [] - - for _ in range(self.a): - ten = [] - for _ in range(self.b): - outcome = Dice("1d10").roll() - outcome = outcome if outcome != 10 else 0 - ten.append(outcome) - - result = Dice("1d100").roll() - ten.append(result // 10) - maxten = max(ten) - ten.remove(result // 10) - outcome = maxten * 10 + (result % 10) - self.results.append(outcome) - self.display.append([result, ten]) - - self.outcome = sum(self.results) - return self.outcome - - -class Dicer: - """掷骰类 - 参数: - roll_string: 标准掷骰表达式 - explode: 是否启用爆炸骰 - 示例: - ```python - dice = Dice("1d10") - dice.roll() - print(dice.outcome) # 输出`1d10`投掷结果 - ``` - """ - - def __init__(self, roll_string: str = EMPTY_STRING, explode: bool = False) -> None: - self.roll_string: str = roll_string - self.explode: bool = explode - self.calc_list: List[str | Dice | DigitDice | AwardDice | PunishDice] = [] - self.results: List[int] = [] - self.display: List[int | List[int]] = [] - self.outcome: int = ZERO - self.great: bool = False - self.dices: List[str] = [] - - def parse(self, roll_string: str = EMPTY_STRING, explode: bool = False): - self.roll_string = roll_string if roll_string else self.roll_string - self.calc_list = [] - self.db = EMPTY_STRING - matches: List[str] = re.findall(r"\d*[a-zA-Z]\w*|\d+|[-+*/]", self.roll_string) - - for match in matches: - if match in ("+", "-", "*", "/", "(", ")"): - self.calc_list.append(match) - self.db += match - elif re.match(r"\d*[dD]\d*", match): - self.calc_list.append(Dice(match, explode=explode)) - self.db += match.upper() - elif re.match(r"\d*[bB]\d+", match): - self.calc_list.append(AwardDice(match)) - self.db += match.upper() - elif re.match(r"\d*[pP]\d+", match): - self.calc_list.append(PunishDice(match)) - self.db += match.upper() - elif re.match(r"\d+", match): - self.calc_list.append(DigitDice(match)) - self.db += match.upper() - else: - raise ValueError(f"骰 {match} 不符合规范.") - - if not matches: - self.calc_list.append(Dice("1d100")) - self.db = "1D100" - - return self - - def roll(self): - self.parse(roll_string=self.roll_string, explode=self.explode) - self.dices = [] - self.display = [] - for index, calc in enumerate(self.calc_list): - if calc in ("+", "-", "*", "/", "(", ")"): - continue - - outcome = calc.roll() - self.calc_list[index] = outcome - self.results.append(outcome) - self.display += calc.display - - if isinstance(calc, Dice) and self.explode: - if calc.great: - self.great = True - - self.dices += calc.dices - - self.outcome = eval("".join(map(str, self.calc_list))) - return self - - def description(self): - def count_integers(lst: list) -> int: - count = 0 - for item in lst: - if isinstance(item, int): - count += 1 - elif isinstance(item, list): - count += count_integers(item) - return count - - results = self.display - len_display = count_integers(self.display) - len_results = count_integers(self.results) - - if len_display <= 10: - results = self.display - elif len_results <= 10: - results = self.results - else: - results = [...] - - return f"{self.db}={results}={self.outcome}" - - def get_results(self): - return self.results - - def detail_expr(self): - return str(self.results) - - def calc(self): - return self.outcome - - def __repr__(self): - return self.db - - -if __name__ == "__main__": - # text = "-10/d2/1d10+2d2-22/2+3p2+2b10-p4/b2/d2" - # dice = Dicer(text) - # print(dice.calc_list) - # dice.roll() - # print(dice.calc_list) - # print(dice.results) - # print(dice.outcome) - roll_strings = { - "1": 1, - "10": 10, - "100": 100, - "-1": -1, - "-10": -10, - "-100": -100, - "1d1": 1, - "10d1": 10, - "100d1": 100, - "10d1+10d1": 20, - "10d1-10d1": 0, - "10d1+10d1+10d1": 30, - "10d1-10d1+10d1": 10, - "10d1-10d1-10d1": -10, - } - for roll_string in roll_strings.keys(): - try: - dice = Dicer().parse(roll_string).roll().roll() - if dice.outcome != roll_strings[roll_string]: - print(dice.description()) - raise ValueError( - f"对于 {roll_string} dice.toal={dice.outcome} 但期待 {roll_strings[roll_string]}" - ) - except ValueError as error: - logger.exception(error) - - try: - roll_string = "d" - dice = Dicer(roll_string).roll() - print(dice.description()) - except ValueError as error: - logger.exception(error) diff --git a/tests/examples/ndice/src/ndice.py b/tests/examples/ndice/src/ndice.py deleted file mode 100644 index 082de9f8..00000000 --- a/tests/examples/ndice/src/ndice.py +++ /dev/null @@ -1,156 +0,0 @@ -# Initialized `__init__.py` generated by ipm. -# Documents at https://ipm.hydroroll.team/ - -from infini.register import Register -from infini.router import Startswith -from infini.input import Input -from infini.output import Output -from .dicer import Dicer - -import re - -register = Register() -register.register_textevent( - "ndice.roll", - "[{{ username }}]掷骰: " - "{% if descs|length == 1 %}" - "{{ descs[0] }}" - "{% else %}" - "{{ db }}=[...]=" - "{% for outcome in outcomes %}" - "{{ outcome }}" - "{% if not loop.last %}, {% endif %}" - "{% endfor %}" - "{% endif %}", -) -register.register_textevent( - "ndice.error.bad_roll_string", "[{{ username }}]掷骰时出现异常, 疑似掷骰表达式错误." -) -register.register_textevent("ndice.error.too_much_round", "[{{ username }}]给入的掷骰轮数超出预期.") -register.register_textevent( - "ndice.error.unknown", - "未知错误: {{ error }}, 可能是掷骰语法异常.\nBUG提交: https://gitee.com/unvisitor/issues", -) -register.register_textevent("ndice.error.bad_round", "多轮检定的轮数应当是整型数.") -register.register_textevent("ndice.error.too_much_round", "多轮检定的轮数超出预期.") - - -def translate_punctuation(string: str) -> str: - punctuation_mapping = { - ",": ",", - "。": ".", - "!": "!", - "?": "?", - ";": ";", - ":": ":", - "“": '"', - "”": '"', - "‘": "'", - "’": "'", - "(": "(", - ")": ")", - "【": "[", - "】": "]", - "《": "<", - "》": ">", - } - for ch_punct, en_punct in punctuation_mapping.items(): - string = string.replace(ch_punct, en_punct) - return string - - -def format_str(message: str, begin=None, lower=True) -> str: - regex = r"[<\[](.*?)[\]>]" - message = str(message).lower() if lower else str(message) - msg = translate_punctuation( - re.sub("\s+", " ", re.sub(regex, "", message)).strip(" ") - ) - if msg.startswith("/"): - msg = "." + msg[1:] - - if begin: - if isinstance(begin, str): - begin = [ - begin, - ] - elif isinstance(begin, tuple): - begin = list(begin) - - begin.sort(reverse=True) - for b in begin: - msg = msg.replace(b, "").lstrip(" ") - - return msg - - -def roll(_: Input, args: str, name: str = None) -> str: - time = 1 - if "#" in args: - args = args.split("#") - - try: - time = int(args[0].strip()) - if time > 20: - return Output( - "text", "ndice.error.too_much_round", variables={"username": name} - ) - except ValueError: - return Output("text", "ndice.error.bad_round", variables={"username": name}) - - if len(args) == 1: - args = "1d100" - else: - args = args[1] - else: - args = args.strip() - - args = args.split() - if len(args) > 1: - reason = args[1] - else: - reason = None - - roll_string = args[0] - descs = [] - outcomes = [] - - try: - dice = Dicer(roll_string).roll() - descs.append(dice.description()) - outcomes.append(dice.outcome) - - for _ in range(time - 1): - dice.roll() - descs.append(dice.description()) - outcomes.append(dice.outcome) - except ValueError: - return Output( - "text", - "ndice.error.bad_roll_string", - status=1, - variables={"username": name}, - ) - - return Output( - "text", - "ndice.roll", - variables={ - "username": name, - "descs": descs, - "outcomes": outcomes, - "db": dice.db, - }, - ) - - -@register.handler(router=Startswith(".r"), priority=0) -def roll_handler(input: Input): - args = format_str(input.get_plain_text(), begin=(".r", ".roll")) - name = input.variables.get("nickname") or "苏向夜" - if not args: - return roll(input, "1d100", name=name) - - try: - return roll(input, args, name=name) - except Exception as error: - return Output("text", "ndice.error.unknown", variables={"error": str(error)}) -- cgit v1.2.3-70-g09d2