Skip to content

Commit bb62d28

Browse files
committed
Year 2024 Day 7
1 parent 61c7596 commit bb62d28

File tree

7 files changed

+131
-0
lines changed

7 files changed

+131
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
7878
| 4 | [Ceres Search](https://adventofcode.com/2024/day/4) | [Source](src/year2024/day04.rs) | 77 |
7979
| 5 | [Print Queue](https://adventofcode.com/2024/day/5) | [Source](src/year2024/day05.rs) | 18 |
8080
| 6 | [Guard Gallivant](https://adventofcode.com/2024/day/6) | [Source](src/year2024/day06.rs) | 386 |
81+
| 7 | [Bridge Repair](https://adventofcode.com/2024/day/7) | [Source](src/year2024/day07.rs) | 220 |
8182

8283
## 2023
8384

benches/benchmark.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,4 +298,5 @@ mod year2024 {
298298
benchmark!(year2024, day04);
299299
benchmark!(year2024, day05);
300300
benchmark!(year2024, day06);
301+
benchmark!(year2024, day07);
301302
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,5 @@ pub mod year2024 {
297297
pub mod day04;
298298
pub mod day05;
299299
pub mod day06;
300+
pub mod day07;
300301
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,5 +367,6 @@ fn year2024() -> Vec<Solution> {
367367
solution!(year2024, day04),
368368
solution!(year2024, day05),
369369
solution!(year2024, day06),
370+
solution!(year2024, day07),
370371
]
371372
}

src/year2024/day07.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//! # Bridge Repair
2+
//!
3+
//! The equations can be validated using a recursive solution that checks all possible combinations
4+
//! of operators. However the number of states to check grows exponentially as 2ⁿ in part one
5+
//! and 3ⁿ in part two.
6+
//!
7+
//! As much faster approach works in reverse from the end of the equation to prune as many states
8+
//! as possible by checking which operations are possible. For example:
9+
//!
10+
//! ```none
11+
//! Test Value: 123456
12+
//! Equation: 2 617 56
13+
//! Addition is possible as 123456 >= 56
14+
//! Multiplication is not possible as 56 is not a factor of 123456
15+
//! Concatenation is possible as 1234 || 56 = 123456
16+
//! ```
17+
//!
18+
//! Following the concatenation branch and applying an inverse concentation
19+
//! (the full solution would also follow the addition branch):
20+
//!
21+
//! ```none
22+
//! Test Value: 1234
23+
//! Equation: 2 617
24+
//! Addition is possible as 1234 >= 617
25+
//! Multiplication is possible as 2 * 617 = 1234
26+
//! Concatenation is not possible as 1234 does not end in 617
27+
//! ```
28+
//!
29+
//! Following the multiplication branch:
30+
//!
31+
//! ```none
32+
//! Test Value: 2
33+
//! Equation: 2
34+
//! Addition is possible
35+
//! Multiplication is possible
36+
//! Concatenation is possible
37+
//! ```
38+
//!
39+
//! Following any of theses branches results in a test value of 0 which means that all terms
40+
//! have been applied successfully and the equation is valid.
41+
//!
42+
//! Inverse concenation can be implemented without time consuming conversion to or from
43+
//! strings by dividing the left term by the next power of ten greater than the right term.
44+
//! For example:
45+
//!
46+
//! * 7 || 9 => 79 => 79 / 10 => 7
47+
//! * 12 || 34 => 1234 => 1234 / 100 => 12
48+
//! * 123 || 789 => 123789 => 123789 / 1000 => 123
49+
use crate::util::parse::*;
50+
51+
type Input = (u64, u64);
52+
53+
pub fn parse(input: &str) -> Input {
54+
let mut equation = Vec::new();
55+
let mut part_one = 0;
56+
let mut part_two = 0;
57+
58+
for line in input.lines() {
59+
equation.extend(line.iter_unsigned::<u64>());
60+
61+
// If an equation is valid for part one then it's also valid for part two.
62+
if valid(&equation, equation[0], equation.len() - 1, false) {
63+
part_one += equation[0];
64+
part_two += equation[0];
65+
} else if valid(&equation, equation[0], equation.len() - 1, true) {
66+
part_two += equation[0];
67+
}
68+
69+
equation.clear();
70+
}
71+
72+
(part_one, part_two)
73+
}
74+
75+
pub fn part1(input: &Input) -> u64 {
76+
input.0
77+
}
78+
79+
pub fn part2(input: &Input) -> u64 {
80+
input.1
81+
}
82+
83+
fn valid(terms: &[u64], test_value: u64, index: usize, concat: bool) -> bool {
84+
(test_value == 0)
85+
|| (concat
86+
&& test_value % next_power_of_ten(terms[index]) == terms[index]
87+
&& valid(terms, test_value / next_power_of_ten(terms[index]), index - 1, concat))
88+
|| (test_value % terms[index] == 0
89+
&& valid(terms, test_value / terms[index], index - 1, concat))
90+
|| (test_value >= terms[index]
91+
&& valid(terms, test_value - terms[index], index - 1, concat))
92+
}
93+
94+
fn next_power_of_ten(n: u64) -> u64 {
95+
let mut power = 10;
96+
97+
while power <= n {
98+
power *= 10;
99+
}
100+
101+
power
102+
}

tests/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,5 @@ mod year2024 {
287287
mod day04_test;
288288
mod day05_test;
289289
mod day06_test;
290+
mod day07_test;
290291
}

tests/year2024/day07_test.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use aoc::year2024::day07::*;
2+
3+
const EXAMPLE: &str = "\
4+
190: 10 19
5+
3267: 81 40 27
6+
83: 17 5
7+
156: 15 6
8+
7290: 6 8 6 15
9+
161011: 16 10 13
10+
192: 17 8 14
11+
21037: 9 7 18 13
12+
292: 11 6 16 20";
13+
14+
#[test]
15+
fn part1_test() {
16+
let input = parse(EXAMPLE);
17+
assert_eq!(part1(&input), 3749);
18+
}
19+
20+
#[test]
21+
fn part2_test() {
22+
let input = parse(EXAMPLE);
23+
assert_eq!(part2(&input), 11387);
24+
}

0 commit comments

Comments
 (0)