Refactor trip planning: DAG router + trip options UI + simplified itinerary
- Replace O(2^n) GeographicRouteExplorer with O(n) GameDAGRouter using DAG + beam search - Add geographic diversity to route selection (returns routes from distinct regions) - Add trip options selector UI (TripOptionsView, TripOptionCard) to choose between routes - Simplify itinerary display: separate games and travel segments by date - Remove complex ItineraryDay bundling, query games/travel directly per day - Update ScenarioA/B/C planners to use GameDAGRouter - Add new test suites for planners and travel estimator 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
enum Sport: String, Codable, CaseIterable, Identifiable {
|
||||
case mlb = "MLB"
|
||||
@@ -34,6 +35,16 @@ enum Sport: String, Codable, CaseIterable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .mlb: return .red
|
||||
case .nba: return .orange
|
||||
case .nhl: return .blue
|
||||
case .nfl: return .brown
|
||||
case .mls: return .green
|
||||
}
|
||||
}
|
||||
|
||||
var seasonMonths: ClosedRange<Int> {
|
||||
switch self {
|
||||
case .mlb: return 3...10 // March - October
|
||||
|
||||
@@ -297,8 +297,21 @@ actor StubDataProvider: DataProvider {
|
||||
return Calendar.current.date(bySettingHour: hour, minute: minute, second: 0, of: dateOnly)
|
||||
}
|
||||
|
||||
// Venue name aliases for stadiums that changed names
|
||||
private static let venueAliases: [String: String] = [
|
||||
"daikin park": "minute maid park", // Houston Astros (renamed 2024)
|
||||
"rate field": "guaranteed rate field", // Chicago White Sox
|
||||
"george m. steinbrenner field": "tropicana field", // Tampa Bay spring training → main stadium
|
||||
"loandepot park": "loandepot park", // Miami - ensure case match
|
||||
]
|
||||
|
||||
private func findStadiumId(venue: String, sport: Sport) -> UUID {
|
||||
let venueLower = venue.lowercased()
|
||||
var venueLower = venue.lowercased()
|
||||
|
||||
// Check for known aliases
|
||||
if let aliasedName = Self.venueAliases[venueLower] {
|
||||
venueLower = aliasedName
|
||||
}
|
||||
|
||||
// Try exact match
|
||||
if let stadium = stadiumsByVenue[venueLower] {
|
||||
@@ -313,6 +326,7 @@ actor StubDataProvider: DataProvider {
|
||||
}
|
||||
|
||||
// Generate deterministic ID for unknown venues
|
||||
print("[StubDataProvider] No stadium match for venue: '\(venue)'")
|
||||
return deterministicUUID(from: "venue_\(venue)")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user