File size: 7,737 Bytes
fa70ae5
 
 
 
 
 
 
2c2bab6
 
fa70ae5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
930b95e
4432909
930b95e
 
fa70ae5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44bd370
 
 
fa70ae5
 
44bd370
 
4432909
44bd370
 
 
 
 
 
 
 
 
 
 
 
 
4432909
44bd370
 
 
 
 
 
 
 
 
 
 
 
fa70ae5
 
 
 
4432909
fa70ae5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# 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()