aoc2023/day-5/two.go

90 lines
1.8 KiB
Go

package main
import (
"math"
"sync"
)
var wg sync.WaitGroup
var mu sync.Mutex
const UNLIMITED = -1
// bound represents the lower and upper limits of a single range
type bound struct {
lower, upper int
}
// newBound returns a bound type
// it defines an open ended interval
func newBound(lower, upper int) bound {
return bound{lower: lower, upper: upper - 1}
}
// nextTransform recursively calculates each new set of seed ranges for each set of data in dataMap
func nextTransform(i int, in []bound) []bound {
if i == len(identifiers) {
return in
}
q := newQueue(UNLIMITED, in)
in = make([]bound, 0)
for !q.isEmpty() {
r := q.dequeue()
hasOverlap := func() bool {
for _, data := range dataMap[identifiers[i]] {
start := max(r.lower, data.source)
end := min(r.upper, data.source+data.offset)
if isOverlapping(start, end) {
// add new seed range
in = append(in, newBound(data.transform(start, end)))
// append unmatched portions of seed range back into queue
if start > r.lower {
q.enqueue(newBound(r.lower, start))
}
if r.upper > end {
q.enqueue(newBound(end, r.upper))
}
return true
}
}
return false
}()
// there was no overlap, add the seed range as is
if !hasOverlap {
in = append(in, r)
}
}
return nextTransform(i+1, in)
}
// two returns the lowest location for any seed in seedRanges
func two(lines []string) int {
var seedRanges = []bound{}
for i := 0; i < len(seeds); i += 2 {
wg.Add(1)
go func(i int) {
defer wg.Done()
mu.Lock()
seedRanges = append(seedRanges, nextTransform(0, []bound{newBound(seeds[i], seeds[i]+seeds[i+1]-1)})...)
mu.Unlock()
}(i)
}
wg.Wait()
lowest := math.MaxInt
for _, r := range seedRanges {
if r.lower < lowest {
lowest = r.lower
}
}
return lowest
}