]> fbox.kageds.com Git - adventofcode.git/blob - 2023/gareth/utils/utils.go
day5 part2
[adventofcode.git] / 2023 / gareth / utils / utils.go
1 package utils
2
3 import (
4 "bufio"
5 "fmt"
6 "io"
7 "os"
8 "reflect"
9 "regexp"
10 "strconv"
11 "strings"
12
13 "golang.org/x/exp/constraints"
14 )
15
16 func PanicOnErr(err error) {
17 if err != nil {
18 panic(err)
19 }
20 }
21
22 const MaxInt = int(^uint(0) >> 1)
23 const MinInt = ^MaxInt
24
25 func Max[T constraints.Ordered](a, b T) T {
26 if a > b {
27 return a
28 }
29 return b
30 }
31
32 func Min[T constraints.Ordered](a, b T) T {
33 if a < b {
34 return a
35 }
36 return b
37 }
38
39 func SliceMinMax[T constraints.Ordered](slice []T) (*T, *T) {
40 if len(slice) == 0 {
41 return nil, nil
42 }
43 min := &slice[0]
44 max := &slice[0]
45 for i, v := range slice {
46 if v < *min {
47 min = &slice[i]
48 }
49 if v > *max {
50 max = &slice[i]
51 }
52 }
53 return min, max
54 }
55
56 func MustAtoi(s string) int {
57 v, err := strconv.Atoi(s)
58 PanicOnErr(err)
59 return v
60 }
61
62 // Returns key from map[T]int which has the max value
63 func MapFindMax(m interface{}) interface{} {
64 var maxK interface{} = nil
65 var maxV = MinInt
66 iter := reflect.ValueOf(m).MapRange()
67 for iter.Next() {
68 k := iter.Key()
69 v := int(iter.Value().Int())
70 if v > maxV {
71 maxV = v
72 maxK = k.Interface()
73 }
74 }
75 return maxK
76 }
77
78 // Returns key from map[T]int which has the min value
79 func MapFindMin(m interface{}) interface{} {
80 var minK interface{} = nil
81 var minV = MaxInt
82 iter := reflect.ValueOf(m).MapRange()
83 for iter.Next() {
84 k := iter.Key()
85 v := int(iter.Value().Int())
86 if v < minV {
87 minV = v
88 minK = k.Interface()
89 }
90 }
91 return minK
92 }
93
94 func Readfile(day int) string {
95 filename := fmt.Sprintf("day%02d/input.txt", day)
96 file, err := os.Open(filename)
97 PanicOnErr(err)
98 defer file.Close()
99
100 reader := bufio.NewReader(file)
101 contents, err := io.ReadAll(reader)
102 PanicOnErr(err)
103
104 return strings.TrimSuffix(string(contents), "\n")
105 }
106
107 func ParseToStruct(re *regexp.Regexp, input string, target interface{}) bool {
108 m := re.FindStringSubmatch(input)
109 if m == nil {
110 return false
111 }
112
113 var useOffset bool
114
115 for i, name := range re.SubexpNames() {
116 if i == 0 {
117 continue
118 }
119 var field reflect.Value
120 if name == "" {
121 // use offset
122 if i == 1 {
123 useOffset = true
124 } else if !useOffset {
125 panic("can't mix named and unnamed subexpressions")
126 }
127 field = reflect.ValueOf(target).Elem().Field(i - 1)
128 } else {
129 // use name
130 if i == 1 {
131 useOffset = false
132 } else if useOffset {
133 panic("can't mix named and unnamed subexpressions")
134 }
135 field = reflect.ValueOf(target).Elem().FieldByName(name)
136 }
137 if field.Kind() == reflect.String {
138 field.SetString(m[i])
139 } else if field.Kind() == reflect.Int {
140 v, err := strconv.Atoi(m[i])
141 PanicOnErr(err)
142 field.SetInt(int64(v))
143 } else if field.Kind() == reflect.Uint8 {
144 if len(m[i]) != 1 {
145 panic(fmt.Sprintf("expecting 1 char, got: %s", m[i]))
146 }
147 field.SetUint(uint64(m[i][0]))
148 } else {
149 panic(fmt.Sprintf("unknown kind: %s", field.Kind()))
150 }
151 }
152 return true
153 }
154
155 func MustParseToStruct(re *regexp.Regexp, input string, target interface{}) {
156 if !ParseToStruct(re, input, target) {
157 panic(fmt.Errorf("failed to parse: %s", input))
158 }
159 }
160
161 func CharToLower(c byte) byte {
162 return strings.ToLower(string(c))[0]
163 }
164
165 func CharToUpper(c byte) byte {
166 return strings.ToUpper(string(c))[0]
167 }
168
169 func Contains(haystack []string, needle string) bool {
170 for _, s := range haystack {
171 if s == needle {
172 return true
173 }
174 }
175 return false
176 }
177
178 func Abs[T constraints.Signed](x T) T {
179 if x < 0 {
180 return -x
181 }
182 return x
183 }
184
185 func Gcd(x, y int) int {
186 if x <= 0 || y <= 0 {
187 panic(fmt.Errorf("invalid input: %d, %d", x, y))
188 }
189 if x == y {
190 return x
191 }
192 if x > y {
193 return Gcd(x-y, y)
194 } else {
195 return Gcd(x, y-x)
196 }
197 }
198
199 func Sign[T constraints.Signed](x T) int {
200 if x < 0 {
201 return -1
202 } else if x > 0 {
203 return 1
204 } else {
205 return 0
206 }
207 }