Compare commits

...

2 commits

Author SHA1 Message Date
7d8df0db21 Half assed start at seven 2025-12-07 20:27:32 +00:00
14a16819c5 solve five 2025-12-07 19:51:21 +00:00
3 changed files with 219 additions and 30 deletions

View file

@ -13,49 +13,108 @@ type freshRange struct {
start, end int start, end int
} }
type freshDB struct {
ranges []freshRange
}
func (r *freshRange) contains(c int) bool { func (r *freshRange) contains(c int) bool {
return c >= r.start && c <= r.end return c >= r.start && c <= r.end
} }
func (r *freshRange) nInRange() int { func (r *freshRange) nInRange() int {
return (r.end - r.start) + 1 total := (r.end - r.start) + 1
return total
} }
/* Check for an error, panic if there is */
func check(err error) { func check(err error) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
func getRanges(scanner *bufio.Scanner) (ranges []freshRange, err error) { func dbFromSlice(ranges []int) (db freshDB, err error) {
ranges = make([]freshRange, 0, 5) 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)
for scanner.Scan() { for scanner.Scan() {
text := scanner.Text() text := scanner.Text()
if text == "" { if text == "" {
return ranges, nil return db, nil
} }
startEnd := strings.Split(text, "-") startEnd := strings.Split(text, "-")
if len(startEnd) != 2 { if len(startEnd) != 2 {
return nil, errors.New("Fresh range does not contain exactly two numbers") return db, errors.New("Fresh range does not contain exactly two numbers")
} }
start, err := strconv.Atoi(startEnd[0]) start, err := strconv.Atoi(startEnd[0])
if err != nil { if err != nil {
return nil, err return db, err
} }
end, err := strconv.Atoi(startEnd[1]) end, err := strconv.Atoi(startEnd[1])
if err != nil { if err != nil {
return nil, err return db, err
} }
ranges = append(ranges, freshRange{start, end}) db.ranges = append(db.ranges, freshRange{start, end})
} }
return nil, errors.New("No empty line in file to delimit fresh ranges") 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
} }
func main() { func main() {
@ -65,37 +124,30 @@ func main() {
defer file.Close() defer file.Close()
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
ranges, err := getRanges(scanner) db, err := parse(scanner)
check(err) check(err)
authRanges := make([]freshRange, 1, len(ranges)) nRaw := len(db.ranges)
authRanges[0] = ranges[0]
RANGE: for {
for _, r := range ranges { before, after := db.collapse()
for _, authR := range authRanges { fmt.Printf("Collapsed %d to %d ranges\n", before, after)
if authR.contains(r.start) {
if r.end > authR.end {
authR.end = r.end
}
continue RANGE
}
if authR.contains(r.end) { if before == after {
if r.start < authR.start { break
authR.start = r.start
}
continue RANGE
}
} }
authRanges = append(authRanges, r)
} }
potentialNFresh := 0 potentialNFresh := 0
for _, r := range authRanges { for _, r := range db.ranges {
potentialNFresh += r.nInRange() potentialNFresh += r.nInRange()
} }
fmt.Printf("N raw %d and consolidated %d. %d potential fresh ingredients.\n", len(ranges), len(authRanges), potentialNFresh) fmt.Printf(
"N raw %d and consolidated %d. %d potential fresh ingredients.\n",
nRaw,
len(db.ranges),
potentialNFresh,
)
} }

67
2025/five/five_test.go Normal file
View file

@ -0,0 +1,67 @@
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)
}
}
}
}

70
2025/seven/seven.go Normal file
View file

@ -0,0 +1,70 @@
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,
)
}