d18
This commit is contained in:
69
day18/d18p1.swift
Normal file
69
day18/d18p1.swift
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
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 dijkstra(from start: Coord, to end: Coord) -> Int? {
|
||||||
|
var q = Heap<(Coord, Int)>(comparator: { l, r in l.1 < r.1 })
|
||||||
|
var seen: Set<Coord> = [start]
|
||||||
|
q.insert((start, 0))
|
||||||
|
while let (cell, cost) = q.pop() {
|
||||||
|
if cell == end {
|
||||||
|
return cost
|
||||||
|
}
|
||||||
|
[(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 { !seen.contains($0) }
|
||||||
|
.filter { !walls.contains($0) }
|
||||||
|
.forEach { neighbor in
|
||||||
|
seen.insert(neighbor)
|
||||||
|
q.insert((neighbor, cost + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 limit = Int(CommandLine.arguments[4]) ?? 1024
|
||||||
|
let map = Map(walls: Set(bytes.prefix(limit)), w: w, h: h)
|
||||||
|
print(map)
|
||||||
|
print(map.dijkstra(
|
||||||
|
from: Coord(x: 0, y: 0), to: Coord(x: map.w - 1, y: map.h - 1)
|
||||||
|
) ?? "no solution")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
76
day18/d18p2.swift
Normal file
76
day18/d18p2.swift
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
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 dijkstra(from start: Coord, to end: Coord) -> Int? {
|
||||||
|
var q = Heap<(Coord, Int)>(comparator: { l, r in l.1 < r.1 })
|
||||||
|
var seen: Set<Coord> = [start]
|
||||||
|
q.insert((start, 0))
|
||||||
|
while let (cell, cost) = q.pop() {
|
||||||
|
if cell == end {
|
||||||
|
return cost
|
||||||
|
}
|
||||||
|
[(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 { !seen.contains($0) }
|
||||||
|
.filter { !walls.contains($0) }
|
||||||
|
.forEach { neighbor in
|
||||||
|
seen.insert(neighbor)
|
||||||
|
q.insert((neighbor, cost + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
for limit in 1024..<bytes.count {
|
||||||
|
let map = Map(walls: Set(bytes.prefix(limit)), w: w, h: h)
|
||||||
|
if let cost = map.dijkstra(
|
||||||
|
from: Coord(x: 0, y: 0),
|
||||||
|
to: Coord(x: map.w - 1, y: map.h - 1)
|
||||||
|
) {
|
||||||
|
print("\(limit): \(cost)")
|
||||||
|
} else {
|
||||||
|
print(map)
|
||||||
|
print("found byte \(limit-1): \(bytes[limit-1])")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
54
day18/heap.swift
Normal file
54
day18/heap.swift
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
struct Heap<T> {
|
||||||
|
var comparator: ((_ l: T,_ r: T) -> Bool)
|
||||||
|
var heap: [T] = []
|
||||||
|
var isEmpty: Bool { return heap.isEmpty }
|
||||||
|
|
||||||
|
private mutating func bubbleUp(idx: Int) {
|
||||||
|
let parent = (idx - 1) / 2
|
||||||
|
if idx <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if comparator(heap[idx], heap[parent]) {
|
||||||
|
heap.swapAt(parent, idx)
|
||||||
|
bubbleUp(idx: parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private mutating func heapify(_ idx: Int) {
|
||||||
|
let left = idx * 2 + 1
|
||||||
|
let right = idx * 2 + 2
|
||||||
|
var comp = idx
|
||||||
|
|
||||||
|
if heap.count > left && comparator(heap[left], heap[comp]) {
|
||||||
|
comp = left
|
||||||
|
}
|
||||||
|
if heap.count > right && comparator(heap[right], heap[comp]) {
|
||||||
|
comp = right
|
||||||
|
}
|
||||||
|
if comp != idx {
|
||||||
|
heap.swapAt(comp, idx)
|
||||||
|
heapify(comp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func insert(_ item: T) {
|
||||||
|
heap.append(item)
|
||||||
|
bubbleUp(idx: heap.count-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func pop() -> T? {
|
||||||
|
let item: T? = heap.first
|
||||||
|
if heap.count == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if heap.count > 1 {
|
||||||
|
heap[0] = heap[heap.count-1]
|
||||||
|
heap.removeLast()
|
||||||
|
heapify(0)
|
||||||
|
} else if heap.count == 1{
|
||||||
|
heap.removeLast()
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
3450
day18/input.txt
Normal file
3450
day18/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
25
day18/test.txt
Normal file
25
day18/test.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
5,4
|
||||||
|
4,2
|
||||||
|
4,5
|
||||||
|
3,0
|
||||||
|
2,1
|
||||||
|
6,3
|
||||||
|
2,4
|
||||||
|
1,5
|
||||||
|
0,6
|
||||||
|
3,3
|
||||||
|
2,6
|
||||||
|
5,1
|
||||||
|
1,2
|
||||||
|
5,5
|
||||||
|
2,5
|
||||||
|
6,5
|
||||||
|
1,4
|
||||||
|
0,4
|
||||||
|
6,4
|
||||||
|
1,1
|
||||||
|
6,1
|
||||||
|
1,0
|
||||||
|
0,5
|
||||||
|
1,6
|
||||||
|
2,0
|
Reference in New Issue
Block a user