Files
Sportstime/SportsTime/Planning/Engine/ScenarioPlanner.swift
Trey t f7faec01b1 feat: add Follow Team Mode (Scenario D) for road trip planning
Adds a new planning mode that lets users follow a team's schedule
(home + away games) and builds multi-city routes accordingly.

Key changes:
- New ScenarioDPlanner with team filtering and route generation
- Team picker UI with sport grouping and search
- Fix TravelEstimator 5-day limit (was 2-day) for cross-country routes
- Fix DateInterval end boundary to include games on last day
- Comprehensive test suite covering edge cases:
  - Multi-city routes with adequate/insufficient time
  - Optimal game selection per city for feasibility
  - 5-day driving segment limits
  - Multiple driver scenarios

Enables trips like Houston → Chicago → Anaheim following the Astros.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 12:42:43 -06:00

58 lines
1.7 KiB
Swift

//
// ScenarioPlanner.swift
// SportsTime
//
// Protocol for scenario-based trip planning.
//
import Foundation
/// Protocol that all scenario planners must implement.
/// Each scenario (A, B, C) has its own isolated implementation.
protocol ScenarioPlanner {
/// Plan itineraries for this scenario.
/// - Parameter request: The planning request with all inputs
/// - Returns: Success with ranked itineraries, or explicit failure
func plan(request: PlanningRequest) -> ItineraryResult
}
/// Factory for creating the appropriate scenario planner
enum ScenarioPlannerFactory {
/// Creates the appropriate planner based on the request inputs
static func planner(for request: PlanningRequest) -> ScenarioPlanner {
// Scenario D: User wants to follow a specific team
if request.preferences.followTeamId != nil {
return ScenarioDPlanner()
}
// Scenario B: User selected specific games
if !request.selectedGames.isEmpty {
return ScenarioBPlanner()
}
// Scenario C: User specified start and end locations
if request.startLocation != nil && request.endLocation != nil {
return ScenarioCPlanner()
}
// Scenario A: Date range only (default)
return ScenarioAPlanner()
}
/// Classifies which scenario applies to this request
static func classify(_ request: PlanningRequest) -> PlanningScenario {
if request.preferences.followTeamId != nil {
return .scenarioD
}
if !request.selectedGames.isEmpty {
return .scenarioB
}
if request.startLocation != nil && request.endLocation != nil {
return .scenarioC
}
return .scenarioA
}
}