Day 5: Cafeteria
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465


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) }