adventOfCode/internal/2023/day_05/in.go

166 lines
3.6 KiB
Go

package day_05
import (
"fmt"
"math"
"regexp"
"strings"
"sync"
"git.rpjosh.de/RPJosh/go-logger"
"rpjosh.de/adventOfCode/pkg/utils"
)
type Day struct{}
func (d *Day) Part1(in string) string {
// Regex to get all numbers
numberRegex := regexp.MustCompile(`\d+`)
inSplit := strings.Split(in, "\n")
// Contains the previous values of the last "section"
lastValues := utils.ConvertArrayToInt(numberRegex.FindAllString(inSplit[0], -1))
// Copy last values for each mapping.
// It could be possible that an element is persent
// in multiple mapping values
lastValuesCurrMapp := make([]int, len(lastValues))
copy(lastValuesCurrMapp, lastValues)
for _, val := range inSplit[1:] {
// Get numbers of input
numbersString := numberRegex.FindAllString(val, -1)
numbers := utils.ConvertArrayToInt(numbersString)
// Re-Initialize values
if val == "" {
copy(lastValues, lastValuesCurrMapp)
}
// Don't do anything with invalid lines
if len(numbers) <= 2 {
continue
}
// Try to map the values
startDest := numbers[0]
startSource := numbers[1]
length := numbers[2]
logger.Debug("Found values %d %d %d", startDest, startSource, length)
// Try to find the value in lastValues
for v, val := range lastValues {
if val >= startSource && val < startSource+length {
diff := val - startSource
lastValuesCurrMapp[v] = startDest + diff
}
}
}
return fmt.Sprintf("%d", utils.GetMinValue(lastValues))
}
func (d *Day) Part2(in string) string {
// Regex to get all numbers
numberRegex := regexp.MustCompile(`\d+`)
inSplit := strings.Split(in, "\n")
offset := 0
// Multi thread
minValue := math.MaxInt32
var wg sync.WaitGroup
var mtx sync.Mutex
// Parse mapping once
mapping := make([][]int, 0)
for _, val := range inSplit[1:] {
// Get numbers of input
numbersString := numberRegex.FindAllString(val, -1)
numbers := utils.ConvertArrayToInt(numbersString)
if len(numbers) <= 2 && val != "" {
continue
}
mapping = append(mapping, numbers)
}
// Unfold paris of seed values
seeds := utils.ConvertArrayToInt(numberRegex.FindAllString(inSplit[offset], -1))
for i := 0; i+1 < len(seeds); i += 2 {
wg.Add(1)
go func(i int) {
lastMin := seeds[i]
for m := seeds[i]; m < seeds[i]+seeds[i+1]; m++ {
if m%5000000 == 0 {
logger.Debug("%d. Parsing %d", i, m)
}
// Bulk
if m%100000 == 0 || m == seeds[i]+seeds[i+1]-1 {
wg.Add(1)
go func(min, max int) {
rtc := d.ParseSingleFor2(min, max, &mapping)
mtx.Lock()
if rtc < minValue {
minValue = rtc
}
mtx.Unlock()
wg.Done()
}(lastMin, m)
lastMin = m
}
}
logger.Info("Finished %d", i)
wg.Done()
}(i)
// Limit max number of goroutines
if i != 0 && i%10 == 0 {
wg.Wait()
}
}
wg.Wait()
return fmt.Sprintf("%d", minValue)
}
func (d *Day) ParseSingleFor2(min int, max int, values *[][]int) int {
lastValues := make([]int, max-min)
for i := min; i < max; i++ {
lastValues[i-min] = i
}
// Copy last values for each mapping.
// It could be possible that an element is persent
// in multiple mapping values
lastValuesCurrMapp := make([]int, len(lastValues))
copy(lastValuesCurrMapp, lastValues)
for _, val := range *values {
// Re-Initialize values
if len(val) == 0 {
copy(lastValues, lastValuesCurrMapp)
continue
}
// Try to map the values
startDest := val[0]
startSource := val[1]
length := val[2]
// Try to find the value in lastValues
for v, val := range lastValues {
if val >= startSource && val < startSource+length {
diff := val - startSource
lastValuesCurrMapp[v] = startDest + diff
}
}
}
return utils.GetMinValue(lastValues)
}