diff --git a/2025/five/five.go b/2025/five/five.go index 69f3ec7..4fba271 100644 --- a/2025/five/five.go +++ b/2025/five/five.go @@ -13,108 +13,49 @@ type freshRange struct { start, end int } -type freshDB struct { - ranges []freshRange -} - func (r *freshRange) contains(c int) bool { return c >= r.start && c <= r.end } func (r *freshRange) nInRange() int { - total := (r.end - r.start) + 1 - return total + return (r.end - r.start) + 1 } -/* Check for an error, panic if there is */ func check(err error) { if err != nil { panic(err) } } -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) +func getRanges(scanner *bufio.Scanner) (ranges []freshRange, err error) { + ranges = make([]freshRange, 0, 5) for scanner.Scan() { text := scanner.Text() if text == "" { - return db, nil + return ranges, nil } startEnd := strings.Split(text, "-") if len(startEnd) != 2 { - return db, errors.New("Fresh range does not contain exactly two numbers") + return nil, errors.New("Fresh range does not contain exactly two numbers") } start, err := strconv.Atoi(startEnd[0]) if err != nil { - return db, err + return nil, err } end, err := strconv.Atoi(startEnd[1]) if err != nil { - return db, err + return nil, err } - db.ranges = append(db.ranges, freshRange{start, end}) + ranges = append(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 - } - } - db.ranges = append(db.ranges, toinsert) -} - -/* 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) - } - db.ranges = collapsed.ranges - after = len(db.ranges) - return before, after + return nil, errors.New("No empty line in file to delimit fresh ranges") } func main() { @@ -124,30 +65,37 @@ func main() { defer file.Close() scanner := bufio.NewScanner(file) - db, err := parse(scanner) + ranges, err := getRanges(scanner) check(err) - nRaw := len(db.ranges) + authRanges := make([]freshRange, 1, len(ranges)) + authRanges[0] = ranges[0] - for { - before, after := db.collapse() +RANGE: + for _, r := range ranges { - fmt.Printf("Collapsed %d to %d ranges\n", before, after) + for _, authR := range authRanges { + if authR.contains(r.start) { + if r.end > authR.end { + authR.end = r.end + } + continue RANGE + } - if before == after { - break + if authR.contains(r.end) { + if r.start < authR.start { + authR.start = r.start + } + continue RANGE + } } + authRanges = append(authRanges, r) } potentialNFresh := 0 - for _, r := range db.ranges { + for _, r := range authRanges { potentialNFresh += r.nInRange() } - fmt.Printf( - "N raw %d and consolidated %d. %d potential fresh ingredients.\n", - nRaw, - len(db.ranges), - potentialNFresh, - ) + fmt.Printf("N raw %d and consolidated %d. %d potential fresh ingredients.\n", len(ranges), len(authRanges), potentialNFresh) } diff --git a/2025/five/five_test.go b/2025/five/five_test.go deleted file mode 100644 index 4fbefac..0000000 --- a/2025/five/five_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import "testing" - -type insertTest struct { - ranges []int - toinsert freshRange - expected []int -} - -var insertTests = []insertTest{ - {[]int{1, 3}, freshRange{4, 10}, []int{1, 3, 4, 10}}, - {[]int{1, 5}, freshRange{4, 10}, []int{1, 10}}, -} - -func TestInsert(t *testing.T) { - for _, test := range insertTests { - inDB, _ := dbFromSlice(test.ranges) - expectedDB, _ := dbFromSlice(test.expected) - inDB.insert(test.toinsert) - - if len(inDB.ranges) != len(expectedDB.ranges) { - t.Errorf("%+v != %+v", expectedDB, inDB) - continue - } - - for i := range inDB.ranges { - if inDB.ranges[i] != expectedDB.ranges[i] { - t.Errorf("%v != %v", expectedDB, inDB) - } - } - } -} - -type collapseTest struct { - ranges []int - expected []int -} - -var collapseTests = []collapseTest{ - {[]int{1, 3, 4, 10}, []int{1, 3, 4, 10}}, - {[]int{1, 3, 4, 10, 2, 5}, []int{1, 5, 4, 10}}, - {[]int{1, 5, 4, 10}, []int{1, 10}}, - {[]int{1, 5, 5, 10}, []int{1, 10}}, - {[]int{2, 5, 1, 10}, []int{1, 10}}, - {[]int{1, 5, 2, 3}, []int{1, 5}}, -} - -func TestCollapse(t *testing.T) { - for _, test := range collapseTests { - inDB, _ := dbFromSlice(test.ranges) - expectedDB, _ := dbFromSlice(test.expected) - - inDB.collapse() - - if len(inDB.ranges) != len(expectedDB.ranges) { - t.Errorf("%v != %v", expectedDB.ranges, inDB.ranges) - continue - } - - for i := range inDB.ranges { - if inDB.ranges[i] != expectedDB.ranges[i] { - t.Errorf("%v != %v", expectedDB.ranges, inDB.ranges) - } - } - } -} diff --git a/2025/seven/seven.go b/2025/seven/seven.go deleted file mode 100644 index c849bc9..0000000 --- a/2025/seven/seven.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "bufio" - "errors" - "fmt" - "os" - "strconv" - "strings" -) - -func check(err error) { - if err != nil { - panic(err) - } -} - -type beam int -type beams struct { - b map[beam]struct{} -} - -func (b *beams) add(pos beam) { - b.b[pos] = {} -} - -func main() { - - file, err := os.Open("five.txt") - check(err) - defer file.Close() - - scanner := bufio.NewScanner(file) - scanner.Scan() - - text := scanner.Text() - - start := strings.IndexRune(text, 'S') - beams.add(beam(start)) - - for scanner.Scan() { - } - db, err := parse(scanner) - - check(err) - - nRaw := len(db.ranges) - - for { - before, after := db.collapse() - - fmt.Printf("Collapsed %d to %d ranges\n", before, after) - - if before == after { - break - } - } - - potentialNFresh := 0 - for _, r := range db.ranges { - potentialNFresh += r.nInRange() - } - - fmt.Printf( - "N raw %d and consolidated %d. %d potential fresh ingredients.\n", - nRaw, - len(db.ranges), - potentialNFresh, - ) -}