2023 day 08

This commit is contained in:
tristan 2023-12-09 15:39:30 +00:00
parent b54d01e43a
commit 9b5de2f13e
10 changed files with 1114 additions and 0 deletions

43
2023/08/part2/cmd/main.go Normal file
View file

@ -0,0 +1,43 @@
package main
import (
"bufio"
"os"
"fmt"
"git.tristans.cloud/tristan/aoc/2023/08/part2/part2"
"git.tristans.cloud/tristan/aoc/2023/08/part1/part1"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin);
ins, err := reader.ReadString('\n');
if err != nil {
fmt.Println("Halted too soon!")
return
}
ins = strings.Trim(ins, "\n")
_, err = reader.ReadString('\n');
if err != nil {
fmt.Println("Halted too soon!")
return
}
net := part1.Network{}
for {
line, err := reader.ReadString('\n');
if err != nil {
break
}
err = part1.AddToNet(net, line)
if err != nil {
fmt.Println(err, line, net)
}
}
steps, err := part2.StepsToSolveAll(ins, net)
if (err != nil) {
fmt.Println(err)
}
fmt.Println(steps)
}

10
2023/08/part2/example.txt Normal file
View file

@ -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)

View file

@ -0,0 +1,84 @@
package part2
import (
"fmt"
"git.tristans.cloud/tristan/aoc/2023/08/part1/part1"
)
type Network = part1.Network
const start = 'A'
const goal = 'Z'
func StepsToSolveAll(ins string, net Network) (int, error) {
current := GetStarts(net)
res := 1
for _,start := range current {
_, steps, err := StepsToSolve(ins, net, start)
if err != nil {
return 0, err
}
// I expected I'd have to do a bit more than that!
res = LCM(res, steps)
}
return res, nil
}
func GetStarts(net Network) (current []string) {
for key := range net {
if key[2] == start {
current = append(current, key)
}
}
return
}
func IsDone(state []string) bool {
for _,key := range state {
if key[2] != goal {
return false
}
}
return true
}
func StepsToSolve(ins string, net Network, start string) (int, int, error) {
current := start
steps := 0;
history := []string{current}
for {
switch ins[steps % len(ins)] {
case 'L':
current = net[current][0]
case 'R':
current = net[current][1]
default:
return 0, 0, fmt.Errorf("instructions unclear! Must only be 'R' and 'L', but got '%c' at [%v]", ins[steps], steps)
}
steps ++
for step, state := range history {
if state == current && step == steps % len(ins) {
return step, steps-step, nil
}
}
history = append(history, current)
}
}
// greatest common divisor (GCD) via Euclidean algorithm
func GCD(a, b int) int {
for b != 0 {
t := b
b = a % b
a = t
}
return a
}
// find Least Common Multiple (LCM) via GCD
func LCM(a, b int, integers ...int) int {
return a * b / GCD(a, b)
}

View file

@ -0,0 +1,81 @@
package part2
import (
"testing"
"reflect"
"sort"
)
func TestGetStarts(t *testing.T) {
net := Network{
"11A": [2]string{"11B", "XXX"},
"11B": [2]string{"XXX", "11Z"},
"11Z": [2]string{"11B", "XXX"},
"22A": [2]string{"22B", "XXX"},
"22B": [2]string{"22C", "22C"},
"22C": [2]string{"22Z", "22Z"},
"22Z": [2]string{"22B", "22B"},
"XXX": [2]string{"XXX", "XXX"},
}
starts := GetStarts(net);
sort.Strings(starts)
equal(t, starts, []string{"11A", "22A"})
}
func TestIsDone(t *testing.T) {
equal(t, IsDone([]string{"ABZ", "11Z"}), true)
equal(t, IsDone([]string{"ABC", "11Z"}), false)
}
func TestStepsToSolveAll(t *testing.T) {
net := Network{
"11A": [2]string{"11B", "XXX"},
"11B": [2]string{"XXX", "11Z"},
"11Z": [2]string{"11B", "XXX"},
"22A": [2]string{"22B", "XXX"},
"22B": [2]string{"22C", "22C"},
"22C": [2]string{"22Z", "22Z"},
"22Z": [2]string{"22B", "22B"},
"XXX": [2]string{"XXX", "XXX"},
}
steps, err := StepsToSolveAll("LR", net)
equal(t, err, nil)
equal(t, steps, 6)
}
func TestStepsToSolve(t *testing.T) {
net := Network{
"11A": [2]string{"11B", "XXX"},
"11B": [2]string{"XXX", "11Z"},
"11Z": [2]string{"11B", "XXX"},
"22A": [2]string{"22B", "XXX"},
"22B": [2]string{"22C", "22C"},
"22C": [2]string{"22Z", "22Z"},
"22Z": [2]string{"22B", "22B"},
"XXX": [2]string{"XXX", "XXX"},
}
start, steps, err := StepsToSolve("RL", net, "11B")
equal(t, err, nil)
equal(t, start, 0)
equal(t, steps, 2)
start, steps, err = StepsToSolve("LR", net, "11A")
equal(t, err, nil)
equal(t, start, 1)
equal(t, steps, 2)
start, steps, err = StepsToSolve("LR", net, "22A")
equal(t, err, nil)
equal(t, start, 1)
equal(t, steps, 6)
}
func TestLCM(t *testing.T) {
equal(t, LCM(2,3), 6)
}
func equal(t *testing.T, actual any, target any) {
if !reflect.DeepEqual(actual, target) {
t.Errorf("expected '%v', got '%v'", target, actual)
}
}