From dd23f69ad19f6d9499ab2c6fc5d0d00412397651 Mon Sep 17 00:00:00 2001 From: "kyle.brown" Date: Sat, 7 Dec 2024 20:38:54 -0600 Subject: [PATCH] Solve 7 --- 7/main.go | 115 +++++++++++++++++++++++++ 7/main_test.go | 225 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 7/main.go create mode 100644 7/main_test.go diff --git a/7/main.go b/7/main.go new file mode 100644 index 0000000..43f60f8 --- /dev/null +++ b/7/main.go @@ -0,0 +1,115 @@ +package main + +import ( + "adventofcode2024/pkg/helper" + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" +) + +type calibrationData struct { + result int + numbers []int +} + +func main() { + f, err := os.Open("./7/input.txt") + if err != nil { + panic(err) + } + cData := getData(f) + _ = f.Close() + + start := time.Now() + res := sumValidCalibrationData(cData, false) + elapsed := time.Since(start) + fmt.Println(res) + fmt.Println(elapsed) + + start2 := time.Now() + res2 := sumValidCalibrationData(cData, true) + elapsed2 := time.Since(start2) + fmt.Println(res2) + fmt.Println(elapsed2) +} + +func sumValidCalibrationData(dataList []calibrationData, concatActive bool) int { + var acc int + for _, data := range dataList { + if isCalibrationDataPossible(data, concatActive) { + acc += data.result + } + } + return acc +} + +type operator int + +const ( + ADD operator = iota + MULT + CONCAT +) + +func isCalibrationDataPossible(data calibrationData, concatActive bool) bool { + operators := make([]operator, len(data.numbers)-1) + for { + acc := data.numbers[0] + for i := 1; i < len(data.numbers); i++ { + o := operators[i-1] + if o == ADD { + acc += data.numbers[i] + } else if o == CONCAT { + acc = helper.MustAtoI(strconv.Itoa(acc) + strconv.Itoa(data.numbers[i])) + } else { + acc *= data.numbers[i] + } + } + if acc == data.result { + return true + } + if !nextPermutation(operators, concatActive) { + return false + } + } +} + +func nextPermutation(operators []operator, concatActive bool) bool { + i := 0 + for ; i < len(operators); i++ { + o := operators[i] + if o == ADD { + operators[i] = MULT + return true + } else if concatActive && o == MULT { + operators[i] = CONCAT + return true + } else { + operators[i] = ADD + } + } + return !(i == len(operators) && operators[len(operators)-1] == ADD) +} + +func getData(f io.Reader) []calibrationData { + input := bufio.NewScanner(f) + + cData := make([]calibrationData, 0, 1000) + for input.Scan() { + line := input.Text() + parts := strings.Split(line, ":") + result := helper.MustAtoI(parts[0]) + inputs := strings.Split(strings.TrimSpace(parts[1]), " ") + inputList := make([]int, 0, len(inputs)) + for _, i := range inputs { + inputList = append(inputList, helper.MustAtoI(i)) + } + cData = append(cData, calibrationData{result: result, numbers: inputList}) + } + + return cData +} diff --git a/7/main_test.go b/7/main_test.go new file mode 100644 index 0000000..43bfc4e --- /dev/null +++ b/7/main_test.go @@ -0,0 +1,225 @@ +package main + +import ( + "reflect" + "testing" +) + +func Test_nextPermutation(t *testing.T) { + type args struct { + operators []operator + concatActive bool + } + type want struct { + result bool + operators []operator + } + tests := []struct { + name string + args args + want want + }{ + { + name: "single", + args: args{ + operators: []operator{ADD}, + }, + want: want{ + operators: []operator{MULT}, + result: true, + }, + }, + { + name: "single end of cycle", + args: args{ + operators: []operator{MULT}, + }, + want: want{ + operators: []operator{ADD}, + result: false, + }, + }, + { + name: "double no carry", + args: args{ + operators: []operator{ADD, ADD}, + }, + want: want{ + operators: []operator{MULT, ADD}, + result: true, + }, + }, + { + name: "double carry", + args: args{ + operators: []operator{MULT, ADD}, + }, + want: want{ + operators: []operator{ADD, MULT}, + result: true, + }, + }, + { + name: "double v2", + args: args{ + operators: []operator{ADD, MULT}, + }, + want: want{ + operators: []operator{MULT, MULT}, + result: true, + }, + }, + { + name: "double carry carry", + args: args{ + operators: []operator{MULT, MULT}, + }, + want: want{ + operators: []operator{ADD, ADD}, + result: false, + }, + }, + { + name: "triple", + args: args{ + operators: []operator{MULT, MULT, ADD}, + }, + want: want{ + operators: []operator{ADD, ADD, MULT}, + result: true, + }, + }, + { + name: "triple with concat", + args: args{ + concatActive: true, + operators: []operator{MULT, MULT, ADD}, + }, + want: want{ + operators: []operator{CONCAT, MULT, ADD}, + result: true, + }, + }, + { + name: "triple with concat 2", + args: args{ + concatActive: true, + operators: []operator{CONCAT, MULT, ADD}, + }, + want: want{ + operators: []operator{ADD, CONCAT, ADD}, + result: true, + }, + }, + { + name: "triple with concat 3", + args: args{ + concatActive: true, + operators: []operator{ADD, CONCAT, ADD}, + }, + want: want{ + operators: []operator{MULT, CONCAT, ADD}, + result: true, + }, + }, + { + name: "triple with concat 4", + args: args{ + concatActive: true, + operators: []operator{MULT, CONCAT, ADD}, + }, + want: want{ + operators: []operator{CONCAT, CONCAT, ADD}, + result: true, + }, + }, + { + name: "triple with concat 5", + args: args{ + concatActive: true, + operators: []operator{CONCAT, CONCAT, ADD}, + }, + want: want{ + operators: []operator{ADD, ADD, MULT}, + result: true, + }, + }, + { + name: "triple with concat Z", + args: args{ + concatActive: true, + operators: []operator{CONCAT, CONCAT, CONCAT}, + }, + want: want{ + operators: []operator{ADD, ADD, ADD}, + result: false, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := nextPermutation(tt.args.operators, tt.args.concatActive); got != tt.want.result { + t.Errorf("nextPermutation() = %v, want %v", got, tt.want) + } + if eq := reflect.DeepEqual(tt.args.operators, tt.want.operators); !eq { + t.Errorf("nextPermutation() array incorrect, got %v, want %v", tt.args.operators, tt.want.operators) + } + }) + } +} + +func Test_sumValidCalibrationData(t *testing.T) { + type args struct { + dataList []calibrationData + concatActive bool + } + tests := []struct { + name string + args args + want int + }{ + { + name: "example", + args: args{ + concatActive: false, + dataList: []calibrationData{ + {result: 190, numbers: []int{10, 19}}, + {result: 3267, numbers: []int{81, 40, 27}}, + {result: 83, numbers: []int{17, 5}}, + {result: 156, numbers: []int{15, 6}}, + {result: 7290, numbers: []int{6, 8, 6, 15}}, + {result: 161011, numbers: []int{16, 10, 13}}, + {result: 192, numbers: []int{17, 8, 14}}, + {result: 21037, numbers: []int{9, 7, 18, 13}}, + {result: 292, numbers: []int{11, 6, 16, 20}}, + }, + }, + want: 3749, + }, + { + name: "example", + args: args{ + concatActive: true, + dataList: []calibrationData{ + {result: 190, numbers: []int{10, 19}}, + {result: 3267, numbers: []int{81, 40, 27}}, + {result: 83, numbers: []int{17, 5}}, + {result: 156, numbers: []int{15, 6}}, + {result: 7290, numbers: []int{6, 8, 6, 15}}, + {result: 161011, numbers: []int{16, 10, 13}}, + {result: 192, numbers: []int{17, 8, 14}}, + {result: 21037, numbers: []int{9, 7, 18, 13}}, + {result: 292, numbers: []int{11, 6, 16, 20}}, + }, + }, + want: 11387, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := sumValidCalibrationData(tt.args.dataList, tt.args.concatActive); got != tt.want { + t.Errorf("sumValidCalibrationData() = %v, want %v", got, tt.want) + } + }) + } +}