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 }