This refactor fixes the achievement system by using stable canonical string IDs (e.g., "stadium_mlb_fenway_park") instead of random UUIDs. This ensures stadium mappings for achievements are consistent across app launches and CloudKit sync operations. Changes: - Stadium, Team, Game: id property changed from UUID to String - Trip, TripStop, TripPreferences: updated to use String IDs for games/stadiums - CKModels: removed UUID parsing, use canonical IDs directly - AchievementEngine: now matches against canonical stadium IDs - All test files updated to use String IDs instead of UUID() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
68 lines
2.4 KiB
Swift
68 lines
2.4 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 {
|
|
print("🔍 ScenarioPlannerFactory: Selecting planner...")
|
|
print(" - followTeamId: \(request.preferences.followTeamId ?? "nil")")
|
|
print(" - selectedGames.count: \(request.selectedGames.count)")
|
|
print(" - startLocation: \(request.startLocation?.name ?? "nil")")
|
|
print(" - endLocation: \(request.endLocation?.name ?? "nil")")
|
|
|
|
// Scenario D: User wants to follow a specific team
|
|
if request.preferences.followTeamId != nil {
|
|
print("🔍 ScenarioPlannerFactory: → ScenarioDPlanner (follow team)")
|
|
return ScenarioDPlanner()
|
|
}
|
|
|
|
// Scenario B: User selected specific games
|
|
if !request.selectedGames.isEmpty {
|
|
print("🔍 ScenarioPlannerFactory: → ScenarioBPlanner (selected games)")
|
|
return ScenarioBPlanner()
|
|
}
|
|
|
|
// Scenario C: User specified start and end locations
|
|
if request.startLocation != nil && request.endLocation != nil {
|
|
print("🔍 ScenarioPlannerFactory: → ScenarioCPlanner (start/end locations)")
|
|
return ScenarioCPlanner()
|
|
}
|
|
|
|
// Scenario A: Date range only (default)
|
|
print("🔍 ScenarioPlannerFactory: → ScenarioAPlanner (default/date range)")
|
|
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
|
|
}
|
|
}
|