2025-12-06 21:26:00 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type freshRange struct {
|
|
|
|
|
start, end int
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
type freshDB struct {
|
|
|
|
|
ranges []freshRange
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 21:26:00 +00:00
|
|
|
func (r *freshRange) contains(c int) bool {
|
|
|
|
|
return c >= r.start && c <= r.end
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *freshRange) nInRange() int {
|
2025-12-07 19:51:21 +00:00
|
|
|
total := (r.end - r.start) + 1
|
|
|
|
|
return total
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
/* Check for an error, panic if there is */
|
2025-12-06 21:26:00 +00:00
|
|
|
func check(err error) {
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
func dbFromSlice(ranges []int) (db freshDB, err error) {
|
|
|
|
|
if len(ranges)%2 != 0 {
|
|
|
|
|
return freshDB{}, errors.New("Input slice not of even length")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.ranges = make([]freshRange, 0, len(ranges)/2)
|
|
|
|
|
|
|
|
|
|
for i := 0; i < len(ranges); i += 2 {
|
|
|
|
|
db.ranges = append(db.ranges, freshRange{ranges[i], ranges[i+1]})
|
|
|
|
|
}
|
|
|
|
|
return db, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse ranges out of a bufio.Scanner */
|
|
|
|
|
func parse(scanner *bufio.Scanner) (db freshDB, err error) {
|
|
|
|
|
db.ranges = make([]freshRange, 0, 5)
|
2025-12-06 21:26:00 +00:00
|
|
|
|
|
|
|
|
for scanner.Scan() {
|
|
|
|
|
text := scanner.Text()
|
|
|
|
|
|
|
|
|
|
if text == "" {
|
2025-12-07 19:51:21 +00:00
|
|
|
return db, nil
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startEnd := strings.Split(text, "-")
|
|
|
|
|
|
|
|
|
|
if len(startEnd) != 2 {
|
2025-12-07 19:51:21 +00:00
|
|
|
return db, errors.New("Fresh range does not contain exactly two numbers")
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start, err := strconv.Atoi(startEnd[0])
|
|
|
|
|
if err != nil {
|
2025-12-07 19:51:21 +00:00
|
|
|
return db, err
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end, err := strconv.Atoi(startEnd[1])
|
|
|
|
|
if err != nil {
|
2025-12-07 19:51:21 +00:00
|
|
|
return db, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.ranges = append(db.ranges, freshRange{start, end})
|
|
|
|
|
}
|
|
|
|
|
return db, errors.New("No empty line in file to delimit fresh ranges")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (db *freshDB) insert(toinsert freshRange) {
|
|
|
|
|
for i := range db.ranges {
|
|
|
|
|
r := &db.ranges[i]
|
|
|
|
|
if r.contains(toinsert.start) {
|
|
|
|
|
if toinsert.end > r.end {
|
|
|
|
|
r.end = toinsert.end
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r.contains(toinsert.end) {
|
|
|
|
|
if toinsert.start < r.start {
|
|
|
|
|
r.start = toinsert.start
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if toinsert.contains(r.start) && toinsert.contains(r.end) {
|
|
|
|
|
r.start = toinsert.start
|
|
|
|
|
r.end = toinsert.end
|
|
|
|
|
return
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
2025-12-07 19:51:21 +00:00
|
|
|
}
|
|
|
|
|
db.ranges = append(db.ranges, toinsert)
|
|
|
|
|
}
|
2025-12-06 21:26:00 +00:00
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
/* Collapse a list of fresh ingredient ranges to avoid overlaps */
|
|
|
|
|
func (db *freshDB) collapse() (before int, after int) {
|
|
|
|
|
before = len(db.ranges)
|
|
|
|
|
collapsed := freshDB{make([]freshRange, 0, len(db.ranges))}
|
|
|
|
|
|
|
|
|
|
for _, r := range db.ranges {
|
|
|
|
|
collapsed.insert(r)
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
2025-12-07 19:51:21 +00:00
|
|
|
db.ranges = collapsed.ranges
|
|
|
|
|
after = len(db.ranges)
|
|
|
|
|
return before, after
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
|
|
|
|
|
file, err := os.Open("five.txt")
|
|
|
|
|
check(err)
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
scanner := bufio.NewScanner(file)
|
2025-12-07 19:51:21 +00:00
|
|
|
db, err := parse(scanner)
|
2025-12-06 21:26:00 +00:00
|
|
|
check(err)
|
|
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
nRaw := len(db.ranges)
|
2025-12-06 21:26:00 +00:00
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
for {
|
|
|
|
|
before, after := db.collapse()
|
2025-12-06 21:26:00 +00:00
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
fmt.Printf("Collapsed %d to %d ranges\n", before, after)
|
2025-12-06 21:26:00 +00:00
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
if before == after {
|
|
|
|
|
break
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
potentialNFresh := 0
|
2025-12-07 19:51:21 +00:00
|
|
|
for _, r := range db.ranges {
|
2025-12-06 21:26:00 +00:00
|
|
|
potentialNFresh += r.nInRange()
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-07 19:51:21 +00:00
|
|
|
fmt.Printf(
|
|
|
|
|
"N raw %d and consolidated %d. %d potential fresh ingredients.\n",
|
|
|
|
|
nRaw,
|
|
|
|
|
len(db.ranges),
|
|
|
|
|
potentialNFresh,
|
|
|
|
|
)
|
2025-12-06 21:26:00 +00:00
|
|
|
}
|