Files
aoc2025odin/day5/day5.odin
2025-12-05 22:51:17 -05:00

156 lines
3.7 KiB
Odin

package main
import "core:fmt"
import "core:log"
import "core:os"
import "core:strings"
import "core:strconv"
import "core:testing"
sample :: `3-5
10-14
16-20
12-18
1
5
8
11
17
32`
Range :: struct {
start: u64,
end: u64,
}
parse_range :: proc(s: string) -> Range {
range: Range
delim_index := strings.index_rune(s, '-')
range.start, _ = strconv.parse_u64(s[:delim_index])
range.end, _ = strconv.parse_u64(s[delim_index + 1:])
return range
}
solve_first :: proc(input: string) -> u64 {
input := input
fresh_ingredient_ids: [dynamic]Range
defer delete(fresh_ingredient_ids)
available_ingredient_ids: [dynamic]u64
defer delete(available_ingredient_ids)
in_ranges := true
for line in strings.split_lines_iterator(&input) {
if line == "" {
in_ranges = false
}
if in_ranges {
range := parse_range(line)
append(&fresh_ingredient_ids, range)
} else {
val, _ := strconv.parse_u64(line)
append(&available_ingredient_ids, val)
}
}
total_fresh: u64
for id in available_ingredient_ids {
for range in fresh_ingredient_ids {
if range.start <= id && id <= range.end {
total_fresh += 1
break
}
}
}
return total_fresh
}
@(test)
solves_sample :: proc(^testing.T) {
total_fresh := solve_first(sample)
log.info("sample total fresh: %v", total_fresh)
assert(total_fresh == 3)
}
@(test)
solves_input :: proc(^testing.T) {
content, _ := os.read_entire_file("day5input.txt")
defer delete(content)
total_fresh := solve_first(string(content))
log.info("input total fresh: %v", total_fresh)
assert(total_fresh == 701)
}
RangeResult :: struct {
range: Range,
primary: bool,
used: bool
}
solve_second :: proc(input: string) -> u64 {
input := input
fresh_set: [dynamic]RangeResult
defer delete(fresh_set)
for line in strings.split_lines_iterator(&input) {
if line == "" {
break
}
range := parse_range(line)
append(&fresh_set, RangeResult{ range=range })
}
for &rr, index in fresh_set {
r1 := rr
if rr.used do continue
rr.primary = true
if index == len(fresh_set) - 1 {
continue
}
increased := true
for increased {
increased = false
for &compare in fresh_set[index + 1:] {
if compare.used do continue
r := rr.range
r2 := compare
crr := compare.range
if (crr.start <= r.start && r.start <= crr.end) ||
(crr.start <= r.end && r.end <= crr.end) ||
(crr.start <= r.start && r.end <= crr.end) ||
(r.start <= crr.start && crr.end <= r.end) {
rr.range.start = min(r.start, crr.start)
rr.range.end = max(r.end, crr.end)
compare.used = true
increased = true
}
}
}
}
total: u64
for rr in fresh_set {
if !rr.primary do continue
total += (rr.range.end - rr.range.start) + 1
}
return total
}
@(test)
solves_second_sample :: proc(t: ^testing.T) {
fresh_count := solve_second(sample)
log.info("solves_second_sample count = %v", fresh_count)
testing.expect_value(t, fresh_count, 14)
}
@(test)
solves_second_input :: proc(t: ^testing.T) {
content, _ := os.read_entire_file("day5input.txt")
defer delete(content)
fresh_count := solve_second(string(content))
log.info("solves_second_input count = %v", fresh_count)
testing.expect_value(t, fresh_count, 352340558684863)
}