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