#!/usr/bin/env python """ Play chess against the Chess Master agent. A full interactive CLI game with the complete trigger system, personality, and memory integration. """ import asyncio import traceback from datetime import datetime from typing import Optional from agent.main_agent import ChessMaster from agent.subconscious import Subconscious from agent.scheduler import MatchScheduler, TriggerPoint from db.database import get_db_manager, get_or_create_player from chess_engine import ChessGame, choose_move async def display_board(scheduler: MatchScheduler) -> None: """Display the chess board with context.""" game = scheduler.chess_game print("\n" + "=" * 70) print(game.get_ascii_board()) print("=" * 70) status = game.get_game_status() if status["is_checkmate"]: winner = "White" if status["is_check"] else "Black" print(f"ā™ž CHECKMATE! {winner} wins!") elif status["is_stalemate"]: print("ā™ž STALEMATE! Draw!") elif status["is_check"]: print(f"ā™ž CHECK! {game.get_current_player()} is in check!") print(f"Move count: {status['moves_count']} | Phase: {game.get_game_phase()}") print() def show_legal_moves(scheduler: MatchScheduler) -> None: """Show available moves.""" moves = scheduler.chess_game.get_legal_moves() print(f"Legal moves ({len(moves)}): {', '.join(moves[:15])}", end="") if len(moves) > 15: print(f", ... (+{len(moves) - 15} more)", end="") print("\n") def show_help() -> None: """Show command help.""" print(""" Commands: - Make a move (e.g., e4, Nf3, O-O for castling) resign - Resign the game draw - Offer a draw board - Show the board again moves - Show all legal moves history - Show move history help - Show this help quit - Exit """) async def get_player_move(scheduler: MatchScheduler, player_name: str) -> Optional[str]: """Get and validate a player move.""" while True: try: move_input = input(f"\n{player_name}'s move (or 'help'): ").strip() if not move_input: print("Please enter a move or command") continue move_lower = move_input.lower() # Commands if move_lower == "help": show_help() continue elif move_lower == "board": await display_board(scheduler) continue elif move_lower == "moves": show_legal_moves(scheduler) continue elif move_lower == "history": history = scheduler.chess_game.get_move_history() if history: moves_str = " ".join([m["move_san"] for m in history]) print(f"Move history: {moves_str}\n") else: print("No moves yet.\n") continue elif move_lower in ["resign", "draw"]: return move_lower elif move_lower == "quit": return "quit" # Try to make the move success, error = scheduler.chess_game.make_move(move_input) if success: return move_input else: print(f"āŒ {error}") print("Try 'moves' to see legal moves.") continue except KeyboardInterrupt: return "quit" except Exception as e: print(f"Error: {e}") continue async def make_agent_move(scheduler: MatchScheduler) -> bool: """Make agent's move with trigger system.""" game = scheduler.chess_game if not game.get_legal_moves_uci(): return False response = await scheduler.trigger(TriggerPoint.BEFORE_AGENT_MOVE) if response and response.get("action") == "send_message": print(f"\nšŸŽ­ Chess Master: {response.get('content')}") if response.get("tone"): print(f" (tone: {response.get('tone')})") mv = choose_move(game.board, depth=2) if mv is None: return False san = game.board.san(mv) # compute before pushing result = scheduler.make_agent_move(mv.uci()) if result["success"]: print(f"\nā™˜ Chess Master played: {san}") return True return False async def play_game() -> None: """Main game loop.""" print("\n" + "=" * 70) print("ā™Ÿļø METROPOLIS CHESS CLUB ā™Ÿļø") print(" Play Against the Chess Master") print("=" * 70) # Get player info player_name = input("\nWhat's your name? ").strip() if not player_name: player_name = "Player" print(f"\nWelcome, {player_name}!") # Initialize database db = get_db_manager() db.initialize() player = get_or_create_player(player_name, player_name) print(f"Games played: {player.total_games} | Wins: {player.wins_against_agent}") # Initialize agents print("\nšŸ”„ Initializing Chess Master...", end="", flush=True) chess_master = ChessMaster() subconscious = Subconscious() print(" Ready!") # Create match match_id = f"match-{datetime.now().timestamp()}" scheduler = MatchScheduler( match_id=match_id, player_id=player.player_id, main_agent=chess_master, subconscious_agent=subconscious, player_name=player_name, agent_name="Chess Master", ) # Start match scheduler.start_match() # Before match trigger print("\nšŸŽ­ Triggering before_match...\n") response = await scheduler.trigger(TriggerPoint.BEFORE_MATCH) if response and response.get("action") == "send_message": print(f"Chess Master: {response.get('content')}") if response.get("tone"): print(f"(tone: {response.get('tone')})") show_help() # Game loop while not scheduler.chess_game.is_game_over(): await display_board(scheduler) show_legal_moves(scheduler) # Get player move player_move = await get_player_move(scheduler, player_name) if player_move == "quit": print("\nGame abandoned.") return elif player_move == "resign": result = scheduler.resign_player() print(f"\n{player_name} resigned.") print(f"Result: {result.get('result')}") break elif player_move == "draw": result = scheduler.offer_draw() print(f"\nDraw accepted.") print(f"Result: {result.get('result')}") break # Trigger on_user_move response = await scheduler.trigger( TriggerPoint.ON_USER_MOVE, {"move": player_move} ) if response and response.get("action") == "send_message": print(f"\nšŸŽ­ Chess Master: {response.get('content')}") if response.get("tone"): print(f" (tone: {response.get('tone')})") if scheduler.chess_game.is_game_over(): break # Agent move await make_agent_move(scheduler) if scheduler.chess_game.is_game_over(): break # Game over await display_board(scheduler) game_result = scheduler.chess_game.get_game_result() if game_result: if game_result == "1-0": print("šŸŽ‰ White wins!") elif game_result == "0-1": print("šŸŽ‰ Black wins!") else: print("šŸ¤ Draw!") # After match — fires AFTER_MATCH trigger and records outcome to DB print("\nšŸŽ­ Triggering after_match...\n") response = await scheduler.end_match() if response and response.get("action") == "send_message": print(f"Chess Master: {response.get('content')}") if response.get("tone"): print(f"(tone: {response.get('tone')})") # Show stats stats = scheduler.get_stats() print("\n" + "=" * 70) print("MATCH STATS") print("=" * 70) print(f"Match ID: {stats['match_id']}") print(f"Duration: {stats['duration_seconds']:.1f}s") print(f"Moves: {stats['moves_count']}") print(f"Messages: {stats['conversation_count']}") print(f"Triggers: {stats['trigger_count']}") print("=" * 70 + "\n") async def main(): """Entry point.""" try: await play_game() except KeyboardInterrupt: print("\n\nGame interrupted.") except Exception as e: print(f"\nError: {e}") traceback.print_exc() if __name__ == "__main__": asyncio.run(main())