Samuel Bargallo 9b009ef593
Some checks failed
Build Simulation and Test / Run All Tests (push) Failing after 14m52s
Added early stopping to the headless simulation.
2025-11-11 19:47:02 +00:00

200 lines
6.8 KiB
Python

#!/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"
)
parser.add_argument(
"--early-stop",
action="store_true",
help="Stop simulation when there are 0 cells remaining"
)
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
# Set early stopping flag
if args.early_stop:
headless_config.early_stop = 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,
early_stop=headless_config.early_stop
)
# 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()