2023: day 8

master
Jonas Letzbor 2023-12-08 13:28:54 +01:00
parent 15985840a4
commit 996b8bffd6
Signed by: RPJosh
GPG Key ID: 46D72F589702E55A
2 changed files with 140 additions and 2 deletions

View File

@ -1,11 +1,126 @@
package day_08 package day_08
import (
"fmt"
"regexp"
"strings"
"rpjosh.de/adventOfCode/pkg/utils"
)
type Day struct{} type Day struct{}
func (d *Day) Part1(in string) string { func (d *Day) Part1(in string) string {
return "" inSplit := strings.Split(in, "\n")
// Initialize variables
instructions := inSplit[0]
line := 0
instructionCounter := 0
instructionRegex := regexp.MustCompile(`[ \(](?P<primary>\w+)[,\)]`)
steps := 0
// Build indexed map for better performance
instructionMap := make(map[string]int, 0)
for i, val := range inSplit {
if i > 1 && len(val) > 2 {
v := val[0:3]
instructionMap[v] = i
// Found start
if v == "AAA" {
line = i
}
}
}
// Find destination
for {
// Start by first instruction on end
if instructionCounter >= len(instructions) {
instructionCounter = 0
}
// Get left or right
instructionIndex := 0
if instructions[instructionCounter] == 'R' {
instructionIndex = 1
}
// Get the next instruction to move on
next := instructionRegex.FindAllStringSubmatch(inSplit[line], -1)[instructionIndex]
line = instructionMap[next[1]]
//logger.Debug("Going to %q on line %d", next[1], line)
steps++
instructionCounter++
// Did we reach the end?
if strings.HasPrefix(next[1], "ZZZ") {
break
}
}
return fmt.Sprintf("%d", steps)
} }
func (d *Day) Part2(in string) string { func (d *Day) Part2(in string) string {
return "" inSplit := strings.Split(in, "\n")
// Initialize variables
instructions := inSplit[0]
starts := make([]int, 0)
stepsByStarts := make([]int, 0)
instructionRegex := regexp.MustCompile(`[ \(](?P<primary>\w+)[,\)]`)
// Build map for better performance
instructionMap := make(map[string]int, 0)
for i, val := range inSplit {
if i > 1 && len(val) > 2 {
v := val[0:3]
instructionMap[v] = i
// Found start
if v[2] == 'A' {
starts = append(starts, i)
}
}
}
// Find for each starting point the amount of steps that we need to go to the
// first 'Z'.
// The input data makes sure that the way back from a Z Node to another Z Node
// is always the same as from start to the first Z node.
// How would you find out without looping the first time!
for _, val := range starts {
steps := 0
line := val
instructionCounter := 0
for {
// Start by first instruction on end
if instructionCounter >= len(instructions) {
instructionCounter = 0
}
// Get left or right
instructionIndex := 0
if instructions[instructionCounter] == 'R' {
instructionIndex = 1
}
next := instructionRegex.FindAllStringSubmatch(inSplit[line], -1)[instructionIndex]
line = instructionMap[next[1]]
//logger.Debug("%d. Going to %q on line %d", i, next[1], line)
steps++
instructionCounter++
if next[1][2] == 'Z' {
break
}
}
stepsByStarts = append(stepsByStarts, steps)
}
return fmt.Sprintf("%d", utils.CalculateLCM(stepsByStarts...))
} }

View File

@ -150,3 +150,26 @@ func SortRunes(value string) string {
func ReplaceCharacterInString(str, replace string, index int) string { func ReplaceCharacterInString(str, replace string, index int) string {
return str[:index] + replace + str[index+1:] return str[:index] + replace + str[index+1:]
} }
// CalculateGCD (greates common divisor) calculates the biggest
// positive integer that is divisible by a and b
func CalculateGCD(a, b int) int {
for b != 0 {
t := b
b = a % b
a = t
}
return a
}
// CalculateLCM (least common multiple) calculates the smallest
// positive integer that is divisible by all numbers
func CalculateLCM(ints ...int) int {
if len(ints) == 1 {
return ints[0]
} else if len(ints) == 2 {
return ints[0] * ints[1] / CalculateGCD(ints[0], ints[1])
}
return CalculateLCM(ints[0], CalculateLCM(ints[1:]...))
}