AoC/2022/day16.swift

101 lines
2.8 KiB
Swift
Raw Permalink Normal View History

2022-12-17 17:38:00 +01:00
import Foundation
import RegexBuilder
struct Room {
var name: String
var flowRate: Int
var connections: [String]
2024-12-01 11:53:48 +01:00
var index: Int = -1
2022-12-17 17:38:00 +01:00
}
let regex = #/Valve (?<room>[A-Z]{2}) has flow rate=(?<flow>\d+); tunnels? leads? to valves? (?<links>[A-Z]{2}(, [A-Z]{2})*)/#
2024-12-01 11:53:48 +01:00
var rooms: [String:Room] = [:]
2022-12-17 17:38:00 +01:00
for try await line in URL(fileURLWithPath: "day16.input").lines {
guard let match = try regex.wholeMatch(in: line) else {
fatalError("Invalid input: \(line)")
}
2024-12-01 11:53:48 +01:00
rooms[String(match.room)] = (Room(name: String(match.room), flowRate: Int(match.flow)!, connections: match.links.split(separator: ", ").map(String.init)))
2022-12-17 17:38:00 +01:00
}
2024-12-01 11:53:48 +01:00
let roomsWithValves: [String] = ["AA"] + rooms.values.lazy.filter { $0.flowRate > 0 }.map(\.name).sorted()
for (index, name) in roomsWithValves.enumerated() {
rooms[name]?.index = index
2022-12-17 17:38:00 +01:00
}
2024-12-01 11:53:48 +01:00
struct Matrix<Element> {
var size: Int
var data: [Element]
2022-12-17 17:38:00 +01:00
2024-12-01 11:53:48 +01:00
init(size: Int, data: [Element]) {
precondition(data.count == size * size)
self.size = size
self.data = data
2022-12-17 17:38:00 +01:00
}
2024-12-01 11:53:48 +01:00
init(size: Int, repeating: Element) {
self.init(size: size, data: Array(repeating: repeating, count: size * size))
}
2022-12-17 17:38:00 +01:00
2024-12-01 11:53:48 +01:00
subscript(x: Int, y: Int) -> Element {
get {
precondition(0 <= x && x < size && 0 <= y && y < size)
return data[x + size * y]
2022-12-17 17:38:00 +01:00
}
2024-12-01 11:53:48 +01:00
set {
precondition(0 <= x && x < size && 0 <= y && y < size)
data[x + size * y] = newValue
2022-12-17 17:38:00 +01:00
}
}
2024-12-01 11:53:48 +01:00
mutating func setDiagonal(to value: Element) {
for i in 0..<size {
self[i, i] = value
}
}
2022-12-17 17:38:00 +01:00
}
2022-12-20 20:11:25 +01:00
2024-12-01 11:53:48 +01:00
var distanceMatrix = Matrix(size: roomsWithValves.count, repeating: Int.max)
distanceMatrix.setDiagonal(to: 0)
2022-12-20 20:11:25 +01:00
2024-12-01 11:53:48 +01:00
func findDistances(start: String, current: String, previous: String? = nil, distance: Int = 0) {
2022-12-20 20:11:25 +01:00
2024-12-01 11:53:48 +01:00
let currentRoom = rooms[current]!
let startRoom = rooms[start]!
2022-12-20 20:11:25 +01:00
2024-12-01 11:53:48 +01:00
let nextStart = currentRoom.flowRate > 0 ? current : start
if currentRoom.flowRate > 0 {
distanceMatrix[startRoom.index, currentRoom.index] = min(distanceMatrix[startRoom.index, currentRoom.index], distance)
2022-12-20 20:11:25 +01:00
}
2024-12-01 11:53:48 +01:00
for next in currentRoom.connections where next != previous {
findDistances(start: nextStart, current: next, previous: current, distance: distance + 1)
2022-12-20 20:11:25 +01:00
}
}
2024-12-01 11:53:48 +01:00
findDistances(start: "AA", current: "AA")
2022-12-20 20:11:25 +01:00
2024-12-01 11:53:48 +01:00
print(" ", terminator: "")
for name in roomsWithValves {
print("| \(name) ", terminator: "")
}
print("|")
for y in 0..<distanceMatrix.size {
print(roomsWithValves[y], "", terminator: "")
for x in 0..<distanceMatrix.size {
let value = distanceMatrix[x, y]
if value == .max {
print("| ", terminator: "")
} else {
print(String(format: "| %2d ", value), terminator: "")
2022-12-20 20:11:25 +01:00
}
}
2024-12-01 11:53:48 +01:00
print("|")
2022-12-20 20:11:25 +01:00
}