-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday17-1.go
130 lines (110 loc) · 2.4 KB
/
day17-1.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
118
119
120
121
122
123
124
125
126
127
128
129
130
package main
import (
"fmt"
"slices"
"strconv"
)
type day17Field [][]int
type day17Pos struct {
y, x int
}
type day17Move struct {
pos, dir day17Pos
}
type day17Acc struct {
move day17Move
loss int
}
var (
day17North day17Pos = day17Pos{-1, 0}
day17South day17Pos = day17Pos{1, 0}
day17East day17Pos = day17Pos{0, 1}
day17West day17Pos = day17Pos{0, -1}
)
var day17AllDir = []day17Pos{day17North, day17South, day17East, day17West}
func day17part1(filename string) (string, error) {
f, err := day17ReadMap(filename)
if err != nil {
return "", err
}
to := day17Pos{len(f) - 1, len(f[0]) - 1}
s := f.shortest4(day17Pos{0, 0}, to, 1, 3)
return fmt.Sprint(s), nil
}
func (f day17Field) shortest4(from, to day17Pos, minRoll, maxRoll int) int {
dist := make(map[day17Move]int)
vert := []day17Acc{{}}
for len(vert) > 0 {
slices.SortFunc(vert, func(a, b day17Acc) int {
return a.loss - b.loss
})
v := vert[0]
vert = vert[1:]
if v.move.pos == to {
return v.loss
}
if d, ok := dist[v.move]; ok && v.loss > d {
continue
}
for _, m := range f.nextMoves(v, minRoll, maxRoll) {
prev, ok := dist[m.move]
if !ok || m.loss < prev {
dist[m.move] = m.loss
vert = append(vert, m)
}
}
}
return 0
}
func (f day17Field) at(p day17Pos) int {
return f[p.y][p.x]
}
func (f day17Field) nextMoves(s day17Acc, minMoves, maxMoves int) []day17Acc {
var n []day17Acc
for _, d := range day17AllDir {
if d.sameOrReverse(s.move.dir) {
continue
}
nextLoss := s.loss
for i := 1; i <= maxMoves; i++ {
nextPos := day17Pos{s.move.pos.y + i*d.y, s.move.pos.x + i*d.x}
if !f.isValid(nextPos) {
continue
}
nextLoss += f.at(nextPos)
if i < minMoves {
continue
}
nextMove := day17Move{
pos: nextPos,
dir: d,
}
n = append(n, day17Acc{nextMove, nextLoss})
}
}
return n
}
func (f day17Field) isValid(p day17Pos) bool {
return p.y >= 0 && p.y < len(f) && p.x >= 0 && p.x < len(f[p.y])
}
func (d day17Pos) sameOrReverse(o day17Pos) bool {
return d == o || (d.y == -o.y && d.x == -o.x)
}
func day17ReadMap(filename string) (day17Field, error) {
var m day17Field
if err := forLineError(filename, func(line string) error {
var r []int
for _, v := range line {
n, err := strconv.Atoi(string(v))
if err != nil {
return err
}
r = append(r, n)
}
m = append(m, r)
return nil
}); err != nil {
return m, err
}
return m, nil
}