50 lines
1.5 KiB
Swift
50 lines
1.5 KiB
Swift
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 valid(xLimit: Int, yLimit: Int) -> Bool {
|
|
return x >= 0 && y >= 0 && x < xLimit && y < yLimit
|
|
}
|
|
}
|
|
|
|
func readInput(_ filePath: String) throws -> ([Int:Set<Coord>], 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<Coord>] = [:]
|
|
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])
|
|
var answer: Int = 0
|
|
//topo.forEach { k, v in print("\(k): \(v)") }
|
|
|
|
for start in topo[0]! {
|
|
var froms: Set<Coord> = [start]
|
|
for altitude in 1...9 {
|
|
var tos: Set<Coord> = []
|
|
for from in froms {
|
|
from.neighbors()
|
|
.filter { c in c.valid(xLimit: height, yLimit: width) }
|
|
.filter { c in topo[altitude]!.contains(c) }
|
|
.forEach { c in tos.insert(c) }
|
|
}
|
|
froms = tos
|
|
}
|
|
answer += froms.count
|
|
}
|
|
print(answer)
|