Solve day 5
This commit is contained in:
11
day5/example.txt
Normal file
11
day5/example.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
3-5
|
||||
10-14
|
||||
16-20
|
||||
12-18
|
||||
|
||||
1
|
||||
5
|
||||
8
|
||||
11
|
||||
17
|
||||
32
|
||||
123
day5/main.go
Normal file
123
day5/main.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmp"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := os.Stdin
|
||||
if len(os.Args) > 1 && os.Args[1] != "-" {
|
||||
var err error
|
||||
f, err = os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
fresh, available, err := readIngredients(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var availableFresh int
|
||||
for _, id := range available {
|
||||
for _, r := range fresh {
|
||||
if r.Includes(id) {
|
||||
availableFresh++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var freshIds int
|
||||
compactFresh := compactedRanges(fresh)
|
||||
for _, r := range compactFresh {
|
||||
freshIds += r.to - r.from + 1
|
||||
}
|
||||
|
||||
fmt.Println("available fresh:", availableFresh)
|
||||
fmt.Println("total fresh:", freshIds)
|
||||
}
|
||||
|
||||
type idsRange struct {
|
||||
from, to int
|
||||
}
|
||||
|
||||
func (r idsRange) Includes(n int) bool {
|
||||
return r.from <= n && n <= r.to
|
||||
}
|
||||
|
||||
func readIngredients(r io.Reader) (fresh []idsRange, available []int, err error) {
|
||||
seenEmptyLine := false
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
if sc.Text() == "" {
|
||||
seenEmptyLine = true
|
||||
continue
|
||||
}
|
||||
if seenEmptyLine {
|
||||
id, err := strconv.ParseUint(sc.Text(), 10, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
available = append(available, int(id))
|
||||
} else {
|
||||
r, err := parseRange(sc.Text())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fresh = append(fresh, r)
|
||||
}
|
||||
}
|
||||
return fresh, available, nil
|
||||
}
|
||||
|
||||
func parseRange(s string) (idsRange, error) {
|
||||
before, after, ok := strings.Cut(s, "-")
|
||||
if !ok {
|
||||
return idsRange{}, fmt.Errorf("range %q: missing hyphen", s)
|
||||
}
|
||||
from, err := strconv.ParseUint(before, 10, 0)
|
||||
if err != nil {
|
||||
return idsRange{}, fmt.Errorf("range from: %w", err)
|
||||
}
|
||||
to, err := strconv.ParseUint(after, 10, 0)
|
||||
if err != nil {
|
||||
return idsRange{}, fmt.Errorf("range to: %w", err)
|
||||
}
|
||||
return idsRange{
|
||||
from: int(from),
|
||||
to: int(to),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func compactedRanges(ranges []idsRange) []idsRange {
|
||||
ranges = slices.Clone(ranges)
|
||||
|
||||
slices.SortFunc(ranges, func(a, b idsRange) int {
|
||||
if x := cmp.Compare(a.from, b.from); x != 0 {
|
||||
return x
|
||||
}
|
||||
return cmp.Compare(a.to, b.to)
|
||||
})
|
||||
|
||||
i := 0
|
||||
for j := 1; j < len(ranges); j++ {
|
||||
if !ranges[i].Includes(ranges[j].from) {
|
||||
i++
|
||||
ranges[i] = ranges[j]
|
||||
continue
|
||||
}
|
||||
ranges[i].to = max(ranges[i].to, ranges[j].to)
|
||||
}
|
||||
return ranges[:i+1]
|
||||
}
|
||||
68
day5/main_test.go
Normal file
68
day5/main_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_compactedRanges(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // description of this test case
|
||||
ranges []idsRange
|
||||
want []idsRange
|
||||
}{
|
||||
{
|
||||
name: "single",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "identical",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
{0, 10},
|
||||
{0, 10},
|
||||
{20, 30},
|
||||
{20, 30},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 10},
|
||||
{20, 30},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
{2, 11},
|
||||
{20, 30},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 11},
|
||||
{20, 30},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "swallows",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
{2, 8},
|
||||
{20, 30},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 10},
|
||||
{20, 30},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, compactedRanges(tt.ranges))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user