Go
I started by not sorting the ranges in the input stream and try to merge everything together. It didn't work, but the same algorithm with sorted input does. I guess I'm missing something important, but I tested my code and can't find the corner case that make it fail. Bah...
day05.go
package main
import (
"aoc/utils"
"cmp"
"fmt"
"slices"
"strconv"
"strings"
)
type idrange struct {
start, end int
}
func (rng idrange) contains(entry int) bool {
return rng.start <= entry && entry <= rng.end
}
func (rng idrange) length() int {
return (rng.end - rng.start) + 1
}
type rangeSet []idrange
func (r *rangeSet) addRange(rng idrange) {
containsStartIdx := slices.IndexFunc(*r, func(elem idrange) bool {
return elem.contains(rng.start)
})
containsEndIdx := slices.IndexFunc(*r, func(elem idrange) bool {
return elem.contains(rng.end)
})
// The range overlaps to other ranges.
if containsStartIdx != -1 && containsEndIdx != -1 {
// If it is in fact contained inside one range, it is ignored.
if containsStartIdx == containsEndIdx {
return
}
before := (*r)[containsStartIdx]
after := (*r)[containsEndIdx]
before.end = after.end
(*r)[containsStartIdx] = before
*r = slices.Delete(*r, containsStartIdx+1, containsEndIdx+1)
} else if containsEndIdx != -1 {
// If the range's end overlaps with another range, that range is
// extended on the front to start like the range in argument.
after := (*r)[containsEndIdx]
after.start = rng.start
(*r)[containsEndIdx] = after
smallestAfterIdx := slices.IndexFunc(*r, func(elem idrange) bool {
return rng.start < elem.start
})
if smallestAfterIdx != -1 && smallestAfterIdx != containsEndIdx+1 {
*r = slices.Delete(*r, smallestAfterIdx, containsEndIdx)
}
} else if containsStartIdx != -1 {
// If the range's start overlaps with another range, that range is
// extended on the back to start like the range in argument.
before := (*r)[containsStartIdx]
before.end = rng.end
(*r)[containsStartIdx] = before
smallestAfterIdx := slices.IndexFunc(*r, func(elem idrange) bool {
return rng.end < elem.end
})
if smallestAfterIdx != -1 && smallestAfterIdx != containsStartIdx+1 {
*r = slices.Delete(*r, containsStartIdx+1, smallestAfterIdx)
}
} else {
// If the range is standalone, it is added at the right position.
afterIdx := slices.IndexFunc(*r, func(elem idrange) bool {
return rng.start < elem.start
})
if afterIdx == -1 {
*r = append(*r, rng)
} else {
*r = slices.Insert(*r, afterIdx, rng)
}
}
}
func (r rangeSet) contains(entry int) bool {
for _, rng := range r {
if rng.contains(entry) {
return true
}
}
return false
}
func (r rangeSet) length() int {
sum := 0
for _, rng := range r {
sum += rng.length()
}
return sum
}
func parseRange(line string) (idrange, error) {
bounds := strings.Split(line, "-")
start, err1 := strconv.Atoi(bounds[0])
end, err2 := strconv.Atoi(bounds[1])
if err1 != nil {
return idrange{}, err1
}
if err2 != nil {
return idrange{}, err2
}
return idrange{
start: start,
end: end,
}, nil
}
func parseRangeSet(input chan string) (rangeSet, error) {
rangeSet := rangeSet{}
ranges := []idrange{}
for line := range input {
if line == "" {
break
}
rng, err := parseRange(line)
if err != nil {
return nil, err
}
ranges = append(ranges, rng)
}
slices.SortFunc(ranges, func(a, b idrange) int {
return cmp.Compare(a.start, b.start)
})
for _, rng := range ranges {
rangeSet.addRange(rng)
}
return rangeSet, nil
}
func getNumberChannel(input chan string) chan int {
ch := make(chan int, cap(input))
go func() {
for line := range input {
num, _ := strconv.Atoi(line)
ch <- num
}
close(ch)
}()
return ch
}
func stepOne(input chan string) (int, error) {
rngSet, errParse := parseRangeSet(input)
if errParse != nil {
return 0, errParse
}
numCh := getNumberChannel(input)
count := 0
for entry := range numCh {
if rngSet.contains(entry) {
count++
}
}
return count, nil
}
func stepTwo(input chan string) (int, error) {
rngSet, err := parseRangeSet(input)
if err != nil {
return 0, err
}
return rngSet.length(), nil
}
func main() {
inputFile := utils.FilePath("day05.txt")
utils.RunStep(utils.ONE, inputFile, stepOne)
utils.RunStep(utils.TWO, inputFile, stepTwo)
}