summaryrefslogtreecommitdiff
path: root/day7/main.go
blob: fd20d4f505473e87174d3274b5ca9b9b297b40bc (plain)
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
}