package main import ( "bufio" "cmp" "fmt" "io" "log" "os" "slices" "strconv" "strings" ) func main() { f := os.Stdin if len(os.Args) > 1 && os.Args[1] != "-" { var err error f, err = os.Open(os.Args[1]) if err != nil { log.Fatal(err) } defer f.Close() } fresh, available, err := readIngredients(f) if err != nil { log.Fatal(err) } var availableFresh int for _, id := range available { for _, r := range fresh { if r.Includes(id) { availableFresh++ break } } } var freshIds int compactFresh := compactedRanges(fresh) for _, r := range compactFresh { freshIds += r.to - r.from + 1 } fmt.Println("available fresh:", availableFresh) fmt.Println("total fresh:", freshIds) } type idsRange struct { from, to int } func (r idsRange) Includes(n int) bool { return r.from <= n && n <= r.to } func readIngredients(r io.Reader) (fresh []idsRange, available []int, err error) { seenEmptyLine := false sc := bufio.NewScanner(r) for sc.Scan() { if sc.Text() == "" { seenEmptyLine = true continue } if seenEmptyLine { id, err := strconv.ParseUint(sc.Text(), 10, 0) if err != nil { return nil, nil, err } available = append(available, int(id)) } else { r, err := parseRange(sc.Text()) if err != nil { return nil, nil, err } fresh = append(fresh, r) } } return fresh, available, nil } func parseRange(s string) (idsRange, error) { before, after, ok := strings.Cut(s, "-") if !ok { return idsRange{}, fmt.Errorf("range %q: missing hyphen", s) } from, err := strconv.ParseUint(before, 10, 0) if err != nil { return idsRange{}, fmt.Errorf("range from: %w", err) } to, err := strconv.ParseUint(after, 10, 0) if err != nil { return idsRange{}, fmt.Errorf("range to: %w", err) } return idsRange{ from: int(from), to: int(to), }, nil } func compactedRanges(ranges []idsRange) []idsRange { ranges = slices.Clone(ranges) slices.SortFunc(ranges, func(a, b idsRange) int { if x := cmp.Compare(a.from, b.from); x != 0 { return x } return cmp.Compare(a.to, b.to) }) i := 0 for j := 1; j < len(ranges); j++ { if !ranges[i].Includes(ranges[j].from) { i++ ranges[i] = ranges[j] continue } ranges[i].to = max(ranges[i].to, ranges[j].to) } return ranges[:i+1] }