124 lines
2.3 KiB
Go
124 lines
2.3 KiB
Go
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]
|
|
}
|