File size: 11,542 Bytes
ad372ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
"""Main Streamlit application for Stratego Human vs AI"""

import streamlit as st
from stratego.web.config import session_manager, agent_builder, game_config
from stratego.web.game_controller import GameController
from stratego.web.components import game_history, status_panel
from stratego.web.components.interactive_board import render_interactive_board
from stratego.web.utils.validators import normalize_move


def screen_welcome():
    """Screen 0: Welcome and game mode selection"""
    st.title("โš”๏ธ STRATEGO - Human vs AI")
    st.markdown("*Challenge an intelligent AI opponent in the classic strategy game!*")

    st.divider()

    col1, col2 = st.columns([2, 1])

    with col1:
        st.subheader("๐ŸŽฎ How to Play")
        st.write("""

        **Objective:** Capture the enemy flag or eliminate all movable pieces



        **Your Setup:**

        - ๐Ÿ”ต Your army positioned at the **BOTTOM** of the board

        - Arrange your pieces strategically before the game starts

        - Each piece has a rank that determines its strength



        **Your Turn:**

        1. **Click on one of your pieces** (blue area at bottom)

        2. **Available destination squares will be highlighted** in green with a dot (โ—)

        3. **Click the destination** to move your piece there

        4. **Battles resolve automatically** when pieces meet



        **AI Opponent:**

        - ๐Ÿ”ด Enemy forces at the **TOP** of the board

        - Uses Mistral 7B LLM to make strategic decisions

        - Plays immediately after your move

        """)

        st.markdown("---")
        st.markdown("### โš™๏ธ Setup Requirements")
        with st.expander("๐Ÿ“ฆ Ollama Installation", expanded=False):
            st.code(
                """# Make sure you have Ollama running locally:

ollama serve



# In a new terminal, pull Mistral:

ollama pull mistral:7b



# Verify it's installed:

ollama list""",
                language="bash"
            )
            st.caption(
                "๐Ÿ’ก Ollama provides local LLM inference. "
                "Download: https://ollama.ai"
            )

    with col2:
        st.subheader("๐Ÿ“Š Game Info")
        selected_config = game_config.get_game_config(
            "Standard (10x10)"
        )
        st.metric("Board Size", "10 ร— 10")
        st.metric("Players", "2 (You vs AI)")
        st.metric("AI Model", "Mistral 7B")
        st.metric("Time/Move", "~2-5 sec")

        st.divider()

        st.subheader("๐ŸŽฏ Piece Legend")
        legend_data = {
            "๐Ÿšฉ": "Flag (0โ˜…) - Must protect!",
            "๐Ÿ’ฃ": "Bomb (0โ˜…) - Immovable",
            "๐Ÿ‘‘": "Marshal (10โ˜…) - Strongest",
            "โญ": "General (9โ˜…) - Second strongest",
            "๐Ÿƒ": "Scout (2โ˜…) - Can move multi-square",
            "๐Ÿ•ต๏ธ": "Spy (1โ˜…) - Defeats Marshal",
            "๐Ÿช–": "Sergeant (3โ˜…)",
            "๐Ÿ“": "Lieutenant (4โ˜…)",
            "๐ŸŽ–๏ธ": "Captain (6โ˜…)",
        }
        for emoji, desc in legend_data.items():
            st.caption(f"{emoji} {desc}")

    st.divider()

    # Game mode selection
    st.markdown("### ๐Ÿ•น๏ธ Start Your Battle")

    col1, col2 = st.columns([3, 1])

    with col1:
        st.markdown(
            "**Standard 10ร—10 with lakes**\n"
            "Classic Stratego rules. Your pieces at bottom, AI at top."
        )

    with col2:
        if st.button("Start Game โ†’", type="primary", use_container_width=True, key="start_game_btn"):
            session_manager.SessionManager.set_game_mode("Standard (10x10)")
            session_manager.SessionManager.set_screen(1)
            st.rerun()


def screen_ai_config():
    """Screen 1: AI agent configuration - Real Ollama setup"""
    st.title("โš™๏ธ Configure AI Opponent")

    col1, col2 = st.columns(2)

    with col1:
        st.subheader("๐Ÿš€ Ollama AI Model")

        # Ollama configuration
        backend = "ollama"
        st.success("โœ… Using Ollama Backend")

        available_models = game_config.get_available_models(backend)
        model = st.selectbox(
            "Select Model:",
            available_models,
            index=0,
            help="Choose from available Ollama models (make sure it's pulled: ollama pull mistral:7b)"
        )

        ollama_url = st.text_input(
            "๐Ÿ”— Ollama Server URL:",
            value="http://localhost:11434",
            help="Local: http://localhost:11434 | Remote: your_server_ip:11434"
        )

        # Test connection button
        if st.button("๐Ÿงช Test Connection", help="Check if Ollama is running"):
            try:
                import requests
                response = requests.get(f"{ollama_url}/api/tags", timeout=3)
                if response.status_code == 200:
                    st.success("โœ… Connected to Ollama!")
                    st.caption(f"(Available models: {len(response.json().get('models', []))})")
                else:
                    st.error(f"โŒ Ollama responded with status {response.status_code}")
            except Exception as e:
                st.error(f"โŒ Cannot connect to Ollama: {str(e)}")
                st.caption(f"Make sure Ollama is running at {ollama_url}")

    with col2:
        st.subheader("๐Ÿ“– Strategy & Settings")

        prompt = st.selectbox(
            "Prompt Style:",
            game_config.PROMPT_PRESETS,
            index=0,
            help="base=minimal | concise=focused on winning | adaptive=strategic analysis"
        )

        st.info("๐Ÿ’ก Tip: Start with Mistral 7B for good balance of speed and quality")

    st.divider()

    col1, col2, col3 = st.columns(3)
    with col1:
        if st.button("< Back", use_container_width=True):
            session_manager.SessionManager.set_screen(0)
            st.rerun()

    with col3:
        if st.button("๐ŸŽฎ Start Game", type="primary", use_container_width=True):
            # Build real OllamaAgent
            try:
                from stratego.models.ollama_model import OllamaAgent

                st.session_state.ollama_url = ollama_url
                agent = OllamaAgent(
                    model_name=model,
                    prompt_pack=prompt,
                    host=ollama_url
                )

                # Initialize game
                mode = session_manager.SessionManager.get_game_mode()
                env_id = game_config.get_env_id(mode)
                size = game_config.get_board_size(mode)

                game_ctrl = GameController(env_id, size, agent, prompt)
                game_ctrl.reset()

                session_manager.SessionManager.set_game_controller(game_ctrl)
                session_manager.SessionManager.set_ai_config(backend, model, prompt)
                session_manager.SessionManager.set_screen(2)
                st.rerun()

            except Exception as e:
                st.error(f"โŒ Failed to create AI: {str(e)}")
                st.code(f"Error details:\n{str(e)}")
                st.warning(
                    f"Make sure:\n"
                    f"1. Ollama is running: `ollama serve`\n"
                    f"2. Model is pulled: `ollama pull {model}`\n"
                    f"3. Server URL is correct: {ollama_url}"
                )


def screen_active_game():
    """Screen 2: Active game with interactive chess-like board"""
    game_ctrl = session_manager.SessionManager.get_game_controller()

    if not game_ctrl:
        st.error("Game not initialized!")
        return

    st.title("โš”๏ธ STRATEGO - Battle Arena")

    # Top controls
    col1, col2, col3 = st.columns([1, 2, 1])
    with col1:
        if st.button("๐Ÿ”„ Reset", help="Start a new game"):
            session_manager.SessionManager.reset_all()
            st.rerun()

    with col2:
        # Game stats in header
        col2a, col2b, col2c = st.columns(3)
        with col2a:
            st.metric("Moves", game_ctrl.get_turn_count())
        with col2b:
            current = "๐Ÿ‘ค You" if game_ctrl.is_human_turn() else "๐Ÿค– AI"
            st.metric("Current", current)
        with col2c:
            st.metric("Status", "๐ŸŽฎ Active" if not game_ctrl.game_done else "๐Ÿ Ended")

    with col3:
        if st.button("๐Ÿ“‹ Menu", help="Return to main menu"):
            session_manager.SessionManager.reset_all()
            st.rerun()

    st.divider()

    # Main game area
    left, right = st.columns([2.5, 1.5])

    with left:
        # Interactive board
        player_move = render_interactive_board(game_ctrl)

        if player_move:
            # Execute human move
            done, info = game_ctrl.execute_move(player_move)

            if done:
                st.session_state.game_ended = True
                st.rerun()

            # Trigger AI turn
            player_id, obs = game_ctrl.get_current_player()
            st.rerun()

        # AI's turn
        if game_ctrl.is_ai_turn():
            st.divider()
            st.markdown("## ๐Ÿค– AI is thinking...")

            with st.spinner("AI calculating move..."):
                try:
                    move, error = game_ctrl.get_ai_move()

                    if error:
                        st.warning(f"โš ๏ธ {error}")

                    done, info = game_ctrl.execute_move(move)
                    st.success(f"โœ… AI played: {move}")

                    if done:
                        st.session_state.game_ended = True
                    else:
                        # Update to human turn
                        player_id, obs = game_ctrl.get_current_player()

                    st.rerun()

                except Exception as e:
                    st.error(f"โŒ AI Error: {str(e)}")
                    st.code(str(e))

    with right:
        st.subheader("๐Ÿ“Š Game Info")

        # Status panel with beautiful styling
        status_panel.render_status_panel(game_ctrl)

        st.divider()

        # Move history
        st.subheader("๐Ÿ“œ Move History")
        game_history.render_game_history(game_ctrl)

        # Game end screen
        if game_ctrl.game_done:
            st.divider()
            st.error("๐Ÿ GAME ENDED!")
            col1, col2 = st.columns(2)
            with col1:
                if st.button("๐Ÿ”„ Play Again", use_container_width=True):
                    session_manager.SessionManager.reset_all()
                    st.rerun()
            with col2:
                if st.button("๐Ÿ  Main Menu", use_container_width=True):
                    session_manager.SessionManager.reset_all()
                    st.rerun()


def main():
    """Main application entry point"""
    # Configure page
    st.set_page_config(
        page_title="Stratego - Human vs AI",
        page_icon="chess",
        layout="wide",
        initial_sidebar_state="collapsed"
    )
    
    # Initialize session
    session_manager.SessionManager.init()
    
    # Route to correct screen
    screen = session_manager.SessionManager.get_screen()
    
    if screen == 0:
        screen_welcome()
    elif screen == 1:
        screen_ai_config()
    elif screen == 2:
        screen_active_game()
    else:
        st.error(f"Unknown screen: {screen}")


if __name__ == "__main__":
    main()