148 lines
3.6 KiB
Go
148 lines
3.6 KiB
Go
package year25
|
|
|
|
import (
|
|
"bufio"
|
|
"cmp"
|
|
"fmt"
|
|
"iter"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.bizdoc.ro/gabi-public/Advent-of-Code.git/aocutils"
|
|
)
|
|
|
|
type Day5Interval struct {
|
|
Start, End int64
|
|
isRemoved bool
|
|
}
|
|
|
|
type MergedIntervals struct {
|
|
intervals []*Day5Interval
|
|
}
|
|
|
|
func (m *MergedIntervals) Put1(newInterval Day5Interval) {
|
|
for item := range m.Items() {
|
|
if newInterval.Start <= item.End && newInterval.End >= item.Start {
|
|
newInterval.Start = min(newInterval.Start, item.Start)
|
|
newInterval.End = max(newInterval.End, item.End)
|
|
|
|
item.isRemoved = true
|
|
m.Put(newInterval)
|
|
return
|
|
}
|
|
}
|
|
|
|
// just in case there are too many intervals
|
|
m.intervals = slices.DeleteFunc(m.intervals, func(i *Day5Interval) bool {
|
|
return i.isRemoved
|
|
})
|
|
|
|
m.intervals = append(m.intervals, &newInterval)
|
|
}
|
|
func (m *MergedIntervals) Put(newInterval Day5Interval) {
|
|
// fast search start, end
|
|
for item := range m.Items() {
|
|
if newInterval.Start <= item.End && newInterval.End >= item.Start {
|
|
newInterval.Start = min(newInterval.Start, item.Start)
|
|
newInterval.End = max(newInterval.End, item.End)
|
|
|
|
item.isRemoved = true
|
|
m.Put(newInterval)
|
|
return
|
|
}
|
|
}
|
|
|
|
m.intervals = slices.DeleteFunc(m.intervals, func(i *Day5Interval) bool {
|
|
return i.isRemoved
|
|
})
|
|
|
|
i, _ := slices.BinarySearchFunc(m.intervals, &newInterval, func(interval *Day5Interval, d *Day5Interval) int {
|
|
return cmp.Compare(interval.Start, newInterval.Start)
|
|
})
|
|
m.intervals = slices.Insert(m.intervals, i, &newInterval)
|
|
}
|
|
|
|
func (m *MergedIntervals) CheckItem(itemId int64) (*Day5Interval, bool) {
|
|
for interval := range m.Items() {
|
|
if interval.Start <= itemId && itemId <= interval.End {
|
|
return interval, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (m *MergedIntervals) Items() iter.Seq[*Day5Interval] {
|
|
return func(yield func(*Day5Interval) bool) {
|
|
for _, interval := range m.intervals {
|
|
if !interval.isRemoved {
|
|
if !yield(interval) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func Day5ParseIntervals(s *bufio.Scanner) (intervals *MergedIntervals, err error) {
|
|
intervals = new(MergedIntervals)
|
|
for s.Scan() {
|
|
line := strings.TrimSpace(s.Text())
|
|
if line == "" {
|
|
return
|
|
}
|
|
|
|
var newInterval Day5Interval
|
|
dashIndex := strings.Index(line, "-")
|
|
newInterval.Start, err = strconv.ParseInt(line[:dashIndex], 10, 64)
|
|
if err != nil {
|
|
return intervals, fmt.Errorf("day5: failed to parse line %s. invalid start index: %w", line, err)
|
|
}
|
|
newInterval.End, err = strconv.ParseInt(line[dashIndex+1:], 10, 64)
|
|
if err != nil {
|
|
return intervals, fmt.Errorf("day5: failed to parse line %s. invalid end index: %w", line, err)
|
|
}
|
|
|
|
intervals.Put(newInterval)
|
|
}
|
|
|
|
return intervals, s.Err()
|
|
}
|
|
|
|
func Day5Part1(ctx aoc.Context) (int, error) {
|
|
scanner := ctx.Scanner()
|
|
intervals, err := Day5ParseIntervals(scanner)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("day5: failed to parse intervals %w", err)
|
|
}
|
|
|
|
var freshIngredients int
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
itemId, err := strconv.ParseInt(line, 10, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("day5: failed to parse itemId in line %s. %w", line, err)
|
|
}
|
|
if interval, ok := intervals.CheckItem(itemId); ok {
|
|
freshIngredients += 1
|
|
ctx.Println(itemId, "is fresh because it was found in", interval)
|
|
} else {
|
|
ctx.Println(itemId, "is spoiled")
|
|
}
|
|
}
|
|
return freshIngredients, scanner.Err()
|
|
}
|
|
|
|
func Day5Part2(ctx aoc.Context) (solution int64, _ error) {
|
|
intervals, err := Day5ParseIntervals(ctx.Scanner())
|
|
if err != nil {
|
|
return 0, fmt.Errorf("day5: failed to parse intervals %w", err)
|
|
}
|
|
|
|
for interval := range intervals.Items() {
|
|
solution += interval.End - interval.Start + 1
|
|
}
|
|
|
|
return solution, nil
|
|
}
|