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>
58 lines
1.7 KiB
Swift
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
|
|
}
|
|
}
|