2023: day 8
parent
15985840a4
commit
996b8bffd6
|
@ -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...))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:]...))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue