···11+# Seeds for failure cases proptest has generated in the past. It is
22+# automatically read and these particular cases re-run before any
33+# novel cases are generated.
44+#
55+# It is recommended to check this file in to source control so that
66+# everyone who runs the test benefits from these saved cases.
77+cc bb0719e603e9f2a6737bc2edded7acfc9bc57a242925352b86fd427aed246bff # shrinks to v = [1]
88+cc 71c951b8e7ff83d0d15eb4d275d309b580358257edde61fc52834333377dfd70 # shrinks to s = "0"
+236
examples/day_03_lobby.rs
···11+fn main() {
22+ aoc2025::run(
33+ "Day 3: Lobby",
44+ "inputs/day_03.txt",
55+ parse_input,
66+ part_1,
77+ part_2,
88+ )
99+ .unwrap();
1010+}
1111+1212+fn parse_bank(bank: &str) -> Vec<u64> {
1313+ bank.chars()
1414+ .filter_map(|ch| ch.to_digit(10))
1515+ .map(|x| x as u64)
1616+ .filter(|x| *x != 0)
1717+ .collect::<Vec<_>>()
1818+}
1919+2020+fn parse_input(input: &str) -> Vec<Vec<u64>> {
2121+ (input.split("\n"))
2222+ .map(|s| parse_bank(s))
2323+ .filter(|v| !v.is_empty())
2424+ .collect::<Vec<_>>()
2525+}
2626+2727+fn find_highest_naive_joltage(bank: Vec<u64>) -> u64 {
2828+ let mut max = 0;
2929+ for (i, a) in bank.iter().enumerate() {
3030+ for b in &bank[(i + 1)..bank.len()] {
3131+ max = max.max(a * 10 + b);
3232+ }
3333+ }
3434+ max
3535+}
3636+3737+fn find_highest_joltage(bank: Vec<u64>) -> u64 {
3838+ let n = bank.len();
3939+4040+ let keep = 12_usize;
4141+ let mut result: Vec<u64> = Vec::with_capacity(keep);
4242+4343+ let mut start = 0_usize;
4444+ let mut remaining = keep;
4545+4646+ while remaining > 0 {
4747+ let end = n - remaining;
4848+4949+ let mut best_digit = 0_u64;
5050+ let mut best_index = start;
5151+5252+ for i in start..=end {
5353+ let d = bank[i];
5454+ if d > best_digit {
5555+ best_digit = d;
5656+ best_index = i;
5757+5858+ if d == 9 {
5959+ break;
6060+ }
6161+ }
6262+ }
6363+6464+ result.push(best_digit);
6565+ start = best_index + 1;
6666+ remaining -= 1;
6767+ }
6868+6969+ let s: String = result.iter().map(|d| d.to_string()).collect();
7070+ s.parse::<u64>().unwrap()
7171+}
7272+7373+fn part_1(banks: Vec<Vec<u64>>) -> u64 {
7474+ (banks.iter())
7575+ .map(|bank| find_highest_naive_joltage(bank.clone()))
7676+ .sum()
7777+}
7878+7979+fn part_2(banks: Vec<Vec<u64>>) -> u64 {
8080+ (banks.iter())
8181+ .map(|bank| find_highest_joltage(bank.clone()))
8282+ .sum()
8383+}
8484+8585+#[cfg(test)]
8686+mod test {
8787+ use super::*;
8888+ use proptest::prelude::*;
8989+9090+ fn bank() -> impl Strategy<Value = Vec<u64>> {
9191+ prop::collection::vec(1_u64..10, 2..200)
9292+ }
9393+9494+ fn rigged_bank(rig_count: usize) -> impl Strategy<Value = (Vec<u64>, Vec<u64>)> {
9595+ let min_len = rig_count.max(2);
9696+9797+ prop::collection::vec(1_u64..5, min_len..20).prop_flat_map(move |bank| {
9898+ let len = bank.len();
9999+ let all_indices: Vec<usize> = (0..len).collect();
100100+101101+ let indices_strategy = prop::sample::subsequence(all_indices.clone(), rig_count);
102102+103103+ let values_strategy =
104104+ prop::collection::vec(6_u64..10, rig_count).prop_map(|mut vals| {
105105+ vals.sort_by(|a, b| b.cmp(a));
106106+ vals
107107+ });
108108+109109+ (indices_strategy, values_strategy).prop_map(move |(indices, rigged_values)| {
110110+ let mut bank = bank.clone();
111111+112112+ for (idx, val) in indices.iter().zip(rigged_values.iter()) {
113113+ bank[*idx] = *val;
114114+ }
115115+116116+ (bank, rigged_values)
117117+ })
118118+ })
119119+ }
120120+121121+ prop_compose! {
122122+ fn bank_input()(bank in bank()) -> (Vec<u64>, String) {
123123+ let input = bank.iter().map(|x| x.to_string()).collect::<Vec<_>>().join("");
124124+ (bank, input)
125125+ }
126126+ }
127127+128128+ prop_compose! {
129129+ fn input()(banks in prop::collection::vec(bank_input(), 1..200)) -> (Vec<Vec<u64>>, String) {
130130+ let (values, input): (Vec<_>, Vec<_>) = banks.into_iter().unzip();
131131+ (values, input.join("\n"))
132132+ }
133133+ }
134134+135135+ mod parse_bank {
136136+ use super::*;
137137+138138+ proptest! {
139139+ #[test]
140140+ fn doesnt_crash(s in "\\PC+") {
141141+ parse_bank(s.as_str());
142142+ }
143143+144144+ #[test]
145145+ fn doesnt_parse_nondigits(s in "[^[1-9]]+") {
146146+ prop_assert!(parse_bank(s.as_str()).is_empty());
147147+ }
148148+149149+ #[test]
150150+ fn correctly_parses_digits((values, input) in bank_input()) {
151151+ prop_assert_eq!(values, parse_bank(&input));
152152+ }
153153+ }
154154+ }
155155+156156+ mod parse_input {
157157+ use super::*;
158158+159159+ proptest! {
160160+ #[test]
161161+ fn doesnt_crash(s in "\\PC+") {
162162+ parse_input(s.as_str());
163163+ }
164164+165165+ #[test]
166166+ fn ignores_empty_banks(s in "\\n+") {
167167+ prop_assert!(parse_input(s.as_str()).is_empty());
168168+ }
169169+170170+ #[test]
171171+ fn correctly_parses_banks((values, input) in input()) {
172172+ prop_assert_eq!(values, parse_input(input.as_str()));
173173+ }
174174+ }
175175+ }
176176+177177+ mod find_highest_naive_joltage {
178178+ use super::*;
179179+180180+ proptest! {
181181+ #[test]
182182+ fn handles_two_joltages(x in 1_u64..10, y in 1_u64..10) {
183183+ prop_assert_eq!(x * 10 + y, find_highest_naive_joltage(vec![x, y]));
184184+ }
185185+186186+ #[test]
187187+ fn maximizes_bank_joltage((bank, values) in rigged_bank(2)) {
188188+ let values = values.iter().map(|x| x.to_string()).collect::<Vec<_>>().join("").parse::<u64>().unwrap();
189189+ prop_assert_eq!(values, find_highest_naive_joltage(bank));
190190+ }
191191+ }
192192+ }
193193+194194+ mod find_highest_joltage {
195195+ use super::*;
196196+197197+ proptest! {
198198+ #[test]
199199+ fn maximizes_bank_joltage((bank, values) in rigged_bank(12)) {
200200+ let values = values.iter().map(|x| x.to_string()).collect::<Vec<_>>().join("").parse::<u64>().unwrap();
201201+ prop_assert_eq!(values, find_highest_joltage(bank));
202202+ }
203203+ }
204204+ }
205205+206206+ const EXAMPLE_INPUT: &str = r#"
207207+ 987654321111111
208208+ 811111111111119
209209+ 234234234234278
210210+ 818181911112111
211211+ "#;
212212+213213+ mod part_1 {
214214+ use super::*;
215215+216216+ const EXAMPLE_ANSWER: u64 = 357;
217217+218218+ #[test]
219219+ fn solves_example() {
220220+ let input = parse_input(EXAMPLE_INPUT);
221221+ assert_eq!(EXAMPLE_ANSWER, part_1(input));
222222+ }
223223+ }
224224+225225+ mod part_2 {
226226+ use super::*;
227227+228228+ const EXAMPLE_ANSWER: u64 = 3_121_910_778_619;
229229+230230+ #[test]
231231+ fn solves_example() {
232232+ let input = parse_input(EXAMPLE_INPUT);
233233+ assert_eq!(EXAMPLE_ANSWER, part_2(input));
234234+ }
235235+ }
236236+}