-
Notifications
You must be signed in to change notification settings - Fork 0
/
day12.go
117 lines (103 loc) · 2.42 KB
/
day12.go
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package main
import (
"io"
"math"
"github.com/armsnyder/aoc2022/aocutil"
)
var _ = declareDay(12, func(part2 bool, inputReader io.Reader) any {
if part2 {
return day12Part2(inputReader)
}
return day12Part1(inputReader)
})
func day12Part1(inputReader io.Reader) any {
// This should have been a fun A* problem, but I decided to use a modified Dijkstra, since it is
// orders of magnitude more efficient at this problem's scale.
grid, width, start, end := day12Parse(inputReader)
distances := make([]int, len(grid))
for i := range distances {
distances[i] = math.MaxInt
}
distances[start] = 0
queue := make([]int, 0, len(grid))
queue = append(queue, start)
for len(queue) > 0 {
cur := queue[0]
queue = queue[1:]
for _, dir := range []int{1, -1, width, -width} {
neighbor := cur + dir
if neighbor < 0 || neighbor >= len(grid) {
continue
}
if grid[cur]+1 < grid[neighbor] {
continue
}
newDist := distances[cur] + 1
oldDist := distances[neighbor]
if newDist >= oldDist {
continue
}
distances[neighbor] = newDist
queue = append(queue, neighbor)
}
}
return distances[end]
}
func day12Part2(inputReader io.Reader) any {
grid, width, _, end := day12Parse(inputReader)
distances := make([]int, len(grid))
for i := range distances {
distances[i] = math.MaxInt
}
distances[end] = 0
queue := make([]int, 0, len(grid))
queue = append(queue, end)
minDistanceToA := math.MaxInt
for len(queue) > 0 {
cur := queue[0]
queue = queue[1:]
for _, dir := range []int{1, -1, width, -width} {
neighbor := cur + dir
if neighbor < 0 || neighbor >= len(grid) {
continue
}
if grid[cur] > grid[neighbor]+1 {
continue
}
newDist := distances[cur] + 1
if newDist >= minDistanceToA {
continue
}
oldDist := distances[neighbor]
if newDist >= oldDist {
continue
}
distances[neighbor] = newDist
queue = append(queue, neighbor)
if grid[neighbor] == 'a' {
minDistanceToA = newDist
}
}
}
return minDistanceToA
}
func day12Parse(inputReader io.Reader) (grid []byte, width, start, end int) {
var height int
grid = make([]byte, 0, 154*41)
aocutil.VisitStrings(inputReader, func(v []byte) {
width = len(v)
for i, ch := range v {
switch ch {
case 'S':
start = width*height + i
v[i] = 'a'
case 'E':
end = width*height + i
v[i] = 'z'
}
}
grid = append(grid, v...)
height++
})
return grid, width, start, end
}