Skip to content

Commit 3bbd42f

Browse files
committed
Solution for 2024-12-21 in rust
1 parent d9d7550 commit 3bbd42f

4 files changed

Lines changed: 147 additions & 3 deletions

File tree

2024/examples/day21_01.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
029A
2+
980A
3+
179A
4+
456A
5+
379A

2024/inputs/day21.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
319A
2+
985A
3+
340A
4+
489A
5+
964A

2024/rust/src/day21.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use std::{collections::HashMap, hash::Hash};
2+
3+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4+
struct Point {
5+
row: usize,
6+
col: usize,
7+
}
8+
9+
impl Point {
10+
// Only consider sequences with a single turn
11+
pub fn sequences_to(&self, other: &Point, reverse_row_axis: bool) -> Vec<String> {
12+
let delta_row = (other.row as isize - self.row as isize) * if reverse_row_axis { -1 } else { 1 };
13+
let symbol = if delta_row < 0 { "v" } else { "^" };
14+
let vertical_part = (0..delta_row.abs()).fold("".to_string(), |res, _| res + symbol);
15+
16+
let delta_col = other.col as isize - self.col as isize;
17+
let symbol = if delta_col < 0 { "<" } else { ">" };
18+
let horizontal_part = (0..delta_col.abs()).fold("".to_string(), |res, _| res + symbol);
19+
20+
21+
if self.col == 0 && other.row == 0 {
22+
return vec![horizontal_part + &vertical_part + &"A"];
23+
}
24+
25+
if self.row == 0 && other.col == 0 {
26+
return vec![vertical_part + &horizontal_part + &"A"];
27+
}
28+
29+
if self.row == other.row || self.col == other.col {
30+
return vec![horizontal_part + &vertical_part + &"A"]
31+
}
32+
33+
vec![horizontal_part.clone() + &vertical_part + &"A", vertical_part + &horizontal_part + &"A"]
34+
}
35+
}
36+
37+
#[derive(Debug, Clone, PartialEq, Eq)]
38+
struct Keypad {
39+
keys: HashMap<char, Point>,
40+
reverse_row_axis: bool,
41+
}
42+
43+
impl Keypad {
44+
pub fn numpad() -> Self {
45+
let mut keys = HashMap::new();
46+
keys.insert('0', Point { row: 0, col: 1 });
47+
keys.insert('A', Point { row: 0, col: 2 });
48+
keys.insert('1', Point { row: 1, col: 0 });
49+
keys.insert('2', Point { row: 1, col: 1 });
50+
keys.insert('3', Point { row: 1, col: 2 });
51+
keys.insert('4', Point { row: 2, col: 0 });
52+
keys.insert('5', Point { row: 2, col: 1 });
53+
keys.insert('6', Point { row: 2, col: 2 });
54+
keys.insert('7', Point { row: 3, col: 0 });
55+
keys.insert('8', Point { row: 3, col: 1 });
56+
keys.insert('9', Point { row: 3, col: 2 });
57+
58+
Keypad { keys, reverse_row_axis: false }
59+
}
60+
61+
pub fn arrowpad() -> Self {
62+
let mut keys = HashMap::new();
63+
keys.insert('^', Point { row: 0, col: 1 });
64+
keys.insert('A', Point { row: 0, col: 2 });
65+
keys.insert('<', Point { row: 1, col: 0 });
66+
keys.insert('v', Point { row: 1, col: 1 });
67+
keys.insert('>', Point { row: 1, col: 2 });
68+
69+
70+
Keypad { keys, reverse_row_axis: true }
71+
}
72+
73+
pub fn generate_sequences(&self) -> HashMap<String, Vec<String>> {
74+
let mut sequences = HashMap::new();
75+
for (key, point) in self.keys.iter() {
76+
for (other_key, other_point) in self.keys.iter() {
77+
let seqs = point.sequences_to(other_point, self.reverse_row_axis);
78+
let pair = format!("{}{}", key, other_key);
79+
sequences.insert(pair, seqs);
80+
81+
}
82+
}
83+
84+
sequences
85+
}
86+
87+
}
88+
89+
fn count_levels(current_sequence: &String, depth: usize, pair_to_paths_map: &HashMap<String, Vec<String>>, memo: &mut HashMap<(String, usize), usize>) -> usize {
90+
if depth == 0 {
91+
return current_sequence.len();
92+
}
93+
94+
match memo.get(&(current_sequence.clone(), depth)) {
95+
Some(count) => { return count.clone() },
96+
None => {},
97+
}
98+
99+
let (_, count) = current_sequence.chars().fold(('A', 0_usize), |(last_char, mut count), char| {
100+
let pattern = format!("{}{}", last_char, char);
101+
count += pair_to_paths_map.get(&pattern).unwrap().iter().map(|next_part| {
102+
count_levels(&next_part, depth - 1, pair_to_paths_map, memo)
103+
}).min().unwrap();
104+
(char, count)
105+
});
106+
107+
memo.insert((current_sequence.clone(), depth), count);
108+
count
109+
}
110+
111+
fn task(input: &str, n_robots: usize) -> String {
112+
let numpad = Keypad::numpad();
113+
let arrowpad = Keypad::arrowpad();
114+
115+
let mut pair_to_paths_map = numpad.generate_sequences();
116+
arrowpad.generate_sequences().iter().for_each(|(k, v)| {
117+
pair_to_paths_map.insert(k.clone(), v.clone());
118+
});
119+
120+
121+
let mut memo = HashMap::new();
122+
input.lines().fold(0, |acc, line| {
123+
let min_len = count_levels(&line.to_string(), n_robots, &pair_to_paths_map, &mut memo);
124+
acc + min_len * line[..line.len() - 1].parse::<usize>().unwrap()
125+
}).to_string()
126+
}
127+
128+
pub fn task01(input: &str) -> String {
129+
task(input, 3)
130+
}
131+
132+
pub fn task02(input: &str) -> String {
133+
task(input, 26)
134+
}

2024/rust/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mod day17;
2222
mod day18;
2323
mod day19;
2424
mod day20;
25-
// mod day21;
25+
mod day21;
2626
mod day22;
2727
mod day23;
2828

@@ -68,8 +68,8 @@ pub fn get_task_map() -> HashMap<(i32, i32), fn(&str) -> String> {
6868
task_map.insert((19, 2), day19::task02);
6969
task_map.insert((20, 1), day20::task01);
7070
task_map.insert((20, 2), day20::task02);
71-
// task_map.insert((21, 1), day21::task01);
72-
// task_map.insert((21, 2), day21::task02);
71+
task_map.insert((21, 1), day21::task01);
72+
task_map.insert((21, 2), day21::task02);
7373
task_map.insert((22, 1), day22::task01);
7474
task_map.insert((22, 2), day22::task02);
7575
task_map.insert((23, 1), day23::task01);

0 commit comments

Comments
 (0)