Source code for haive.games.fox_and_geese.fixed_runner
#!/usr/bin/env python3"""Fixed runner for Fox and Geese game without LangGraph streaming issues."""importargparseimportloggingimporttimeimporttracebackimportuuidfromrich.consoleimportConsolefromrich.liveimportLivefromrich.panelimportPanelfromhaive.games.fox_and_geese.agentimportFoxAndGeeseAgentfromhaive.games.fox_and_geese.configimportFoxAndGeeseConfigfromhaive.games.fox_and_geese.stateimportFoxAndGeeseStatefromhaive.games.fox_and_geese.uiimportFoxAndGeeseUI# Configure logginglogging.basicConfig(level=logging.INFO)logger=logging.getLogger(__name__)
[docs]classFixedFoxAndGeeseAgent(FoxAndGeeseAgent):"""Fixed Fox and Geese agent that handles state directly."""
[docs]defrun_fixed_game(self,delay:float=1.0,max_moves:int=100)->FoxAndGeeseState:"""Run the Fox and Geese game step by step, managing state directly. This bypasses LangGraph's stream method, which can have issues with certain state types. Args: delay: Time delay between moves for better visualization max_moves: Maximum number of moves before forcing a draw Returns: Final game state """console=Console()console.print(Panel("Starting Fox and Geese Game with Fixed Runner",border_style="green"))# Initialize UIui=FoxAndGeeseUI(console)ui.display_welcome()time.sleep(1)# Initialize game statestate=self.state_manager.initialize()# Create a live display for the boardwithLive(ui.create_layout(state),refresh_per_second=4)aslive:move_count=0whilestate.game_status=="ongoing"andmove_count<max_moves:# Update the displaylive.update(ui.create_layout(state))time.sleep(delay)# Make the next move based on the current turnifstate.turn=="fox":console.print("[bold red]🦊 Fox's turn...[/bold red]")# First run analysis if enabledifself.config.enable_analysis:analysis_command=self.analyze_player1(state)if(hasattr(analysis_command,"update")andanalysis_command.update):# Extract fox_analysis from the command and update# stateif"fox_analysis"inanalysis_command.update:state=state.model_copy(deep=True)state.fox_analysis=analysis_command.update["fox_analysis"]# Now make the movenew_state=self.make_fox_move(state)state=new_stateelse:# geese's turnconsole.print("[bold blue]🪿 Geese's turn...[/bold blue]")# First run analysis if enabledifself.config.enable_analysis:analysis_command=self.analyze_player2(state)if(hasattr(analysis_command,"update")andanalysis_command.update):# Extract geese_analysis from the command and# update stateif"geese_analysis"inanalysis_command.update:state=state.model_copy(deep=True)state.geese_analysis=analysis_command.update["geese_analysis"]# Now make the movenew_state=self.make_geese_move(state)state=new_statemove_count+=1# Update the display after the movelive.update(ui.create_layout(state))time.sleep(delay)# Check if the game is overifstate.game_status!="ongoing":break# If we reached max moves, set as a drawifstate.game_status=="ongoing"andmove_count>=max_moves:state=state.model_copy(deep=True)state.game_status="draw"state.winner="none"live.update(ui.create_layout(state))time.sleep(delay)# Display final resultsui.display_final_results(state)returnstate
[docs]defparse_arguments():"""Parse command line arguments."""parser=argparse.ArgumentParser(description="Run Fox and Geese game with fixed state handling")parser.add_argument("--delay",type=float,default=1.0,help="Delay between moves (seconds)")parser.add_argument("--debug",action="store_true",help="Enable debug logging")parser.add_argument("--no-analysis",action="store_true",help="Disable position analysis")parser.add_argument("--max-moves",type=int,default=100,help="Maximum number of moves")returnparser.parse_args()
[docs]defmain():"""Run the Fox and Geese game with the fixed runner."""args=parse_arguments()# Configure loggingifargs.debug:logging.basicConfig(level=logging.DEBUG)else:logging.basicConfig(level=logging.INFO)console=Console()try:# Create config with unique IDconfig=FoxAndGeeseConfig(name="fox_and_geese_fixed",enable_analysis=notargs.no_analysis,visualize=True,runnable_config={"configurable":{"thread_id":uuid.uuid4().hex[:8],"recursion_limit":400,}},)# Create agent with the fixed implementationagent=FixedFoxAndGeeseAgent(config)console.print(Panel("Running Fox and Geese with fixed state handling\n"f"Delay between moves: {args.delay} seconds\n"f"Analysis enabled: {notargs.no_analysis}\n"f"Maximum moves: {args.max_moves}",title="🎮 Fox and Geese Fixed Game",border_style="cyan",))# Run the game with the fixed step-by-step approachagent.run_fixed_game(delay=args.delay,max_moves=args.max_moves)exceptExceptionase:console.print(f"[bold red]Error running game: {e}[/bold red]")console.print(Panel(traceback.format_exc(),title="Error Details",border_style="red"))