156 lines
3.7 KiB
Odin
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)
|
|
}
|