diff --git a/2023/day08_left_right.go b/2023/day08_left_right.go index fa45d0c..1382db2 100644 --- a/2023/day08_left_right.go +++ b/2023/day08_left_right.go @@ -44,11 +44,66 @@ func move(current string, step int, leftRight string, nodes map[string][2]string func Day08Part2(input io.Reader) (int, error) { scanner := bufio.NewScanner(input) + scanner.Scan() + leftRight := scanner.Text() + + scanner.Scan() // skip blank line + + nodes := make(map[string][2]string) + var positions []string for scanner.Scan() { - line := scanner.Text() - _ = line + line := strings.Split(scanner.Text(), " = ") // AAA = (BBB, CCC) + node := line[0] + rest := strings.Split(strings.NewReplacer("(", "", " ", "", ")", "").Replace(line[1]), ",") + nodes[node] = [2]string{rest[0], rest[1]} + if strings.HasSuffix(node, "A") { + positions = append(positions, node) + } } - return 0, nil + step := 0 + reachedZ := make([]int, len(positions)) + for !allFinished(positions, reachedZ, step) { + for i := 0; i < len(positions); i++ { + positions[i] = move(positions[i], step, leftRight, nodes) + } + step++ + } + + return LCM(reachedZ[0], reachedZ[1], reachedZ[2:]...), nil +} + +func allFinished(positions []string, reachedZ []int, step int) bool { + for i, pos := range positions { + if strings.HasSuffix(pos, "Z") && reachedZ[i] == 0 { + reachedZ[i] = step + } + } + for _, z := range reachedZ { + if z == 0 { + return false + } + } + return true +} + +// GCD and LCM from https://siongui.github.io/2017/06/03/go-find-lcm-by-gcd/ +func GCD(a, b int) int { + for b != 0 { + t := b + b = a % b + a = t + } + return a +} + +func LCM(a, b int, integers ...int) int { + result := a * b / GCD(a, b) + + for i := 0; i < len(integers); i++ { + result = LCM(result, integers[i]) + } + + return result } diff --git a/2023/day08_left_right_test.go b/2023/day08_left_right_test.go index 796a9e8..3ce2e16 100644 --- a/2023/day08_left_right_test.go +++ b/2023/day08_left_right_test.go @@ -17,8 +17,8 @@ func TestDay08Part1(t *testing.T) { func TestDay08Part2(t *testing.T) { tests := []testCase{ - {"inputs/day08_test2", 0}, - {"inputs/day08", 0}, + {"inputs/day08_test3", 6}, + {"inputs/day08", 14265111103729}, } for _, test := range tests { t.Run(test.filename, check(test, Day08Part2)) diff --git a/2023/inputs/day08_test3 b/2023/inputs/day08_test3 new file mode 100644 index 0000000..5b3fa58 --- /dev/null +++ b/2023/inputs/day08_test3 @@ -0,0 +1,10 @@ +LR + +11A = (11B, XXX) +11B = (XXX, 11Z) +11Z = (11B, XXX) +22A = (22B, XXX) +22B = (22C, 22C) +22C = (22Z, 22Z) +22Z = (22B, 22B) +XXX = (XXX, XXX)