advent-of-code/aoc2023/day08/main.go

150 lines
2.8 KiB
Go
Raw Normal View History

2023-12-08 15:11:24 -07:00
package main
import (
"bufio"
"fmt"
"os"
"strings"
2023-12-08 16:24:48 -07:00
2023-12-15 15:13:24 -07:00
aoc "go.sour.is/advent-of-code"
2023-12-08 15:11:24 -07:00
)
func main() {
2023-12-08 16:24:48 -07:00
result, err := aoc.Runner(run)
2023-12-08 15:11:24 -07:00
if err != nil {
fmt.Println("ERR", err)
os.Exit(1)
}
fmt.Println("result", result)
}
type result struct {
2023-12-08 16:24:48 -07:00
stepsPT1 uint64
2023-12-08 15:11:24 -07:00
stepsPT2 uint64
}
2023-12-08 16:24:48 -07:00
func (r result) String() string {
return fmt.Sprintf("solution 1: %v\nsolution 2: %v\n", r.stepsPT1, r.stepsPT2)
}
2023-12-08 15:11:24 -07:00
func run(scan *bufio.Scanner) (*result, error) {
var path []rune
m := make(nodeMap)
for scan.Scan() {
text := scan.Text()
if len(text) == 0 {
continue
}
if len(path) == 0 {
fmt.Println("path", text)
path = []rune(strings.TrimSpace(text))
continue
}
n := &node{}
i, err := fmt.Sscanf(text, "%s = (%s %s", &n.value, &n.lvalue, &n.rvalue)
if err != nil {
return nil, err
}
n.lvalue = strings.TrimRight(n.lvalue, ",)")
n.rvalue = strings.TrimRight(n.rvalue, ",)")
m[n.value] = n
fmt.Println("value", i, n.value, n.lvalue, n.rvalue)
}
if err := m.mapNodes(); err != nil {
return nil, err
}
2023-12-08 16:24:48 -07:00
steps1 := m.SolvePT1(path)
steps2 := m.SolvePT2(path)
2023-12-08 15:11:24 -07:00
return &result{steps1, steps2}, nil
}
type node struct {
value string
lvalue, rvalue string
left, right *node
}
type nodeMap map[string]*node
func (m nodeMap) mapNodes() error {
for k, v := range m {
if ptr, ok := m[v.lvalue]; ok {
v.left = ptr
} else {
return fmt.Errorf("%s L-> %s not found", k, v.lvalue)
}
if ptr, ok := m[v.rvalue]; ok {
v.right = ptr
} else {
return fmt.Errorf("%s R-> %s not found", k, v.rvalue)
}
m[k] = v
}
return nil
}
2023-12-08 16:24:48 -07:00
func (m nodeMap) solver(start string, isEnd func(string) bool, path []rune) uint64 {
position, ok := m[start]
2023-12-08 15:11:24 -07:00
if !ok {
return 0
}
var i int
2023-12-08 16:24:48 -07:00
var steps uint64
2023-12-08 15:11:24 -07:00
2023-12-08 16:24:48 -07:00
for steps < ^uint64(0) {
2023-12-08 15:11:24 -07:00
steps++
if path[i] == 'R' {
2023-12-08 16:24:48 -07:00
// fmt.Println("step", steps, position.value, "R->", position.rvalue)
2023-12-08 15:11:24 -07:00
position = position.right
} else {
2023-12-08 16:24:48 -07:00
// fmt.Println("step", steps, position.value, "L->", position.lvalue)
2023-12-08 15:11:24 -07:00
position = position.left
}
2023-12-08 16:24:48 -07:00
if isEnd(position.value) {
2023-12-08 15:11:24 -07:00
break
}
i++
if i > len(path)-1 {
i = 0
}
}
return steps
}
2023-12-08 16:24:48 -07:00
func (m nodeMap) SolvePT1(path []rune) uint64 {
fmt.Println("---- PART 1 BEGIN ----")
defer fmt.Println("---- PART 1 END ----")
return m.solver("AAA", func(s string) bool { return s == "ZZZ" }, path)
}
func (m nodeMap) SolvePT2(path []rune) uint64 {
2023-12-08 15:11:24 -07:00
fmt.Println("---- PART 2 BEGIN ----")
2023-12-08 16:24:48 -07:00
defer fmt.Println("---- PART 2 END ----")
2023-12-08 15:11:24 -07:00
2023-12-08 16:24:48 -07:00
var starts []*node
2023-12-08 15:11:24 -07:00
for k, n := range m {
if strings.HasSuffix(k, "A") {
fmt.Println("start", k)
2023-12-08 16:24:48 -07:00
starts = append(starts, n)
2023-12-08 15:11:24 -07:00
}
}
2023-12-08 16:24:48 -07:00
loops := make([]uint64, len(starts))
for i, n := range starts {
loops[i] = m.solver(n.value, func(s string) bool { return strings.HasSuffix(s, "Z") }, path)
2023-12-08 15:11:24 -07:00
}
2023-12-08 16:24:48 -07:00
return aoc.LCM(loops...)
2023-12-08 15:11:24 -07:00
}