diff options
| author | 2025-10-06 00:38:33 +0800 | |
|---|---|---|
| committer | 2025-10-06 00:38:33 +0800 | |
| commit | 3649653bde885371833a33e7265a3b3e76852122 (patch) | |
| tree | 183723d19a12056f945bd40dfc6f88ad4f1e3455 | |
| parent | 6ba44621ae1b289e07562108164bd0419ccf6d75 (diff) | |
| download | OneRoll-3649653bde885371833a33e7265a3b3e76852122.tar.gz OneRoll-3649653bde885371833a33e7265a3b3e76852122.zip | |
style: format code and improve docstrings for consistency
| -rw-r--r-- | docs/source/config.py | 24 | ||||
| -rw-r--r-- | src/oneroll/__init__.py | 19 | ||||
| -rw-r--r-- | src/oneroll/__main__.py | 198 | ||||
| -rw-r--r-- | src/oneroll/_core.pyi | 303 | ||||
| -rw-r--r-- | src/oneroll/tui.py | 95 |
5 files changed, 317 insertions, 322 deletions
diff --git a/docs/source/config.py b/docs/source/config.py index fa4794e..83c0158 100644 --- a/docs/source/config.py +++ b/docs/source/config.py @@ -10,9 +10,11 @@ if sys.version_info >= (3, 11): else: import tomli as tomllib + def setup(app): - app.add_config_value('releaselevel', '', 'env') - + app.add_config_value("releaselevel", "", "env") + + DATA = None PYPROJECT = os.path.join("..", "..", "Cargo.toml") with open(PYPROJECT, "r", encoding="utf8") as f: @@ -55,17 +57,17 @@ extensions = [ "myst_parser", ] -doctest_global_setup = ''' +doctest_global_setup = """ try: import hydro_roll as hr import hydro_roll_core as hrc except ImportError: hr = None hrc = None -''' +""" todo_include_todos = True todo_emit_warnings = True -intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} templates_path = ["_templates"] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] extlinks = { @@ -90,13 +92,13 @@ rst_epilog = """ locale_dirs = ["../locales/"] # path is example but recommended. gettext_compact = False # optional. gettext_uuid = True # optional. -numfig = True # Figures, tables and code blocks are automatically numbered if they have a title -pygments_style = "rrt" # default sphinx, change the style of code block -math_number_all = True # Number all equations, figures, tables and code blocks +numfig = True # Figures, tables and code blocks are automatically numbered if they have a title +pygments_style = "rrt" # default sphinx, change the style of code block +math_number_all = True # Number all equations, figures, tables and code blocks html_additional_pages = { - 'copy': 'copying.html', + "copy": "copying.html", } -html_split_index = True # Split the index page by each alphabet +html_split_index = True # Split the index page by each alphabet # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output @@ -146,4 +148,4 @@ html_theme_options = { # html_sidebars = { # '**': ['globaltoc.html', 'sourcelink.html', 'searchbox.html', 'relations.html'], # 'using/windows': ['windowssidebar.html', 'searchbox.html'], -# }
\ No newline at end of file +# } diff --git a/src/oneroll/__init__.py b/src/oneroll/__init__.py index 5dddfad..cd42d60 100644 --- a/src/oneroll/__init__.py +++ b/src/oneroll/__init__.py @@ -11,17 +11,17 @@ Main functions: - Bracket support - Complete error handling -Example of usage: -# Basic use -import oneroll -result = oneroll.roll("3d6 + 2") -print(result.total) # output total points +Example of usage: +# Basic use +import oneroll +result = oneroll.roll("3d6 + 2") +print(result.total) # output total points -# Use the OneRoll class -roller = oneroll.OneRoll() -result = roller.roll("4d6kh3") +# Use the OneRoll class +roller = oneroll.OneRoll() +result = roller.roll("4d6kh3") -# Simple throw +# Simple throw total = oneroll.roll_simple(3, 6) """ @@ -36,6 +36,7 @@ __version__ = "1.3.2" __author__ = "HsiangNianian" __description__ = "高性能骰子表达式解析器" + # 重新导出主要类和函数,提供更友好的接口 class OneRoll: """ diff --git a/src/oneroll/__main__.py b/src/oneroll/__main__.py index 7ac50f4..04bfff9 100644 --- a/src/oneroll/__main__.py +++ b/src/oneroll/__main__.py @@ -4,14 +4,14 @@ OneRoll interactive dice roll program Supports command line parameters and interactive mode. -Example of usage: -# Direct throw -python -m oneroll "3d6 + 2" +Example of usage: +# Direct throw +python -m oneroll "3d6 + 2" -# Interactive mode -python -m oneroll +# Interactive mode +python -m oneroll -# Statistical Mode +# Statistical Mode python -m oneroll --stats "3d6" --times 100 """ @@ -30,23 +30,24 @@ import oneroll console = Console() + class OneRollCLI: """OneRoll command line interface""" - + def __init__(self): self.roller = OneRoll() self.history: List[Dict[str, Any]] = [] - + def print_result(self, result: Dict[str, Any], expression: str = None): """Pretty print the dice roll result""" if expression is None: - expression = result.get('expression', 'Unknown') - + expression = result.get("expression", "Unknown") + # Create result panel - total = result['total'] - details = result['details'] - rolls = result['rolls'] - + total = result["total"] + details = result["details"] + rolls = result["rolls"] + # Select color based on result value if total >= 15: color = "green" @@ -54,65 +55,65 @@ class OneRollCLI: color = "yellow" else: color = "red" - + # Build display text text = Text() text.append(f"🎲 {expression}\n", style="bold blue") text.append(f"总点数: ", style="bold") text.append(f"{total}", style=f"bold {color}") text.append(f"\n详情: {details}", style="white") - + if rolls: text.append(f"\n投掷结果: ", style="bold") text.append(f"{rolls}", style="cyan") - + # Display comment comment = result.get("comment", "") if comment: text.append(f"\n注释: ", style="bold") text.append(f"{comment}", style="italic blue") - + panel = Panel(text, title="Dice Roll Result", border_style=color) console.print(panel) - + def print_statistics(self, stats: Dict[str, Any], expression: str): """Print statistics information""" table = Table(title=f"统计结果: {expression} (投掷 {stats['count']} 次)") table.add_column("统计项", style="cyan") table.add_column("数值", style="green") - - table.add_row("最小值", str(stats['min'])) - table.add_row("最大值", str(stats['max'])) + + table.add_row("最小值", str(stats["min"])) + table.add_row("最大值", str(stats["max"])) table.add_row("平均值", f"{stats['mean']:.2f}") - table.add_row("总和", str(stats['total'])) - table.add_row("投掷次数", str(stats['count'])) - + table.add_row("总和", str(stats["total"])) + table.add_row("投掷次数", str(stats["count"])) + console.print(table) - + def print_history(self): """Print dice roll history""" if not self.history: console.print("暂无投掷历史", style="yellow") return - + table = Table(title="投掷历史") table.add_column("序号", style="cyan") table.add_column("表达式", style="green") table.add_column("总点数", style="yellow") table.add_column("注释", style="blue") table.add_column("详情", style="white") - + for i, result in enumerate(self.history[-10:], 1): # only show last 30 times table.add_row( str(i), - result.get('expression', 'Unknown'), - str(result['total']), - result.get('comment', ''), - result['details'] + result.get("expression", "Unknown"), + str(result["total"]), + result.get("comment", ""), + result["details"], ) - + console.print(table) - + def show_help(self): """show help information""" help_text = """ @@ -144,41 +145,41 @@ class OneRollCLI: • disadvantage - 2d20kl1 (劣势) • attribute - 4d6kh3 (属性投掷) """ - + console.print(Panel(help_text, title="帮助信息", border_style="blue")) - + def interactive_mode(self): """Interactive Mode""" console.print(Panel.fit("🎲 OneRoll 交互式掷骰程序", style="bold blue")) console.print("输入 'help' 查看帮助,输入 'quit' 退出程序\n") - + while True: try: user_input = Prompt.ask("🎲 请输入骰子表达式").strip() - + if not user_input: continue - + # handle special command - if user_input.lower() in ['quit', 'exit', 'q']: + if user_input.lower() in ["quit", "exit", "q"]: if Confirm.ask("确定要退出吗?"): break continue - - if user_input.lower() == 'help': + + if user_input.lower() == "help": self.show_help() continue - - if user_input.lower() == 'history': + + if user_input.lower() == "history": self.print_history() continue - - if user_input.lower() == 'clear': + + if user_input.lower() == "clear": self.history.clear() console.print("历史已清空", style="green") continue - - if user_input.lower().startswith('stats '): + + if user_input.lower().startswith("stats "): parts = user_input.split() if len(parts) >= 3: expression = parts[1] @@ -187,16 +188,18 @@ class OneRollCLI: if times > 1000: console.print("统计次数不能超过1000次", style="red") continue - + with Progress( SpinnerColumn(), TextColumn("[progress.description]{task.description}"), - console=console + console=console, ) as progress: - task = progress.add_task(f"正在统计 {expression}...", total=None) + task = progress.add_task( + f"正在统计 {expression}...", total=None + ) stats = roll_statistics(expression, times) progress.stop() - + self.print_statistics(stats, expression) except ValueError: console.print("统计次数必须是数字", style="red") @@ -205,10 +208,10 @@ class OneRollCLI: else: console.print("用法: stats <表达式> <次数>", style="red") continue - + # resolve regular expression's alias expression = self._resolve_expression_alias(user_input) - + # execute roll try: result = roll(expression) @@ -216,39 +219,42 @@ class OneRollCLI: self.print_result(result, user_input) except Exception as e: console.print(f"错误: {e}", style="red") - + except KeyboardInterrupt: if Confirm.ask("\n确定要退出吗?"): break except EOFError: break - + def _resolve_expression_alias(self, user_input: str) -> str: """resolve regular expression's alias""" aliases = { - 'd20': CommonRolls.D20, - 'advantage': CommonRolls.D20_ADVANTAGE, - 'disadvantage': CommonRolls.D20_DISADVANTAGE, - 'attr': CommonRolls.ATTRIBUTE_ROLL, - 'attribute': CommonRolls.ATTRIBUTE_ROLL, + "d20": CommonRolls.D20, + "advantage": CommonRolls.D20_ADVANTAGE, + "disadvantage": CommonRolls.D20_DISADVANTAGE, + "attr": CommonRolls.ATTRIBUTE_ROLL, + "attribute": CommonRolls.ATTRIBUTE_ROLL, } - + return aliases.get(user_input.lower(), user_input) - + def run(self, args): """run tui mode""" if args.tui: # start tui try: from .tui import run_tui + run_tui() except ImportError: - console.print("TUI 模式需要安装 textual: pip install textual", style="red") + console.print( + "TUI 模式需要安装 textual: pip install textual", style="red" + ) sys.exit(1) except Exception as e: console.print(f"TUI 启动失败: {e}", style="red") sys.exit(1) - + elif args.expression: # single roll mode try: @@ -257,7 +263,7 @@ class OneRollCLI: except Exception as e: console.print(f"错误: {e}", style="red") sys.exit(1) - + elif args.stats: # stats mode try: @@ -265,25 +271,26 @@ class OneRollCLI: if times > 10000: console.print("统计次数不能超过10000次", style="red") sys.exit(1) - + with Progress( SpinnerColumn(), TextColumn("[progress.description]{task.description}"), - console=console + console=console, ) as progress: task = progress.add_task(f"正在统计 {args.stats}...", total=None) stats = roll_statistics(args.stats, times) progress.stop() - + self.print_statistics(stats, args.stats) except Exception as e: console.print(f"错误: {e}", style="red") sys.exit(1) - + else: # interactive mode self.interactive_mode() + def main(): parser = argparse.ArgumentParser( description="OneRoll 骰子表达式解析器", @@ -294,43 +301,24 @@ def main(): %(prog)s --stats "3d6" --times 100 # 统计模式 %(prog)s --tui # 终端用户界面 %(prog)s # 交互式模式 - """ + """, ) - - parser.add_argument( - 'expression', - nargs='?', - help='骰子表达式,如 "3d6 + 2"' - ) - - parser.add_argument( - '--stats', - help='统计模式,指定要统计的表达式' - ) - - parser.add_argument( - '--times', - type=int, - default=100, - help='统计次数,默认100次' - ) - - parser.add_argument( - '--version', - action='version', - version=oneroll.__version__ - ) - - parser.add_argument( - '--tui', - action='store_true', - help='启动终端用户界面 (TUI)' - ) - + + parser.add_argument("expression", nargs="?", help='骰子表达式,如 "3d6 + 2"') + + parser.add_argument("--stats", help="统计模式,指定要统计的表达式") + + parser.add_argument("--times", type=int, default=100, help="统计次数,默认100次") + + parser.add_argument("--version", action="version", version=oneroll.__version__) + + parser.add_argument("--tui", action="store_true", help="启动终端用户界面 (TUI)") + args = parser.parse_args() - + cli = OneRollCLI() cli.run(args) -if __name__ == '__main__': - main()
\ No newline at end of file + +if __name__ == "__main__": + main() diff --git a/src/oneroll/_core.pyi b/src/oneroll/_core.pyi index 7916261..d81297d 100644 --- a/src/oneroll/_core.pyi +++ b/src/oneroll/_core.pyi @@ -5,185 +5,183 @@ RollHistory = List[DiceResult] ModifierList = List[str] def roll_dice(expression: str) -> DiceResult: - """ - Analyze and calculate dice expressions - - Args: - expression: Dice expression string, supports the following formats: - - Basic dice: "3d6", "1d20", "2d10" - - Mathematical operations: "3d6 + 2", "2d6 * 3", "(2d6 + 3) * 2" - - Modifiers: "2d6!", "4d6kh3", "5d6dl1", "3d6r1", "4d6ro1" - - Returns: - A dictionary containing the following keys: - - expression: str - expression string - - total: int - Total points - - rolls: List[List[int]] - List of throw results - - details: str - details - - comment: str - User comment - - Raises: - ValueError: When the expression is invalid - - Example: - result = roll_dice("3d6 + 2") - print(result["total"]) # output total points + """ + Analyze and calculate dice expressions + + Args: + expression: Dice expression string, supports the following formats: + - Basic dice: "3d6", "1d20", "2d10" + - Mathematical operations: "3d6 + 2", "2d6 * 3", "(2d6 + 3) * 2" + - Modifiers: "2d6!", "4d6kh3", "5d6dl1", "3d6r1", "4d6ro1" + + Returns: + A dictionary containing the following keys: + - expression: str - expression string + - total: int - Total points + - rolls: List[List[int]] - List of throw results + - details: str - details + - comment: str - User comment + + Raises: + ValueError: When the expression is invalid + + Example: + result = roll_dice("3d6 + 2") + print(result["total"]) # output total points """ ... def roll_simple(dice_count: int, dice_sides: int) -> int: - """ - Simple dice throw + """ + Simple dice throw - Args: - dice_count: The number of dice must be greater than 0 - dice_sides: The number of dice faces must be greater than 0 + Args: + dice_count: The number of dice must be greater than 0 + dice_sides: The number of dice faces must be greater than 0 - Returns: - Total points + Returns: + Total points - Raises: - ValueError: When the parameter is invalid + Raises: + ValueError: When the parameter is invalid - Example: - total = roll_simple(3, 6) # Roll 3 6-sided dice + Example: + total = roll_simple(3, 6) # Roll 3 6-sided dice """ ... class OneRoll: - """ - OneRoll dice thrower category + """ + OneRoll dice thrower category - Provides an object-oriented dice throwing interface, supporting complex expressions and various modifiers. + Provides an object-oriented dice throwing interface, supporting complex expressions and various modifiers. """ - + def __init__(self) -> None: """ Initialize OneRoll Object - + Example: roller = OneRoll() """ ... - + def roll(self, expression: str) -> DiceResult: - """ - Analyze and calculate dice expressions - - Args: - expression: Dice expression string, supports the following formats: - - Basic dice: "3d6", "1d20", "2d10" - - Mathematical operations: "3d6 + 2", "2d6 * 3", "(2d6 + 3) * 2" - - Modifiers: "2d6!", "4d6kh3", "5d6dl1", "3d6r1", "4d6ro1" - - Returns: - A dictionary containing the following keys: - - expression: str - expression string - - total: int - Total points - - rolls: List[List[int]] - List of throw results - - details: str - details - - comment: str - User comment - - Raises: - ValueError: When the expression is invalid - - Example: - roller = OneRoll() - result = roller.roll("3d6 + 2") - print(f"Total points: {result['total']}") + """ + Analyze and calculate dice expressions + + Args: + expression: Dice expression string, supports the following formats: + - Basic dice: "3d6", "1d20", "2d10" + - Mathematical operations: "3d6 + 2", "2d6 * 3", "(2d6 + 3) * 2" + - Modifiers: "2d6!", "4d6kh3", "5d6dl1", "3d6r1", "4d6ro1" + + Returns: + A dictionary containing the following keys: + - expression: str - expression string + - total: int - Total points + - rolls: List[List[int]] - List of throw results + - details: str - details + - comment: str - User comment + + Raises: + ValueError: When the expression is invalid + + Example: + roller = OneRoll() + result = roller.roll("3d6 + 2") + print(f"Total points: {result['total']}") """ ... - + def roll_simple(self, dice_count: int, dice_sides: int) -> int: - """ - Simple dice throw + """ + Simple dice throw - Args: - dice_count: The number of dice must be greater than 0 - dice_sides: The number of dice faces must be greater than 0 + Args: + dice_count: The number of dice must be greater than 0 + dice_sides: The number of dice faces must be greater than 0 - Returns: - Total points + Returns: + Total points - Raises: - ValueError: When the parameter is invalid + Raises: + ValueError: When the parameter is invalid - Example: - roller = OneRoll() - total = roller.roll_simple(3, 6) # Throw 3 6-sided dice + Example: + roller = OneRoll() + total = roller.roll_simple(3, 6) # Throw 3 6-sided dice """ ... - + def roll_with_modifiers( - self, - dice_count: int, - dice_sides: int, - modifiers: ModifierList + self, dice_count: int, dice_sides: int, modifiers: ModifierList ) -> DiceResult: - """ - Dice throw with modifier - - Args: - dice_count: The number of dice must be greater than 0 - dice_sides: The number of dice faces must be greater than 0 - modifiers: modifier list, supports the following formats: - - "!" - Explosion dice - - "r<number>" - Re-submit, such as "r1" - - "ro<number>" - Conditional re-submission, such as "ro1" - - "kh<number>" - Take the height, such as "kh3" - - "kl<number>" - Take the low, such as "kl2" - - "dh<number>" - discard the height, such as "dh1" - - "dl<number>" - discard low, such as "dl1" - - Returns: - A dictionary containing the following keys: - - total: int - Total points - - rolls: List[List[int]] - List of throw results - - details: str - details - - Raises: - ValueError: When the parameter or modifier is invalid - - Example: - roller = OneRoll() - result = roller.roll_with_modifiers(4, 6, ["kh3"]) # 4d6kh3 - print(f"Total points: {result['total']}") + """ + Dice throw with modifier + + Args: + dice_count: The number of dice must be greater than 0 + dice_sides: The number of dice faces must be greater than 0 + modifiers: modifier list, supports the following formats: + - "!" - Explosion dice + - "r<number>" - Re-submit, such as "r1" + - "ro<number>" - Conditional re-submission, such as "ro1" + - "kh<number>" - Take the height, such as "kh3" + - "kl<number>" - Take the low, such as "kl2" + - "dh<number>" - discard the height, such as "dh1" + - "dl<number>" - discard low, such as "dl1" + + Returns: + A dictionary containing the following keys: + - total: int - Total points + - rolls: List[List[int]] - List of throw results + - details: str - details + + Raises: + ValueError: When the parameter or modifier is invalid + + Example: + roller = OneRoll() + result = roller.roll_with_modifiers(4, 6, ["kh3"]) # 4d6kh3 + print(f"Total points: {result['total']}") """ ... def is_valid_expression(expression: str) -> bool: - """ - Check if the expression is valid + """ + Check if the expression is valid - Args: - expression: The expression string to check + Args: + expression: The expression string to check - Returns: - Return True if the expression is valid, otherwise return False + Returns: + Return True if the expression is valid, otherwise return False - Example: - if is_valid_expression("3d6 + 2"): - result = roll_dice("3d6 + 2") + Example: + if is_valid_expression("3d6 + 2"): + result = roll_dice("3d6 + 2") """ ... def parse_expression(expression: str) -> Dict[str, Any]: - """ - Parses expressions but not throwing + """ + Parses expressions but not throwing - Args: - expression: The expression string to parse + Args: + expression: The expression string to parse - Returns: - Analytical results dictionary + Returns: + Analytical results dictionary - Raises: - ValueError: When the expression is invalid + Raises: + ValueError: When the expression is invalid """ ... class RollStatistics: """Throw statistics""" + min: int max: int mean: float @@ -192,47 +190,48 @@ class RollStatistics: results: List[int] def roll_multiple(expression: str, times: int) -> RollHistory: - """ - Throw the same expression multiple times + """ + Throw the same expression multiple times - Args: - expression: dice expression string - times: The number of throws must be greater than 0 + Args: + expression: dice expression string + times: The number of throws must be greater than 0 - Returns: - Throw result list + Returns: + Throw result list - Raises: - ValueError: When the parameter is invalid + Raises: + ValueError: When the parameter is invalid - Example: - results = roll_multiple("3d6", 10) - totals = [r["total"] for r in results] + Example: + results = roll_multiple("3d6", 10) + totals = [r["total"] for r in results] """ ... def roll_statistics(expression: str, times: int) -> RollStatistics: - """ - Statistics of multiple throws + """ + Statistics of multiple throws - Args: - expression: dice expression string - times: The number of throws must be greater than 0 + Args: + expression: dice expression string + times: The number of throws must be greater than 0 - Returns: - Object containing statistics + Returns: + Object containing statistics - Raises: - ValueError: When the parameter is invalid + Raises: + ValueError: When the parameter is invalid - Example: - stats = roll_statistics("3d6", 100) - print(f"Average: {stats.mean:.2f}") + Example: + stats = roll_statistics("3d6", 100) + print(f"Average: {stats.mean:.2f}") """ ... class CommonRolls: """Commonly used dice expression constants""" + D20: str D20_ADVANTAGE: str D20_DISADVANTAGE: str @@ -244,4 +243,4 @@ class CommonRolls: HIT_POINTS_D6: str HIT_POINTS_D8: str HIT_POINTS_D10: str - HIT_POINTS_D12: str
\ No newline at end of file + HIT_POINTS_D12: str diff --git a/src/oneroll/tui.py b/src/oneroll/tui.py index 9e4e4c9..fa0eb09 100644 --- a/src/oneroll/tui.py +++ b/src/oneroll/tui.py @@ -16,91 +16,91 @@ from datetime import datetime from . import OneRoll, roll, roll_statistics, CommonRolls + class RollResult(Message): """Throw result message""" - + def __init__(self, result: Dict[str, Any], expression: str) -> None: self.result = result self.expression = expression super().__init__() + class ExpressionInput(Input): """Expression input box""" - + def __init__(self) -> None: super().__init__( - placeholder="输入骰子表达式,如 3d6 + 2", - id="expression_input" + placeholder="输入骰子表达式,如 3d6 + 2", id="expression_input" ) - + def on_key(self, event) -> None: if event.key == "enter": self.post_message(RollResult(roll(self.value), self.value)) self.value = "" + class QuickRollButton(Button): """Quick Throw Button""" - + def __init__(self, label: str, expression: str) -> None: self.expression = expression super().__init__(label, id=f"quick_{expression}") - + def on_button_pressed(self) -> None: self.post_message(RollResult(roll(self.expression), self.expression)) + class RollHistory(DataTable): """Throw History Table""" - + def __init__(self) -> None: super().__init__() self.add_columns("时间", "表达式", "总点数", "详情") - + def add_roll(self, result: Dict[str, Any], expression: str) -> None: """Add throw record""" time_str = datetime.now().strftime("%H:%M:%S") - self.add_row( - time_str, - expression, - str(result["total"]), - result["details"] - ) + self.add_row(time_str, expression, str(result["total"]), result["details"]) # keep table at bottom self.scroll_end() + class StatisticsPanel(Static): """Statistics Panel""" - + def __init__(self) -> None: super().__init__("统计功能", id="stats_panel") - + def show_statistics(self, expression: str, times: int = 100) -> None: """Show statistics information""" try: stats = roll_statistics(expression, times) stats_text = f""" -统计结果: {expression} (投掷 {stats['count']} 次) +统计结果: {expression} (投掷 {stats["count"]} 次) -最小值: {stats['min']} -最大值: {stats['max']} -平均值: {stats['mean']:.2f} -总和: {stats['total']} +最小值: {stats["min"]} +最大值: {stats["max"]} +平均值: {stats["mean"]:.2f} +总和: {stats["total"]} """ self.update(stats_text) except Exception as e: self.update(f"统计错误: {e}") + class RollDisplay(Static): - """The throwing result shows """ - + """The throwing result shows""" + def __init__(self) -> None: super().__init__("等待投掷...", id="roll_display") - + def show_result(self, result: Dict[str, Any], expression: str) -> None: """Display throwing result""" total = result["total"] details = result["details"] rolls = result["rolls"] - + # a kind of color selection based on result if total >= 15: color = "green" @@ -108,7 +108,7 @@ class RollDisplay(Static): color = "yellow" else: color = "red" - + display_text = f"""[bold blue]🎲 {expression}[/bold blue] [bold]总点数:[/bold] [bold {color}]{total}[/bold {color}] @@ -119,13 +119,16 @@ class RollDisplay(Static): # show the comment comment = result.get("comment", "") if comment: - display_text += f"\n\n[bold]注释:[/bold] [italic blue]{comment}[/italic blue]" - + display_text += ( + f"\n\n[bold]注释:[/bold] [italic blue]{comment}[/italic blue]" + ) + self.update(display_text) + class OneRollTUI(App): """OneRoll 终端用户界面""" - + CSS = """ Screen { layout: vertical; @@ -163,14 +166,14 @@ class OneRollTUI(App): margin: 1; } """ - + def compose(self) -> ComposeResult: """UI components""" yield Header() - + with Container(): yield ExpressionInput() - + with Horizontal(classes="quick_buttons"): yield QuickRollButton("D20", CommonRolls.D20) yield QuickRollButton("优势", CommonRolls.D20_ADVANTAGE) @@ -178,35 +181,35 @@ class OneRollTUI(App): yield QuickRollButton("属性", CommonRolls.ATTRIBUTE_ROLL) yield QuickRollButton("3D6", "3d6") yield QuickRollButton("2D6", "2d6") - + yield RollDisplay() - + with Tabs(): with Tab("历史记录", id="history_tab"): yield RollHistory(id="history_table") - + with Tab("统计", id="stats_tab"): yield StatisticsPanel() - + yield Footer() - + def on_mount(self) -> None: """Initialization during interface mount""" self.title = "OneRoll 骰子投掷器" self.sub_title = "高性能骰子表达式解析器" - + # Set focus to the input box self.query_one(ExpressionInput).focus() - + def on_roll_result(self, message: RollResult) -> None: # display result roll_display = self.query_one(RollDisplay) roll_display.show_result(message.result, message.expression) - + # add history history_table = self.query_one(RollHistory) history_table.add_roll(message.result, message.expression) - + def on_key(self, event) -> None: if event.key == "ctrl+q": self.exit() @@ -214,7 +217,7 @@ class OneRollTUI(App): self.show_help() elif event.key == "ctrl+s": self.show_statistics() - + def show_help(self) -> None: help_text = """ OneRoll 骰子投掷器 @@ -237,15 +240,17 @@ OneRoll 骰子投掷器 • Ctrl+S - 显示统计 • Enter - 执行投掷 """ - + self.notify(help_text, title="帮助信息", timeout=10) - + def show_statistics(self) -> None: self.notify("统计功能开发中...", title="统计") + def run_tui(): app = OneRollTUI() app.run() + if __name__ == "__main__": run_tui() |
