112 lines
2.1 KiB
Go
112 lines
2.1 KiB
Go
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
|
|
}
|