2023: day 8
parent
15985840a4
commit
996b8bffd6
|
@ -1,11 +1,126 @@
|
|||
package day_08
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"rpjosh.de/adventOfCode/pkg/utils"
|
||||
)
|
||||
|
||||
type Day struct{}
|
||||
|
||||
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 {
|
||||
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...))
|
||||
}
|
||||
|
|
|
@ -150,3 +150,26 @@ func SortRunes(value string) string {
|
|||
func ReplaceCharacterInString(str, replace string, index int) string {
|
||||
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:]...))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue