solve five
This commit is contained in:
parent
39d96c04ec
commit
14a16819c5
2 changed files with 149 additions and 30 deletions
|
|
@ -13,49 +13,108 @@ 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 {
|
||||
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) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getRanges(scanner *bufio.Scanner) (ranges []freshRange, err error) {
|
||||
ranges = make([]freshRange, 0, 5)
|
||||
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)
|
||||
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
|
||||
if text == "" {
|
||||
return ranges, nil
|
||||
return db, nil
|
||||
}
|
||||
|
||||
startEnd := strings.Split(text, "-")
|
||||
|
||||
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])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return db, err
|
||||
}
|
||||
|
||||
end, err := strconv.Atoi(startEnd[1])
|
||||
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() {
|
||||
|
|
@ -65,37 +124,30 @@ func main() {
|
|||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
ranges, err := getRanges(scanner)
|
||||
db, err := parse(scanner)
|
||||
check(err)
|
||||
|
||||
authRanges := make([]freshRange, 1, len(ranges))
|
||||
authRanges[0] = ranges[0]
|
||||
nRaw := len(db.ranges)
|
||||
|
||||
RANGE:
|
||||
for _, r := range ranges {
|
||||
for {
|
||||
before, after := db.collapse()
|
||||
|
||||
for _, authR := range authRanges {
|
||||
if authR.contains(r.start) {
|
||||
if r.end > authR.end {
|
||||
authR.end = r.end
|
||||
}
|
||||
continue RANGE
|
||||
}
|
||||
fmt.Printf("Collapsed %d to %d ranges\n", before, after)
|
||||
|
||||
if authR.contains(r.end) {
|
||||
if r.start < authR.start {
|
||||
authR.start = r.start
|
||||
}
|
||||
continue RANGE
|
||||
}
|
||||
if before == after {
|
||||
break
|
||||
}
|
||||
authRanges = append(authRanges, r)
|
||||
}
|
||||
|
||||
potentialNFresh := 0
|
||||
for _, r := range authRanges {
|
||||
for _, r := range db.ranges {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue