diff options
Diffstat (limited to 'tests/examples/ndice/src/dicer.py')
| -rw-r--r-- | tests/examples/ndice/src/dicer.py | 360 |
1 files changed, 0 insertions, 360 deletions
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) |
