solve day 5 part 2

This commit is contained in:
Gabriel Augendre 2023-12-08 18:14:11 +01:00
parent 908c7a9d29
commit fa66368b91
3 changed files with 173 additions and 9 deletions

View file

@ -46,12 +46,63 @@ func Day05Part1(input io.Reader) (int, error) {
func Day05Part2(input io.Reader) (int, error) { func Day05Part2(input io.Reader) (int, error) {
scanner := bufio.NewScanner(input) scanner := bufio.NewScanner(input)
scanner.Scan()
seedRanges := parseSeedRanges(lineToInts(strings.TrimPrefix(scanner.Text(), "seeds: ")))
scanner.Scan()
inMap := false
var currentMap day05Map
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
_ = line if line == "" {
var newRanges []day05SeedRange
for _, sRange := range seedRanges {
newRanges = append(newRanges, currentMap.convertRange(sRange)...)
}
seedRanges = newRanges
inMap = false
currentMap = nil
} else if strings.HasSuffix(line, "map:") {
inMap = true
} else if inMap {
currentMap = append(currentMap, newDay05Range(line))
}
} }
return 0, nil if inMap {
// Convert one last time if necessary
var newRanges []day05SeedRange
for _, sRange := range seedRanges {
newRanges = append(newRanges, currentMap.convertRange(sRange)...)
}
seedRanges = newRanges
inMap = false
currentMap = nil
}
mini := int(^uint(0) >> 1) // highest int
for _, r := range seedRanges {
if r.start < mini {
mini = r.start
}
}
return mini, nil
}
func parseSeedRanges(ints []int) []day05SeedRange {
ranges := make([]day05SeedRange, len(ints)/2)
for i := 0; i < len(ints)-1; i += 2 {
ranges[i/2] = day05SeedRange{start: ints[i], end: ints[i] + ints[i+1]}
}
return ranges
}
// range is [start; end)
// start is included, end is not.
type day05SeedRange struct {
start, end int
} }
func lineToInts(line string) []int { func lineToInts(line string) []int {
@ -68,25 +119,61 @@ func lineToInts(line string) []int {
} }
type day05Range struct { type day05Range struct {
destination, source, length int destStart, sourceStart, length int
} }
func newDay05Range(line string) day05Range { func newDay05Range(line string) day05Range {
ints := lineToInts(line) ints := lineToInts(line)
return day05Range{ return day05Range{
destination: ints[0], destStart: ints[0],
source: ints[1], sourceStart: ints[1],
length: ints[2], length: ints[2],
} }
} }
func (r day05Range) sourceEnd() int {
return r.sourceStart + r.length
}
func (r day05Range) destEnd() int {
return r.destStart + r.length
}
func (r day05Range) convert(n int) (int, bool) { func (r day05Range) convert(n int) (int, bool) {
if n >= r.source && n < r.source+r.length { if n >= r.sourceStart && n < r.sourceEnd() {
return n - r.source + r.destination, true return r.mustConvert(n), true
} }
return n, false return n, false
} }
func (r day05Range) mustConvert(n int) int {
return n - r.sourceStart + r.destStart
}
func (r day05Range) convertRange(s day05SeedRange) (converted []day05SeedRange, notConverted []day05SeedRange) {
if r.sourceStart <= s.start && s.end <= r.sourceEnd() {
// s-----s
// r--------r
return []day05SeedRange{{start: r.mustConvert(s.start), end: r.mustConvert(s.end)}}, nil
} else if s.start < r.sourceStart && r.sourceStart <= s.end && s.end <= r.sourceEnd() {
// s-------s
// r--------r
return []day05SeedRange{{start: r.destStart, end: r.mustConvert(s.end)}}, []day05SeedRange{{start: s.start, end: r.sourceStart}}
} else if r.sourceStart <= s.start && s.start <= r.sourceEnd() && r.sourceEnd() < s.end {
// s-------s
// r--------r
return []day05SeedRange{{start: r.mustConvert(s.start), end: r.destEnd()}}, []day05SeedRange{{start: r.sourceEnd(), end: s.end}}
} else if s.start <= r.sourceStart && r.sourceEnd() < s.end {
// s------------s
// r--------r
return []day05SeedRange{{start: r.destStart, end: r.destEnd()}}, []day05SeedRange{{start: s.start, end: r.sourceStart}, {start: r.sourceEnd(), end: s.end}}
} else {
// s---s
// r-----r
return nil, []day05SeedRange{s}
}
}
type day05Map []day05Range type day05Map []day05Range
func (m day05Map) convert(n int) int { func (m day05Map) convert(n int) int {
@ -97,3 +184,19 @@ func (m day05Map) convert(n int) int {
} }
return n return n
} }
func (m day05Map) convertRange(s day05SeedRange) []day05SeedRange {
var converted []day05SeedRange
toConvert := []day05SeedRange{s}
for _, dRange := range m {
var toConvertNext []day05SeedRange
for _, c := range toConvert {
var conv []day05SeedRange
conv, toConvertNext = dRange.convertRange(c)
converted = append(converted, conv...)
}
toConvert = toConvertNext
}
converted = append(converted, toConvert...)
return converted
}

View file

@ -26,10 +26,38 @@ func TestDay05Part1(t *testing.T) {
func TestDay05Part2(t *testing.T) { func TestDay05Part2(t *testing.T) {
tests := []testCase{ tests := []testCase{
{"inputs/day05_test2", 0}, {"inputs/day05_test2", 46},
{"inputs/day05", 0}, {"inputs/day05", 78775051},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.filename, check(test, Day05Part2)) t.Run(test.filename, check(test, Day05Part2))
} }
} }
func TestDay05Ranges(t *testing.T) {
tests := []struct {
name string
dRange day05Range
seedRange day05SeedRange
expected []day05SeedRange
}{
{
"seed included in range",
day05Range{0, 5, 5},
day05SeedRange{6, 8},
[]day05SeedRange{{1, 3}},
},
{
"range included in seed",
day05Range{0, 10, 2},
day05SeedRange{9, 13},
[]day05SeedRange{{0, 2}, {9, 10}, {12, 13}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := day05Map{test.dRange}.convertRange(test.seedRange)
assert.Equal(t, test.expected, got)
})
}
}

View file

@ -0,0 +1,33 @@
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4