]> fbox.kageds.com Git - adventofcode.git/blob - 2023/go/utils/utils.go
day05
[adventofcode.git] / 2023 / go / 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 ReadfileAsSlice(day int) []string {
108 filename := fmt.Sprintf("day%02d/input.txt", day)
109 file, err := os.Open(filename)
110 PanicOnErr(err)
111 defer file.Close()
112
113 arr := make([]string, 0)
114 sc := bufio.NewScanner(file)
115 for sc.Scan() {
116 arr = append(arr, sc.Text())
117 }
118
119 return arr
120 }
121
122 func ParseToStruct(re *regexp.Regexp, input string, target interface{}) bool {
123 m := re.FindStringSubmatch(input)
124 if m == nil {
125 return false
126 }
127
128 var useOffset bool
129
130 for i, name := range re.SubexpNames() {
131 if i == 0 {
132 continue
133 }
134 var field reflect.Value
135 if name == "" {
136 // use offset
137 if i == 1 {
138 useOffset = true
139 } else if !useOffset {
140 panic("can't mix named and unnamed subexpressions")
141 }
142 field = reflect.ValueOf(target).Elem().Field(i - 1)
143 } else {
144 // use name
145 if i == 1 {
146 useOffset = false
147 } else if useOffset {
148 panic("can't mix named and unnamed subexpressions")
149 }
150 field = reflect.ValueOf(target).Elem().FieldByName(name)
151 }
152 if field.Kind() == reflect.String {
153 field.SetString(m[i])
154 } else if field.Kind() == reflect.Int {
155 v, err := strconv.Atoi(m[i])
156 PanicOnErr(err)
157 field.SetInt(int64(v))
158 } else if field.Kind() == reflect.Uint8 {
159 if len(m[i]) != 1 {
160 panic(fmt.Sprintf("expecting 1 char, got: %s", m[i]))
161 }
162 field.SetUint(uint64(m[i][0]))
163 } else {
164 panic(fmt.Sprintf("unknown kind: %s", field.Kind()))
165 }
166 }
167 return true
168 }
169
170 func MustParseToStruct(re *regexp.Regexp, input string, target interface{}) {
171 if !ParseToStruct(re, input, target) {
172 panic(fmt.Errorf("failed to parse: %s", input))
173 }
174 }
175
176 func CharToLower(c byte) byte {
177 return strings.ToLower(string(c))[0]
178 }
179
180 func CharToUpper(c byte) byte {
181 return strings.ToUpper(string(c))[0]
182 }
183
184 func Contains(haystack []string, needle string) bool {
185 for _, s := range haystack {
186 if s == needle {
187 return true
188 }
189 }
190 return false
191 }
192
193 func Abs[T constraints.Signed](x T) T {
194 if x < 0 {
195 return -x
196 }
197 return x
198 }
199
200 func Gcd(x, y int) int {
201 if x <= 0 || y <= 0 {
202 panic(fmt.Errorf("invalid input: %d, %d", x, y))
203 }
204 if x == y {
205 return x
206 }
207 if x > y {
208 return Gcd(x-y, y)
209 } else {
210 return Gcd(x, y-x)
211 }
212 }
213
214 func Sign[T constraints.Signed](x T) int {
215 if x < 0 {
216 return -1
217 } else if x > 0 {
218 return 1
219 } else {
220 return 0
221 }
222 }