advent-of-code/day08/main.go
2023-12-08 21:30:49 -07:00

151 lines
2.8 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strings"
aoc "go.sour.is/advent-of-code-2023"
)
func main() {
result, err := aoc.Runner(run)
if err != nil {
fmt.Println("ERR", err)
os.Exit(1)
}
fmt.Println("result", result)
}
type result struct {
stepsPT1 uint64
stepsPT2 uint64
}
func (r result) String() string {
return fmt.Sprintf("solution 1: %v\nsolution 2: %v\n", r.stepsPT1, r.stepsPT2)
}
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
}
steps1 := m.SolvePT1(path)
steps2 := m.SolvePT2(path)
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
}
func (m nodeMap) solver(start string, isEnd func(string) bool, path []rune) uint64 {
position, ok := m[start]
if !ok {
return 0
}
var i int
var steps uint64
for steps < ^uint64(0) {
steps++
if path[i] == 'R' {
// fmt.Println("step", steps, position.value, "R->", position.rvalue)
position = position.right
} else {
// fmt.Println("step", steps, position.value, "L->", position.lvalue)
position = position.left
}
if isEnd(position.value) {
break
}
i++
if i > len(path)-1 {
i = 0
}
}
return steps
}
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 {
fmt.Println("---- PART 2 BEGIN ----")
defer fmt.Println("---- PART 2 END ----")
var starts []*node
for k, n := range m {
if strings.HasSuffix(k, "A") {
fmt.Println("start", k)
starts = append(starts, n)
}
}
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)
}
return aoc.LCM(loops...)
}