-
Notifications
You must be signed in to change notification settings - Fork 0
/
day18.swift
66 lines (59 loc) · 2.03 KB
/
day18.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//
// day18.swift
// aoc
//
// Created by Greg Titus on 12/17/24.
//
import Foundation
import Collections
func dayEighteen(_ contents: String, part1: Bool = false) -> Int {
let size = 71
struct Square {
var corrupt = false
}
struct Score: ScoreType {
var best = 0
var from: Position? = nil
static func < (lhs: Score, rhs: Score) -> Bool { lhs.best < rhs.best }
}
let grid = Grid(width: size, height: size, element: Square())
let corruptions = contents.matches(of: /([0-9]+),([0-9]+)/).map { Position(x: Int($0.1)!, y: Int($0.2)!) }
let start = Position(x: 0, y: 0)
let end = Position(x: size-1, y: size-1)
// find quickest path, and then return a set of positions in the path via backtracking
func solveAndGetPath() -> Set<Position>? {
let best = grid.bestMoves(from: PossibleMove(move: start, score: Score()), to: { $0 == end }) { grid, possible in
grid.cardinalDirections(from: possible.move)
.filter({ !grid[$0].corrupt })
.map({ PossibleMove(move: $0, score: Score(best: possible.score.best+1, from: possible.move)) })
}
guard best[end] != nil else { return nil }
var result: Set<Position> = []
var i = end
while i != start {
result.insert(i)
i = best[i]!.from!
}
return result
}
// place the first 1024 corrupt blocks
for i in corruptions[..<1024] {
grid[i].corrupt = true
}
if part1 { return grid.manhattanMoveDistance(from: start, to: end, allowed: { !$0.corrupt })! }
// solve, then place more corruptions until you corrupt a spot that was in the solved path
// when that happens, solve again
var path = solveAndGetPath()!
for i in corruptions[1024...] {
grid[i].corrupt = true
if path.contains(i) {
if let newPath = solveAndGetPath() {
path = newPath
} else {
print(i)
break
}
}
}
return 0
}