from race_engine import simulate_race# Run dry race on standard circuitresult = simulate_race( weather="DRY", circuit="STANDARD", seed=42 # for reproducibility)print(f"Winner: {result['winner']}")print(f"Podium: {' / '.join(result['podium'])}")print(f"DNFs: {result['dnf_count']}")
Example Output:
Winner: Max VerstappenPodium: Max Verstappen / Lando Norris / Charles LeclercSC deployments: 2 (laps [12, 34])DNFs: 3Fastest lap: Lewis Hamilton - 88.234sTop 5: P1: Max Verstappen WINNER 1 stop(s) - ['SOFT', 'MEDIUM'] P2: Lando Norris +8.456s 1 stop(s) - ['MEDIUM', 'HARD'] P3: Charles Leclerc +15.234s 1 stop(s) - ['SOFT', 'MEDIUM'] P4: Lewis Hamilton +23.891s 1 stop(s) - ['MEDIUM', 'HARD'] P5: Oscar Piastri +31.567s 2 stop(s) - ['SOFT', 'MEDIUM', 'HARD']
result = simulate_race(weather="DRY", circuit="STANDARD")# Characteristics:# - Grid position is king# - Pole has ~42% win rate# - Standard tire strategies (S-M, M-H)# - Fewer position changes
result = simulate_race(weather="LIGHT_RAIN", circuit="STANDARD")# Characteristics:# - Wet skill matters more# - Pole advantage drops to ~35%# - Intermediate tires# - More overtaking opportunities# - Hamilton/Alonso advantage
result = simulate_race(weather="HEAVY_RAIN", circuit="STANDARD")# Characteristics:# - Complete chaos# - Pole conversion only ~23%# - Full wet tires# - High DNF probability# - Backmarkers can score podiums
The race starts with a realistic qualifying session:
race_engine.py
# Qualifying simulation (determines grid)quali_scores = {}for code, d in DRIVERS.items(): # Use wet skill in rain, dry skill otherwise eff = d["wet"] if weather != "DRY" else d["skill"] car = TEAM_CAR[d["team"]] # Add randomness (±1.5% variation) quali_scores[code] = eff * car + random.gauss(0, 0.015)# Sort to get grid order (best score = pole)grid_order = sorted( DRIVERS.keys(), key=lambda c: quali_scores[c], reverse=True)
Typical Grid Order:
1. VER Max Verstappen Red Bull 2. NOR Lando Norris McLaren 3. LEC Charles Leclerc Ferrari 4. HAM Lewis Hamilton Ferrari 5. PIA Oscar Piastri McLaren ...
for lap in range(1, RACE_LAPS + 1): # 1. Weather changes (3% chance per lap) if lap > 5 and random.random() < 0.03: current_weather = "LIGHT_RAIN" weather_history.append((lap, current_weather)) # 2. Safety car deployment (4% per lap) if not sc_active and random.random() < 0.04: sc_laps_remaining = random.randint(3, 6) sc_active = True sc_deploy_history.append(lap) # 3. Each car executes lap for car in active_cars: # Pit stop decision if lap == car.pit_stops[0]: car.execute_pit_stop() # DNF check (0.6% per car per lap) if random.random() < 0.006: car.dnf = True car.dnf_lap = lap continue # Calculate lap time lt = car.base_lap_time(lap, current_weather, sc_active) car.total_time += lt car.tire_age += 1 # 4. Sort positions alive = sorted( [c for c in cars.values() if not c.dnf], key=lambda c: c.total_time )
# Random SC trigger (crash / debris) - ~4% per lapif not sc_active and random.random() < 0.04: sc_laps_remaining = random.randint(3, 6) sc_active = True sc_deploy_history.append(lap) for c in cars.values(): c.events.append(f"L{lap}: SAFETY CAR deployed!")# Opportunistic pit stops under SCif sc_active and car.pit_stops and abs(lap - car.pit_stops[0]) <= 3: pitting = True car.events.append(f"L{lap}: Pit under Safety Car!")
# Weather change mid-raceif lap > 5: roll = random.random() if current_weather == "DRY" and roll < 0.03: current_weather = "LIGHT_RAIN" weather_history.append((lap, current_weather)) for c in cars.values(): c.events.append(f"L{lap}: Rain starts!") elif current_weather == "LIGHT_RAIN": if roll < 0.04: current_weather = "HEAVY_RAIN" weather_history.append((lap, current_weather)) elif roll < 0.07: current_weather = "DRY" weather_history.append((lap, current_weather))# Wet weather penalty for slick tiresif weather == "LIGHT_RAIN": if self.tire in ["SOFT","MEDIUM","HARD"]: base += 3.0 + random.gauss(0, 0.8) # Major time loss
# DNF check (~0.6% per car per lap = ~5% per race)if random.random() < 0.006: car.dnf = True car.dnf_lap = lap car.events.append(f"L{lap}: DNF - Mechanical failure / Crash!") continue