Solve day 5

This commit is contained in:
2025-12-06 16:50:12 +02:00
parent b73303c965
commit 2d5190c044
3 changed files with 202 additions and 0 deletions

11
day5/example.txt Normal file
View 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
View 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
View 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))
})
}
}