diff --git a/Sources/15/15.swift b/Sources/15/15.swift index e06d373..552fd29 100644 --- a/Sources/15/15.swift +++ b/Sources/15/15.swift @@ -38,22 +38,11 @@ class Day15: Runnable { self.inputPath = inputPath } - public func run() { - let input = try! String(contentsOfFile: inputPath) - parts = input - .trimmingCharacters(in: .newlines) - .components(separatedBy: .newlines) - .map { Array($0) } - .map { ar in ar.map {c in ThreatLevel(c.description)!} } - lastRow = parts.count - 1 - lastCol = (parts.first?.count ?? 0) - 1 - + private func expandMap() { var tmpParts = parts for (rowNum, row) in tmpParts.enumerated() { let newRow = [Int](0...4).flatMap { cr in - row - .map { rv in cr + rv } - .map { $0 > 9 ? $0 - 9 : $0 } + row.map { rv in cr + rv }.map { $0 > 9 ? $0 - 9 : $0 } } parts[rowNum] = newRow } @@ -69,7 +58,25 @@ class Day15: Runnable { lastRow = parts.count - 1 lastCol = (parts.first?.count ?? 0) - 1 + } + + public func run() { + let input = try! String(contentsOfFile: inputPath) + parts = input + .trimmingCharacters(in: .newlines) + .components(separatedBy: .newlines) + .map { Array($0) } + .map { ar in ar.map {c in ThreatLevel(c.description)!} } + lastRow = parts.count - 1 + lastCol = (parts.first?.count ?? 0) - 1 + calculateSafestPath() + expandMap() + neighbors = [Coord: [Coord]]() + calculateSafestPath() + } + + private func calculateSafestPath() { // Distances to startNode var totalThreatLevel = [Coord: ThreatLevel]() @@ -78,6 +85,13 @@ class Day15: Runnable { Coord(row: row.offset, col: col) } }) + + /* Keep a seperate dictionary, to calculate which coordinates have a set threat level + * a.k.a total distance to start + * This allows to find the next coordinate to check fairly quickly, by just + * looking at the minmum key in this. + * I initially tried a PriorityQueue, but my implementation was pretty slow and it spent too much time sorting + */ var threatLevelDistrubution = [ThreatLevel: Set]() let startNode = Coord(row: 0, col: 0) totalThreatLevel[startNode] = 0 @@ -89,6 +103,8 @@ class Day15: Runnable { let currentNode = threatLevelDistrubution[threatLevel]!.first! unvisited.remove(currentNode) threatLevelDistrubution[threatLevel]!.remove(currentNode) + + // Remove key from dictionary if not coords are left for a specific threat level if threatLevelDistrubution[threatLevel]!.isEmpty { threatLevelDistrubution.removeValue(forKey: threatLevel) } @@ -114,6 +130,8 @@ class Day15: Runnable { totalThreatLevel[a] = testCost threatLevelDistrubution[currentCost]!.remove(a) threatLevelDistrubution[testCost, default: Set()].insert(a) + + // Remove key from dictionary if not coords are left for a specific threat leveli if threatLevelDistrubution[currentCost]!.isEmpty { threatLevelDistrubution.removeValue(forKey: currentCost) }