Skip to content

Commit 7fdaeb8

Browse files
committed
feat(21/2024): solve first part
1 parent f41ddb1 commit 7fdaeb8

File tree

2 files changed

+35
-80
lines changed

2 files changed

+35
-80
lines changed

readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
| [Day 18: RAM Run](src/solutions/year2024/day18.rs) | ⭐⭐ | 2.487 | 204.885 |
3232
| [Day 19: Linen Layout](src/solutions/year2024/day19.rs) | ⭐⭐ | 2.923 | 22.751 |
3333
| [Day 20: Race Condition](src/solutions/year2024/day20.rs) | ⭐⭐ | 7.355 | 280.627 |
34-
| [Day 21: Keypad Conundrum](src/solutions/year2024/day21.rs) | - | - | - |
34+
| [Day 21: Keypad Conundrum](src/solutions/year2024/day21.rs) | | 1.610 | - |
3535

3636
# 2023
3737

src/solutions/year2024/day21.rs

+34-79
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl Solution for Day21 {
3131
input
3232
.lines()
3333
.map(|line| {
34-
let path_len = self.path_len(line, &pads);
34+
let path_len = self.path(line, &pads).chars().count();
3535
let num: usize = line.trim_end_matches('A').parse().unwrap();
3636

3737
num * path_len
@@ -46,46 +46,53 @@ impl Solution for Day21 {
4646
}
4747

4848
impl Day21 {
49-
fn path_len(&self, code: &str, pads: &Vec<Pad>) -> usize {
50-
let mut current = code.to_string();
51-
52-
for pad in pads {
53-
let path = self.path_for_str(&current, pad);
54-
55-
current = path.iter().map(|key| key.to_string()).collect::<String>();
49+
fn path(&self, code: &str, pads: &[Pad]) -> String {
50+
if pads.is_empty() {
51+
return code.to_string();
5652
}
5753

58-
current.chars().count()
54+
let code = "A".to_owned() + code;
55+
let pad = &pads[0];
56+
let pad_left = &pads[1..];
57+
58+
code.chars()
59+
.tuple_windows()
60+
.map(|(from, to)| {
61+
self.all_shortest_paths_between_buttons(from, to, pad)
62+
.iter()
63+
.map(|path| self.path(path, pad_left))
64+
.min_by_key(|path| path.chars().count())
65+
.unwrap()
66+
})
67+
.collect()
5968
}
6069

61-
fn path_for_str(&self, code: &str, pad: &Pad) -> Vec<Key> {
62-
let code = "A".to_owned() + code;
70+
fn all_shortest_paths_between_buttons(&self, from: char, to: char, pad: &Pad) -> Vec<String> {
6371
let adjacent = pad.adjacent.clone();
6472

6573
let neighbours = Box::new(move |p: Point| adjacent.get(&p).unwrap().to_vec());
6674
let distance = Box::new(|_, _| 1);
6775

6876
let dijkstra = Dijkstra::new(neighbours, distance);
6977

70-
code.chars()
71-
.tuple_windows()
72-
.flat_map(|(from, to)| {
73-
let start = pad.position(from as u8).unwrap();
74-
let end = pad.position(to as u8).unwrap();
78+
let start = pad.position(from as u8).unwrap();
79+
let end = pad.position(to as u8).unwrap();
7580

76-
let is_end = |p: Point| p == end;
77-
let path = dijkstra.all_paths(vec![start], &is_end);
81+
let is_end = |p: Point| p == end;
82+
let paths = dijkstra.all_paths(vec![start], &is_end);
7883

79-
let min_path = path.iter().min_by_key(|p| p.len()).unwrap();
80-
let mut directions: Vec<Key> = min_path
84+
paths
85+
.iter()
86+
.map(|path| {
87+
let mut directions: Vec<Key> = path
8188
.iter()
8289
.collect_vec()
8390
.windows(2)
8491
.map(|pair| Dir(pair[0].direction(pair[1]).unwrap()))
8592
.collect();
8693
directions.push(Activate);
8794

88-
directions.into_iter()
95+
directions.iter().map(|d| d.to_string()).collect()
8996
})
9097
.collect()
9198
}
@@ -175,10 +182,8 @@ impl Pad {
175182

176183
#[cfg(test)]
177184
mod tests {
178-
use crate::solutions::year2024::day21::Key::{Activate, Dir};
179185
use crate::solutions::year2024::day21::{Day21, Pad};
180186
use crate::solutions::Solution;
181-
use crate::utils::direction::Direction::{East, North, South, West};
182187

183188
const EXAMPLE: &str = r#"029A
184189
980A
@@ -187,69 +192,19 @@ mod tests {
187192
379A"#;
188193

189194
#[test]
190-
#[ignore]
191195
fn part_one_example() {
192196
assert_eq!("126384", Day21.part_one(EXAMPLE));
193197
}
194198

195199
#[test]
196-
#[ignore]
197200
fn path_len() {
198201
let pads = vec![Pad::numeric(), Pad::key(), Pad::key()];
199202

200-
assert_eq!(68, Day21.path_len("029A", &pads));
201-
assert_eq!(60, Day21.path_len("980A", &pads));
202-
assert_eq!(68, Day21.path_len("179A", &pads));
203-
assert_eq!(64, Day21.path_len("456A", &pads));
204-
assert_eq!(64, Day21.path_len("379A", &pads));
205-
assert_eq!(78, Day21.path_len("739A", &pads));
206-
}
207-
208-
#[test]
209-
fn path_for_str() {
210-
let numeric = &Pad::numeric();
211-
let key = &Pad::key();
212-
213-
assert_eq!(Day21.path_for_str("AA", numeric), vec![Activate, Activate]);
214-
assert_eq!(
215-
Day21.path_for_str("A1", numeric),
216-
vec![Activate, Dir(North), Dir(West), Dir(West), Activate]
217-
);
218-
assert_eq!(
219-
Day21.path_for_str("A4", numeric),
220-
vec![
221-
Activate,
222-
Dir(North),
223-
Dir(North),
224-
Dir(West),
225-
Dir(West),
226-
Activate
227-
]
228-
);
229-
assert_eq!(
230-
Day21.path_for_str("A7", numeric),
231-
vec![
232-
Activate,
233-
Dir(North),
234-
Dir(North),
235-
Dir(North),
236-
Dir(West),
237-
Dir(West),
238-
Activate
239-
]
240-
);
241-
assert_eq!(
242-
Day21.path_for_str("<A", key),
243-
vec![
244-
Dir(South),
245-
Dir(West),
246-
Dir(West),
247-
Activate,
248-
Dir(East),
249-
Dir(East),
250-
Dir(North),
251-
Activate
252-
]
253-
);
203+
assert_eq!(68, Day21.path("029A", &pads).len());
204+
assert_eq!(60, Day21.path("980A", &pads).len());
205+
assert_eq!(68, Day21.path("179A", &pads).len());
206+
assert_eq!(64, Day21.path("456A", &pads).len());
207+
assert_eq!(64, Day21.path("379A", &pads).len());
208+
assert_eq!(78, Day21.path("739A", &pads).len());
254209
}
255210
}

0 commit comments

Comments
 (0)