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) }