Compare commits
No commits in common. "7d8df0db21dbbda1a38ad9d69ae5624875a66aa4" and "39d96c04eca09c48cbe451a12a1ce8d4d9f486b0" have entirely different histories.
7d8df0db21
...
39d96c04ec
3 changed files with 30 additions and 219 deletions
|
|
@ -13,108 +13,49 @@ 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 {
|
||||||
total := (r.end - r.start) + 1
|
return (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 dbFromSlice(ranges []int) (db freshDB, err error) {
|
func getRanges(scanner *bufio.Scanner) (ranges []freshRange, err error) {
|
||||||
if len(ranges)%2 != 0 {
|
ranges = make([]freshRange, 0, 5)
|
||||||
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 db, nil
|
return ranges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
startEnd := strings.Split(text, "-")
|
startEnd := strings.Split(text, "-")
|
||||||
|
|
||||||
if len(startEnd) != 2 {
|
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])
|
start, err := strconv.Atoi(startEnd[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return db, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
end, err := strconv.Atoi(startEnd[1])
|
end, err := strconv.Atoi(startEnd[1])
|
||||||
if err != nil {
|
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")
|
return nil, 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() {
|
||||||
|
|
@ -124,30 +65,37 @@ func main() {
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(file)
|
scanner := bufio.NewScanner(file)
|
||||||
db, err := parse(scanner)
|
ranges, err := getRanges(scanner)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
nRaw := len(db.ranges)
|
authRanges := make([]freshRange, 1, len(ranges))
|
||||||
|
authRanges[0] = ranges[0]
|
||||||
|
|
||||||
for {
|
RANGE:
|
||||||
before, after := db.collapse()
|
for _, r := range ranges {
|
||||||
|
|
||||||
fmt.Printf("Collapsed %d to %d ranges\n", before, after)
|
for _, authR := range authRanges {
|
||||||
|
if authR.contains(r.start) {
|
||||||
if before == after {
|
if r.end > authR.end {
|
||||||
break
|
authR.end = r.end
|
||||||
}
|
}
|
||||||
|
continue RANGE
|
||||||
|
}
|
||||||
|
|
||||||
|
if authR.contains(r.end) {
|
||||||
|
if r.start < authR.start {
|
||||||
|
authR.start = r.start
|
||||||
|
}
|
||||||
|
continue RANGE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authRanges = append(authRanges, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
potentialNFresh := 0
|
potentialNFresh := 0
|
||||||
for _, r := range db.ranges {
|
for _, r := range authRanges {
|
||||||
potentialNFresh += r.nInRange()
|
potentialNFresh += r.nInRange()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(
|
fmt.Printf("N raw %d and consolidated %d. %d potential fresh ingredients.\n", len(ranges), len(authRanges), potentialNFresh)
|
||||||
"N raw %d and consolidated %d. %d potential fresh ingredients.\n",
|
|
||||||
nRaw,
|
|
||||||
len(db.ranges),
|
|
||||||
potentialNFresh,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue