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
|
package main
import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"
)
func main() {
fmt.Println(part1(readData("example.txt")))
fmt.Println(part1(readData("data.txt")))
fmt.Println(part2(readData("example.txt")))
fmt.Println(part2(readData("data.txt")))
}
type Case struct {
target int64
operands []int64
}
func part1(cases []Case) (sumOk int64) {
for _, c := range cases {
if canReach(c.target, 0, c.operands) {
sumOk += c.target
}
}
return
}
func part2(cases []Case) (sumOk int64) {
for _, c := range cases {
if canReach2(c.target, 0, c.operands) {
sumOk += c.target
}
}
return
}
func concatenate(a int64, b int64) int64 {
bDecimalLength := len(strconv.FormatInt(b, 10))
return a*int64(math.Pow(10, float64(bDecimalLength))) + b
}
func canReach(target int64, currentTotal int64, operands []int64) bool {
if len(operands) == 0 {
return target == currentTotal
}
if currentTotal > target {
return false
}
return canReach(target, currentTotal+operands[0], operands[1:]) ||
canReach(target, currentTotal*operands[0], operands[1:])
}
func canReach2(target int64, currentTotal int64, operands []int64) bool {
if len(operands) == 0 {
return target == currentTotal
}
if currentTotal > target {
return false
}
return canReach2(target, currentTotal+operands[0], operands[1:]) ||
canReach2(target, currentTotal*operands[0], operands[1:]) ||
canReach2(target, concatenate(currentTotal, operands[0]), operands[1:])
}
func readData(fileName string) (cases []Case) {
fp, err := os.Open(fileName)
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := scanner.Text()
splitColon := strings.Split(line, ":")
if len(splitColon) != 2 {
panic("Not enough data")
}
target, err := strconv.ParseInt(splitColon[0], 10, 64)
if err != nil {
panic(err)
}
operandsStr := strings.Split(strings.TrimSpace(splitColon[1]), " ")
operands := make([]int64, len(operandsStr))
for i, s := range operandsStr {
n, err := strconv.ParseInt(s, 10, 64)
if err != nil {
panic(err)
}
operands[i] = n
}
cases = append(cases, Case{target, operands})
}
return
}
|