import Foundation struct Coord : Hashable, CustomStringConvertible { let x: Int let y: Int var description: String { return "(\(x), \(y))" } func neighbors() -> [Coord] { return [ Coord(x: x-1, y: y), Coord(x: x+1, y: y), Coord(x: x, y: y-1), Coord(x: x, y: y+1) ] } } func readInput(_ filePath: String) throws -> ([Int:Set], Int, Int) { let content = try String(contentsOfFile: filePath, encoding: .ascii) let lines = content.split(separator: "\n").map(Array.init) let map = lines.map { $0.map(String.init).map { Int($0)! } } var topo: [Int:Set] = [:] map.enumerated().forEach { i, row in row.enumerated().forEach { j, h in topo[h] = (topo[h] ?? []).union([Coord(x: i, y: j)]) } } return (topo, lines.count, lines[0].count) } let (topo, height, width) = try readInput(CommandLine.arguments[1]) topo.forEach { k, v in print("\(k): \(v)") } var currentLayer: [Coord:Int] = Dictionary( uniqueKeysWithValues: topo[0]!.map { coord in (coord, 1) } ) print("\n0: \(currentLayer)") for alt in 1...9 { var nextLayer: [Coord:Int] = [:] for (from, score) in currentLayer { from.neighbors() .filter { c in c.x >= 0 && c.y >= 0 && c.x < height && c.y < width } .filter { c in topo[alt]!.contains(c) } .forEach { c in nextLayer[c] = (nextLayer[c] ?? 0) + score } } currentLayer = nextLayer print("\(alt): \(currentLayer)") } print(currentLayer.values.reduce(0) { s, score in s + score })