Compare commits
2 commits
39d96c04ec
...
7d8df0db21
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d8df0db21 | |||
| 14a16819c5 |
3 changed files with 219 additions and 30 deletions
|
|
@ -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
67
2025/five/five_test.go
Normal 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
70
2025/seven/seven.go
Normal 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,
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue