Files
aoc24/day18/d18p2.swift
2024-12-18 12:34:43 -08:00

88 lines
3.0 KiB
Swift

import Foundation
struct Coord : Hashable, CustomStringConvertible {
let (x, y): (Int, Int)
var description: String { return "(\(x),\(y))" }
}
func readInput(_ fileName: String) throws -> [Coord] {
let xy = try Regex(#"([0-9]+),([0-9]+)"#)
return try String(contentsOfFile: fileName, encoding: .ascii)
.split(separator: "\n")
.compactMap { $0.wholeMatch(of: xy) }
.map { Coord(
x: Int($0.output[1].substring!)!,
y: Int($0.output[2].substring!)!
) }
}
struct Map : CustomStringConvertible {
let walls: Set<Coord>
let (w, h): (Int, Int)
var description: String {
let top = " \u{001B}[4m" + (0..<w).map { " \($0 % 10)" }.joined() + "\u{001B}[0m\n"
let maze = (0..<h).map { i in
String(format: "%2d▕", i) + (0..<w).map { j in
walls.contains(Coord(x: j, y: i)) ? "▓▓" : " "
}.joined() + ""
}.joined(separator: "\n")
let bot = "\n " + String(repeating: "🬂", count: w*2) + "🬀"
return top + maze + bot
}
func heur(_ a: Coord, _ b: Coord) -> Int {
return abs(a.x - b.x) + abs(a.y - b.y)
}
func bfs(from start: Coord, to end: Coord) -> Bool {
var q: Set<Coord> = [start]
var seen: Set<Coord> = [start]
while !q.isEmpty {
let cell = q.removeFirst()
if cell == end {
return true
}
[(0, -1), (0, 1), (-1, 0), (1, 0)].map { dy, dx in
Coord(x: cell.x + dx, y: cell.y + dy)}
.filter { c in c.x >= 0 && c.y >= 0 && c.x < w && c.y < h }
.filter { !walls.contains($0) }
.filter { !seen.contains($0) }
.forEach { nb in
seen.insert(nb)
q.insert(nb)
}
}
return false
}
}
@main
struct AoC {
static func main() throws {
let bytes = try readInput(CommandLine.arguments[1])
let w = Int(CommandLine.arguments[2]) ?? 71
let h = Int(CommandLine.arguments[3]) ?? 71
let startLimit = Int(CommandLine.arguments[4]) ?? 1024
var range = Array(startLimit..<bytes.count)
while range.count > 1 {
let center = range.count/2
print("Trying \(range[center])...", terminator: "")
let map = Map(walls: Set(bytes.prefix(range[center])), w: w, h: h)
if map.bfs(from: Coord(x: 0, y: 0), to: Coord(x: w-1, y: h-1)) {
print(" works")
range = Array(range[center+1..<range.count])
} else {
print(" blocked")
range = Array(range[0..<center])
}
}
let map = Map(walls: Set(bytes.prefix(range[0])), w: w, h: h)
print(map)
if map.bfs(from: Coord(x: 0, y: 0), to: Coord(x: w-1, y: h-1)) {
print("at \(range[0]): \(bytes[range[0]])")
} else {
print("at \(range[0] + 1): \(bytes[range[0] + 1])")
}
}
}