Skip to content

Commit dac409b

Browse files
committed
🍲
1 parent 40e0554 commit dac409b

File tree

3 files changed

+105
-1
lines changed

3 files changed

+105
-1
lines changed

aoc2025_wasm/inputs

aoc2025_wasm/src/impl_2025_05.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use ahash::AHashSet;
2+
use anyhow::{Context, Result};
3+
use itertools::Itertools;
4+
5+
fn parse(raw_input: &str) -> Result<(Vec<(u64, u64)>, Vec<u64>)> {
6+
let (ranges, ingredients) = raw_input.split_once("\n\n").context("invalid format")?;
7+
8+
let ranges: Vec<(u64, u64)> = ranges
9+
.lines()
10+
.map(|line| {
11+
let (start, end) = line.split_once("-").context("invalid range format")?;
12+
Ok((start.parse::<u64>()?, end.parse::<u64>()? + 1))
13+
})
14+
.collect::<Result<Vec<_>>>()?;
15+
16+
let ingredients: Vec<u64> = ingredients
17+
.lines()
18+
.map(|line| line.parse::<u64>().context("parsing ingredient failed"))
19+
.collect::<Result<Vec<_>>>()?;
20+
21+
Ok((ranges, ingredients))
22+
}
23+
24+
fn calculate_p1(ranges: &[(u64, u64)], ingredients: &[u64]) -> usize {
25+
ingredients
26+
.iter()
27+
.filter(|&&i| ranges.iter().any(|&r| r.0 <= i && r.1 > i))
28+
.count()
29+
}
30+
31+
fn split_at_boundaries(range: (u64, u64), boundaries: &[u64]) -> Vec<(u64, u64)> {
32+
let mut output = vec![];
33+
output.push(range.0);
34+
for &b in boundaries {
35+
if b > range.0 && b < range.1 {
36+
output.push(b);
37+
}
38+
}
39+
output.push(range.1);
40+
41+
output.into_iter().tuple_windows().collect::<Vec<_>>()
42+
}
43+
44+
fn calculate_p2(ranges: &[(u64, u64)]) -> u64 {
45+
let boundaries = ranges
46+
.iter()
47+
.flat_map(|r| [r.0, r.1])
48+
.sorted()
49+
.unique()
50+
.collect::<Vec<_>>();
51+
52+
let mut fresh = AHashSet::default();
53+
let mut p2 = 0;
54+
55+
for &range in ranges {
56+
for subrange in split_at_boundaries(range, &boundaries) {
57+
if fresh.insert(subrange) {
58+
p2 += subrange.1 - subrange.0;
59+
}
60+
}
61+
}
62+
p2
63+
}
64+
65+
pub fn run_2025_05(inp: &str) -> Result<String> {
66+
let (ranges, ingredients) = parse(inp)?;
67+
let p1 = calculate_p1(&ranges, &ingredients);
68+
let p2 = calculate_p2(&ranges);
69+
Ok(format!("{p1}\n{p2}"))
70+
}
71+
72+
#[cfg(test)]
73+
mod tests {
74+
use super::*;
75+
76+
const EXAMPLE_DATA: &str = include_str!("../inputs/examples/2025_05");
77+
const REAL_DATA: &str = include_str!("../inputs/real/2025_05");
78+
79+
#[test]
80+
fn test_example_p1() {
81+
let (ranges, ingredients) = parse(EXAMPLE_DATA).unwrap();
82+
assert_eq!(calculate_p1(&ranges, &ingredients), 3);
83+
}
84+
85+
#[test]
86+
fn test_example_p2() {
87+
let (ranges, _) = parse(EXAMPLE_DATA).unwrap();
88+
assert_eq!(calculate_p2(&ranges), 14);
89+
}
90+
91+
#[test]
92+
fn test_real_p1() {
93+
let (ranges, ingredients) = parse(REAL_DATA).unwrap();
94+
assert_eq!(calculate_p1(&ranges, &ingredients), 694);
95+
}
96+
97+
#[test]
98+
fn test_real_p2() {
99+
let (ranges, _) = parse(REAL_DATA).unwrap();
100+
assert_eq!(calculate_p2(&ranges), 352716206375547);
101+
}
102+
}

aoc2025_wasm/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod impl_2025_01;
33
mod impl_2025_02;
44
mod impl_2025_03;
55
mod impl_2025_04;
6+
mod impl_2025_05;
67

78
pub use wasm_bindgen_rayon::init_thread_pool;
89

@@ -16,6 +17,7 @@ pub fn run_day(day: u32, input: &str) -> String {
1617
2 => impl_2025_02::run_2025_02(input),
1718
3 => impl_2025_03::run_2025_03(input),
1819
4 => impl_2025_04::run_2025_04(input),
20+
5 => impl_2025_05::run_2025_05(input),
1921
_ => Err(anyhow!("No solution for that day yet")),
2022
};
2123

0 commit comments

Comments
 (0)