-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday19-2.go
122 lines (116 loc) · 2.42 KB
/
day19-2.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
package main
import (
"fmt"
"slices"
)
type day19Range struct {
lo, hi []int
}
type day19Set struct {
flow string
val day19Range
}
func day19part2(filename string) (string, error) {
f, err := day19ReadPlan(filename)
if err != nil {
return "", err
}
var acc []day19Range
q := []day19Set{{
flow: "in",
val: day19Range{
lo: []int{1, 1, 1, 1},
hi: []int{4000, 4000, 4000, 4000},
},
}}
for len(q) > 0 {
next := q[0]
q = q[1:]
sets := []day19Set{next}
for _, rule := range f.rules[next.flow] {
var nextSets []day19Set
for _, set := range sets {
for _, nextSet := range rule.split(set) {
switch nextSet.flow {
case "A":
acc = append(acc, nextSet.val)
case "R":
continue
case next.flow:
nextSets = append(nextSets, nextSet)
default:
q = append(q, nextSet)
}
}
}
sets = nextSets
}
}
var total int
for _, v := range acc {
one := 1
for i := 0; i < len(v.lo); i++ {
one *= v.hi[i] - v.lo[i] + 1
}
total += one
}
return fmt.Sprint(total), nil
}
func (r day19Rule) split(set day19Set) []day19Set {
var res []day19Set
switch r.cond {
case day19CondPass:
res = append(res, day19Set{
flow: r.out,
val: set.val,
})
case day19CondLess:
if set.val.lo[r.part] < r.cmp && set.val.hi[r.part] >= r.cmp {
setLo := day19Set{
flow: r.out,
val: set.val.with(r.part, set.val.lo[r.part], r.cmp-1),
}
setHi := day19Set{
flow: set.flow,
val: set.val.with(r.part, r.cmp, set.val.hi[r.part]),
}
res = append(res, setLo, setHi)
} else if set.val.lo[r.part] >= r.cmp {
res = append(res, set)
} else if set.val.hi[r.part] < r.cmp {
res = append(res, day19Set{
flow: r.out,
val: set.val,
})
}
case day19CondMore:
if set.val.lo[r.part] <= r.cmp && set.val.hi[r.part] > r.cmp {
setLo := day19Set{
flow: set.flow,
val: set.val.with(r.part, set.val.lo[r.part], r.cmp),
}
setHi := day19Set{
flow: r.out,
val: set.val.with(r.part, r.cmp+1, set.val.hi[r.part]),
}
res = append(res, setLo, setHi)
} else if set.val.lo[r.part] <= r.cmp {
res = append(res, set)
} else if set.val.hi[r.part] > r.cmp {
res = append(res, day19Set{
flow: r.out,
val: set.val,
})
}
}
return res
}
func (r day19Range) with(part, lo, hi int) day19Range {
res := day19Range{
lo: slices.Clone(r.lo),
hi: slices.Clone(r.hi),
}
res.lo[part] = lo
res.hi[part] = hi
return res
}