-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.go
127 lines (99 loc) · 2.64 KB
/
main.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
package main
import (
"fmt"
"strconv"
"strings"
"sync"
"github.com./believer/aoc-2024/utils"
"github.com./believer/aoc-2024/utils/files"
)
// Parallelization in Go is so nice and easy and provided a major speed-up
// in this case.
// Also reducing the amount of type conversions in the permutation
// generation made some improvement. We used to give it a []string and get back []string.
// The strings needed to be broken down into individual parts for calculations, so we
// could instead return a [][]string directly from the permutations.
func main() {
fmt.Println("Part 1: ", part1("input.txt"))
fmt.Println("Part 2: ", part2("input.txt"))
}
func part1(name string) int {
lines := files.ReadLines(name)
operators := []string{"+", "*"}
return processLines(lines, operators)
}
func part2(name string) int {
lines := files.ReadLines(name)
operators := []string{"+", "*", "||"}
return processLines(lines, operators)
}
// Each line is an independent expression, we can calculate them in parallel
func processLines(lines, operators []string) int {
results := make(chan int, len(lines))
var wg sync.WaitGroup
for _, line := range lines {
wg.Add(1)
go func(line string) {
defer wg.Done()
calibrationResult := evaluateLine(line, operators)
results <- calibrationResult
}(line)
}
go func() {
wg.Wait()
close(results)
}()
total := 0
for result := range results {
total += result
}
return total
}
func evaluateLine(line string, operators []string) int {
resultAsString, valuesAsString, _ := strings.Cut(line, ":")
values := strings.Split(strings.TrimSpace(valuesAsString), " ")
result := utils.MustIntFromString(resultAsString)
permutations := allPermutations(values, operators)
for _, expression := range permutations {
total := 0
operation := "+"
for _, v := range expression {
switch v {
case "+", "*", "||":
operation = v
continue
}
num := utils.MustIntFromString(v)
switch operation {
case "+":
total += num
case "*":
total *= num
case "||":
total = utils.MustIntFromString(strconv.Itoa(total) + v)
}
}
if total == result {
return total
}
}
return 0
}
func allPermutations(nums []string, ops []string) [][]string {
if len(nums) == 0 {
return nil
}
result := [][]string{}
generateExpressions(nums, ops, []string{nums[0]}, 1, &result)
return result
}
func generateExpressions(nums []string, ops []string, current []string, index int, result *[][]string) {
if index == len(nums) {
*result = append(*result, current)
return
}
for _, op := range ops {
next := append(current, op, nums[index])
generateExpressions(nums, ops, next, index+1, result)
}
}