summaryrefslogtreecommitdiff
path: root/2022/Rust/src
diff options
context:
space:
mode:
authoromagdy7 <omar.professional8777@gmail.com>2023-04-12 20:56:53 +0200
committeromagdy7 <omar.professional8777@gmail.com>2023-04-12 20:56:53 +0200
commit9d0923ac49cc92eb1e75a07dcb6a8a274d144360 (patch)
treed48989bf80999631c488c611f29cb28e76921082 /2022/Rust/src
parent01fe0c7d69cfc15c44bf8da9e7bc12c4b4ced264 (diff)
downloadaoc-9d0923ac49cc92eb1e75a07dcb6a8a274d144360.tar.xz
aoc-9d0923ac49cc92eb1e75a07dcb6a8a274d144360.zip
Day12 done in rust
Diffstat (limited to '2022/Rust/src')
-rw-r--r--2022/Rust/src/day12.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/2022/Rust/src/day12.rs b/2022/Rust/src/day12.rs
new file mode 100644
index 0000000..26dc7ac
--- /dev/null
+++ b/2022/Rust/src/day12.rs
@@ -0,0 +1,126 @@
+use std::collections::{HashMap, VecDeque};
+
+fn in_bounds(pos: (i32, i32), grid: &Vec<&[u8]>) -> bool {
+ let row = grid.len() as i32;
+ let col = grid[0].len() as i32;
+ pos.0 >= 0 && pos.0 < row && pos.1 >= 0 && pos.1 < col
+}
+
+fn is_valid(cur_char: u8, nxt_char: u8) -> bool {
+ let mut cur = cur_char as i32;
+ let mut nxt = nxt_char as i32;
+ if cur == ('S' as i32) {
+ cur = 'a' as i32;
+ }
+ if nxt == ('E' as i32) {
+ nxt = 'z' as i32;
+ }
+ nxt - cur <= 1
+}
+
+fn bfs(
+ grid: &Vec<&[u8]>,
+ target: u8,
+ start: (i32, i32),
+ path: &mut HashMap<(usize, usize), (usize, usize)>,
+) -> (usize, usize) {
+ let mut queue: VecDeque<(i32, i32)> = VecDeque::new();
+ let row = grid.len();
+ let col = grid[0].len();
+ let dx: [i32; 4] = [1, 0, -1, 0];
+ let dy: [i32; 4] = [0, -1, 0, 1];
+ queue.push_front(start);
+ let mut vis: Vec<Vec<bool>> = vec![vec![false; col]; row];
+ while !queue.is_empty() {
+ let (x, y) = queue.pop_front().unwrap();
+ for i in 0..4 {
+ let nx = x + dx[i];
+ let ny = y + dy[i];
+ if in_bounds((nx, ny), &grid)
+ && is_valid(grid[x as usize][y as usize], grid[nx as usize][ny as usize])
+ && grid[nx as usize][ny as usize] == target
+ {
+ queue.clear();
+ path.insert((nx as usize, ny as usize), (x as usize, y as usize));
+ return (nx as usize, ny as usize);
+ }
+ if in_bounds((nx, ny), &grid)
+ && is_valid(grid[x as usize][y as usize], grid[nx as usize][ny as usize])
+ && !vis[nx as usize][ny as usize]
+ {
+ queue.push_back((nx, ny));
+ vis[nx as usize][ny as usize] = true;
+ path.insert((nx as usize, ny as usize), (x as usize, y as usize));
+ }
+ }
+ }
+ (0, 0)
+}
+
+fn get_starting_node(grid: &Vec<&[u8]>) -> (i32, i32) {
+ for i in 0..grid.len() {
+ for j in 0..grid[0].len() {
+ if grid[i][j] == 'S' as u8 {
+ return (i as i32, j as i32);
+ }
+ }
+ }
+ unreachable!()
+}
+
+fn get_nodes_with_elevation_a(grid: &Vec<&[u8]>) -> Vec<(i32, i32)> {
+ let mut ret = vec![];
+ for i in 0..grid.len() {
+ for j in 0..grid[0].len() {
+ if grid[i][j] == 'S' as u8 || grid[i][j] == 'a' as u8 {
+ ret.push((i as i32, j as i32));
+ }
+ }
+ }
+ ret
+}
+
+fn solve_part_one(data: &str) -> usize {
+ let grid: Vec<_> = data.lines().map(|s| s.as_bytes()).collect();
+ let start = get_starting_node(&grid);
+ // path that has the child as a key and the value as its parent
+ let mut path: HashMap<(usize, usize), (usize, usize)> = HashMap::new();
+ let mut cur_pos = bfs(&grid, 'E' as u8, start, &mut path);
+ let mut path_length = 0;
+
+ while *path.get(&cur_pos).unwrap() != (start.0 as usize, start.1 as usize) {
+ path_length += 1;
+ cur_pos = *path.get(&cur_pos).unwrap();
+ }
+ path_length + 1
+}
+
+fn solve_part_two(data: &str) -> usize {
+ let grid: Vec<_> = data.lines().map(|s| s.as_bytes()).collect();
+ let nodes_with_elevation_a = get_nodes_with_elevation_a(&grid);
+ let mut mn = usize::MAX;
+
+ for node in nodes_with_elevation_a {
+ // path that has the child as a key and the value as its parent
+ let mut path: HashMap<(usize, usize), (usize, usize)> = HashMap::new();
+ let mut cur_pos = bfs(&grid, 'E' as u8, node, &mut path);
+ let mut path_length = 0;
+ if path.get(&cur_pos).is_some() {
+ while *path.get(&cur_pos).unwrap() != (node.0 as usize, node.1 as usize) {
+ path_length += 1;
+ cur_pos = *path.get(&cur_pos).unwrap();
+ }
+ mn = std::cmp::min(mn, path_length + 1);
+ }
+ }
+ mn
+}
+
+fn main() {
+ let test = include_str!("../input/day12.test");
+ let prod = include_str!("../input/day12.prod");
+ println!("part1: test {:?}", solve_part_one(test));
+ println!("part1: prod {:?}", solve_part_one(prod));
+ println!("part2: test {:?}", solve_part_two(test));
+ println!("part2: prod {:?}", solve_part_two(prod));
+}