wikihop-server / cli.py
stillerman's picture
stillerman HF Staff
reorganizing
2c2bab6
# 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 <wiki_data_path>")
sys.exit(1)
wiki_data_path = sys.argv[1]
game = WikiRunCLI(wiki_data_path)
game.play()