diff options
Diffstat (limited to 'src/oneroll/__main__.py')
| -rw-r--r-- | src/oneroll/__main__.py | 198 |
1 files changed, 93 insertions, 105 deletions
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() |
