#!/usr/bin/env python3 """Headless simulation entry point - runs simulations without UI.""" import sys import argparse from pathlib import Path # Add project root to path project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) from config import ConfigLoader, HeadlessConfig from engines import HeadlessSimulationEngine, HeadlessConfig as EngineHeadlessConfig def main(): """Main entry point for headless simulation.""" parser = argparse.ArgumentParser(description="Run headless simulation") parser.add_argument( "--config", "-c", type=str, help="Path to configuration file (JSON/YAML)", default=None ) parser.add_argument( "--output-dir", "-o", type=str, help="Output directory for simulation data", default="simulation_output" ) parser.add_argument( "--max-ticks", "-t", type=int, help="Maximum number of ticks to run", default=None ) parser.add_argument( "--max-duration", "-d", type=float, help="Maximum duration in seconds", default=None ) parser.add_argument( "--tps", type=float, help="Target TPS for simulation (default: unlimited speed)", default=None ) parser.add_argument( "--real-time", action="store_true", help="Run in real-time mode (instead of as fast as possible)" ) parser.add_argument( "--collect-metrics", action="store_true", help="Enable metrics data collection" ) parser.add_argument( "--collect-entities", action="store_true", help="Enable entity data collection" ) parser.add_argument( "--collect-evolution", action="store_true", help="Enable evolution data collection" ) parser.add_argument( "--collect-all", action="store_true", help="Enable all data collection (metrics, entities, evolution)" ) parser.add_argument( "--collect-every-tick", action="store_true", help="Collect data on every tick instead of at intervals" ) parser.add_argument( "--create-sample-configs", action="store_true", help="Create sample configuration files and exit" ) args = parser.parse_args() # Create sample configs if requested if args.create_sample_configs: ConfigLoader.create_sample_configs() return # Load configuration try: if args.config: headless_config = ConfigLoader.load_headless_config(args.config) else: headless_config = ConfigLoader.get_default_headless_config() # Override config with command line arguments if args.max_ticks: headless_config.max_ticks = args.max_ticks if args.max_duration: headless_config.max_duration = args.max_duration if args.tps is not None: headless_config.simulation.default_tps = args.tps else: # No TPS specified - run at maximum speed headless_config.simulation.default_tps = 999999999.0 if args.output_dir: headless_config.output.directory = args.output_dir if args.real_time: headless_config.output.real_time = True # Handle data collection arguments - only enable if explicitly requested # Start with all disabled (default) headless_config.output.collect_metrics = False headless_config.output.collect_entities = False headless_config.output.collect_evolution = False if args.collect_all: # Enable all collection headless_config.output.collect_metrics = True headless_config.output.collect_entities = True headless_config.output.collect_evolution = True else: # Enable specific collection types if args.collect_metrics: headless_config.output.collect_metrics = True if args.collect_entities: headless_config.output.collect_entities = True if args.collect_evolution: headless_config.output.collect_evolution = True if args.collect_every_tick: # Set all collection intervals to 1 for every-tick collection headless_config.output.metrics_interval = 1 headless_config.output.entities_interval = 1 headless_config.output.evolution_interval = 1 # Also enable all collection if using --collect-every-tick (backward compatibility) headless_config.output.collect_metrics = True headless_config.output.collect_entities = True headless_config.output.collect_evolution = True except Exception as e: print(f"Error loading configuration: {e}") sys.exit(1) # Create engine configuration engine_config = EngineHeadlessConfig( simulation=headless_config.simulation, max_ticks=headless_config.max_ticks, max_duration=headless_config.max_duration, output_dir=headless_config.output.directory, enable_metrics=headless_config.output.collect_metrics, enable_entities=headless_config.output.collect_entities, enable_evolution=headless_config.output.collect_evolution, metrics_interval=headless_config.output.metrics_interval, entities_interval=headless_config.output.entities_interval, evolution_interval=headless_config.output.evolution_interval, output_formats=headless_config.output.formats, real_time=headless_config.output.real_time ) # Create and run simulation try: print("Starting headless simulation...") engine = HeadlessSimulationEngine(engine_config) summary = engine.run() # Print summary print("\n" + "="*50) print("SIMULATION SUMMARY") print("="*50) print(f"Total ticks: {summary['runtime']['total_ticks']}") print(f"Duration: {summary['runtime']['duration_seconds']:.2f} seconds") print(f"Average TPS: {summary['runtime']['average_tps']:.2f}") print(f"Final entity counts: {summary['final_state']['entity_counts']}") print(f"Output directory: {summary['data_collection']['output_directory']}") except KeyboardInterrupt: print("\nSimulation interrupted by user") sys.exit(0) except Exception as e: print(f"Simulation error: {e}") import traceback traceback.print_exc() sys.exit(1) if __name__ == "__main__": main()