2023 day 08
This commit is contained in:
parent
b54d01e43a
commit
9b5de2f13e
10 changed files with 1114 additions and 0 deletions
43
2023/08/part2/cmd/main.go
Normal file
43
2023/08/part2/cmd/main.go
Normal 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
10
2023/08/part2/example.txt
Normal 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)
|
84
2023/08/part2/part2/part2.go
Normal file
84
2023/08/part2/part2/part2.go
Normal 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)
|
||||
}
|
||||
|
81
2023/08/part2/part2/part2_test.go
Normal file
81
2023/08/part2/part2/part2_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue