# Rich CLI interface for the Wiki Run game from rich.console import Console from rich.panel import Panel from rich.markdown import Markdown from rich.prompt import Prompt from rich.table import Table from engine import WikiRunEnvironment from BFS_solver import WikiSolver console = Console() class WikiRunCLI: def __init__(self, wiki_data_path): """Initialize the CLI interface""" self.env = WikiRunEnvironment(wiki_data_path) self.console = Console() def _display_article(self, state): """Display the current article with highlighted links""" title = state['current_article'] text = state['article_text'] links = state['available_links'] # Create a panel with article title console.print(Panel(f"[bold cyan]{title}[/bold cyan]", expand=False, border_style="cyan")) # Display article text with highlighted links # In a real implementation, we'd need to properly format # the links within the text, but for MVP this is simpler md = Markdown(text) console.print(md) # Display available links console.print("\n[bold green]Available Links:[/bold green]") # Create a table for links (3 columns) table = Table(show_header=False, box=None) table.add_column("Link 1", style="green") table.add_column("Link 2", style="green") table.add_column("Link 3", style="green") # Add links to table (3 per row) row = [] for i, link in enumerate(links): # Check if link is available in the current article is_available = self.env.article_exists(link) color = "green" if is_available else "red" row.append(f"[{color}]{i+1}. {link}[/{color}]") if len(row) == 3: table.add_row(*row) row = [] # Add any remaining links if row: table.add_row(*row + [''] * (3 - len(row))) console.print(table) def _display_game_info(self, state): """Display game information""" console.print("\n[bold yellow]Game Info:[/bold yellow]") console.print(f"Target Article: [bold red]{state['target_article']}[/bold red]") console.print(f"Steps Taken: [bold]{state['steps_taken']}[/bold]") console.print(f"Path: [italic]{' → '.join(state['path_taken'])}[/italic]") def play(self): """Main game loop""" console.clear() console.print("[bold]Welcome to Wiki Run![/bold]") console.print("Navigate from one Wikipedia article to another using only links.\n") # Let user choose between random articles, specific ones, or solver mode choice = Prompt.ask("Choose mode: [bold]r[/bold]andom articles, [bold]s[/bold]pecific ones, or [bold]p[/bold]ath solver?", choices=["r", "s", "p"], default="r") if choice == "p": # Solver mode available_articles = self.env.db.get_all_article_titles() console.print(f"Available articles: {len(available_articles)}") # Show a sample of available articles import random sample = random.sample(available_articles, min(10, len(available_articles))) console.print("Sample articles:") for article in sample: console.print(f"- {article}") start = Prompt.ask("Start article") target = Prompt.ask("Target article") # Initialize solver and find path solver = WikiSolver(self.env) path, error = solver.find_path(start, target) if error: console.print(f"[red]{error}[/red]") else: solver.display_solution(path, start, target) play_again = Prompt.ask("Try another path? (y/n)", choices=["y", "n"], default="y") if play_again == "y": self.play() return if choice == "r": state = self.env.reset() else: # Get start and target articles available_articles = self.env.db.get_all_article_titles() console.print(f"Available articles: {len(available_articles)}") # Show a sample of available articles import random sample = random.sample(available_articles, min(10, len(available_articles))) console.print("Sample articles:") for article in sample: console.print(f"- {article}") start = Prompt.ask("Start article") target = Prompt.ask("Target article") state = self.env.reset(start, target) # Main game loop while not state['is_complete']: console.clear() self._display_article(state) self._display_game_info(state) # Get user input choice = Prompt.ask("\nChoose a link (number) or type part of a link name", default="") # Process input links = state['available_links'] next_article = None try: # Check if input is a number idx = int(choice) - 1 if 0 <= idx < len(links): next_article = links[idx] except ValueError: # Input is text, find closest match matches = [link for link in links if choice.lower() in link.lower()] if len(matches) == 1: next_article = matches[0] elif len(matches) > 1: console.print("[yellow]Multiple matches found:[/yellow]") for i, match in enumerate(matches): console.print(f"{i+1}. {match}") sub_choice = Prompt.ask("Choose a match (number)", default="1") try: idx = int(sub_choice) - 1 if 0 <= idx < len(matches): next_article = matches[idx] except ValueError: pass if next_article: state, message = self.env.step(next_article) if message: console.print(f"[bold]{message}[/bold]") if state['is_complete']: break else: console.print("[red]Invalid choice. Try again.[/red]") console.input("\nPress Enter to continue...") # Game complete console.clear() console.print("[bold green]Congratulations! You've reached the target article![/bold green]") console.print(f"You took [bold]{state['steps_taken']}[/bold] steps.") console.print(f"Your path: [italic]{' → '.join(state['path_taken'])}[/italic]") play_again = Prompt.ask("Play again? (y/n)", choices=["y", "n"], default="y") if play_again == "y": self.play() if __name__ == "__main__": import sys if len(sys.argv) < 2: console.print("[red]Please provide the path to Wikipedia data[/red]") console.print("Usage: python cli.py ") sys.exit(1) wiki_data_path = sys.argv[1] game = WikiRunCLI(wiki_data_path) game.play()