diff --git a/2022/rust/inputs/day12.txt b/2022/rust/inputs/day12.txt new file mode 100644 index 0000000..5b843ef --- /dev/null +++ b/2022/rust/inputs/day12.txt @@ -0,0 +1,41 @@ +abcccccccccaaaaaaaaaaccccccccccccaaaaaaaaccaaccccccccccccccccccccccccccccccccccccccccccccaaaaaa +abccccccccccaaaaaaaaaccccccccccccaaaaaaaaaaaacccccccccccaacccacccccccccccccccccccccccccccaaaaaa +abcccccccccccaaaaaaacccccccccccccaaaaaaaaaaaaaacccccccccaaacaacccccccccaaaccccccccccccccccaaaaa +abccccccccccaaaaaaccccccccccccccaaaaaaaaaaaaaaaccccccccccaaaaaccccccccccaaacccccccccccccccccaaa +abccccccccccaaaaaaaccccccccccccaaaaaaaaaaaaaacccccccccccaaaaaacccccccccaaaacccccccccccccccccaac +abaaccaaccccaaccaaaccccccccaaaaaaaaaaaaaaacaaccccccccccaaaaaaaacccccccccaaalcccccccccccccccaaac +abaaaaaacccccccccaaccccccccaaaaaacccaaaacccaaccccccccccaaaaaaaaccccccccalllllllcccccccccccccccc +abaaaaaacccccccaaacccccccccaaaaccccccaaaccccaaaaacccccccccaacccccccaaaakllllllllcccccccaacccccc +abaaaaaacccccccaaaacccccccccaacccccccaaaccccaaaaacccccccccaacccccccaakkklllpllllccccacaaacccccc +abaaaaaaaccccccaaaaccccaaccccccccccccccccccaaaaaaccccccccccccccccccckkkkpppppplllcccaaaaaaacccc +abaaaaaaacaaaccaaaaccaaaaaaccccccccccccccccaaaaaacccccccaaaccccckkkkkkkpppppppplllcddaaaaaacccc +abcaaaacccaacccccccccaaaaaacccccaaaccccccccaaaaaacccccccaaaaccjkkkkkkkpppppuppplmmdddddaaaccccc +abccaaaaaaaaaccccccccaaaaaaccccaaaaaacccccccaaacccccccccaaaajjjkkkkkrpppuuuuupppmmmdddddacccccc +abccccaaaaaaaacccccccaaaaacccccaaaaaacccccccccccccccccccaaacjjjjrrrrrrppuuuuupqqmmmmmddddaccccc +abccccaaaaaaaaacccccccaaaacccccaaaaaaccccccccccccccccccccccjjjrrrrrrrrpuuuxuvvqqqmmmmmddddccccc +abccccaaaaaaaaacccccccccccccccccaaaaaccccaacccaccccccccaaccjjjrrrruuuuuuuxxyvvqqqqqmmmmmdddcccc +abccccaaaaaaaacccccccccaaaccccccaacaaccccaaacaacccaaacaaaccjjjrrrtuuuuuuuxxyvvvqqqqqmmmmdddcccc +abccaaaaaaaacccccccccccaaaaaccccccccccccccaaaaacccaaaaaaaccjjjrrttttxxxxxxyyvvvvvqqqqmmmmdeeccc +abccaaaccaaaccccccccaacaaaaacccccccccccccaaaaaacccaaaaaacccjjjrrtttxxxxxxxyyvvvvvvvqqqmmmeeeccc +abaaaaaaaaaacccaaaccaaaaaaaaaaaccaaaccccaaaaaaaacccaaaaaaaajjjqqrttxxxxxxxyyyyyyvvvqqqnnneeeccc +SbaaaaaaaaccccaaaaccaaaaaaaaaaaaaaaaacccaaaaaaaaccaaaaaaaaacjjjqqtttxxxxEzzyyyyvvvvqqqnnneeeccc +abcaaaaaacccccaaaaccccaaaaaaaccaaaaaaccccccaaccccaaaaaaaaaaciiiqqqtttxxxyyyyyyvvvvrrrnnneeecccc +abcaaaaaacccccaaaacccaaaaaaaaccaaaaaaccccccaaccccaaacaaacccciiiqqqqttxxyyyyyywvvvrrrnnneeeecccc +abcaaaaaaccccccccccccaaaaaaaaacaaaaacccccccccccccccccaaaccccciiiqqtttxxyyyyyywwrrrrnnnneeeccccc +abcaaacaacccccaacccccaaaaaaaaacaaaaacccccccccccccccccaaaccccciiiqqttxxxywwyyywwrrrnnnneeecccccc +abccccccccaaacaaccccccccccacccccccccccccccccccccccccccccccccciiqqqttxxwwwwwwywwrrrnnneeeccccccc +abccaacccccaaaaaccccccccccccccccccccccccccccccccccccccccaacaaiiqqqttwwwwsswwwwwrrrnnfffeccccccc +abaaaaccccccaaaaaacccccccccccccccccccccccccccccaaaccccccaaaaaiiqqqttssssssswwwwrrronfffaccccccc +abaaaaaacccaaaaaaacccccccccccccccccccccccccccaaaaaacccccaaaaaiiqqqssssssssssswrrrooofffaaaacccc +abaaaaaaccaaaaaacccccccccccccccccccccccccccccaaaaaacccccaaaaaiiqqqppssspppssssrrrooofffaaaacccc +abaaaaaaccaacaaacccccccccccccccccccccccccccccaaaaaacccccaaaaaiihpppppppppppossrrooofffaaaaacccc +abaaaaccccccccaacccccccccccccccccccccccccccccaaaaaccccccccaaahhhhppppppppppoooooooofffaaaaccccc +abaaaaccccccccccaacccccccccccccccccaaacccccccaaaaacccccccccccchhhhhhhhhhggpoooooooffffaaaaccccc +abccaacccccccacaaaccccccccccccccccaaaaacccccccccccccccccccccccchhhhhhhhhggggoooooffffaacaaacccc +abccccccccccaaaaacaaccccccccccccccaaaaaccccccccccccccccccccccccchhhhhhhhggggggggggffcaacccccccc +abccccccccccaaaaaaaaccccccccccccccaaaacccaacccccccccccaccccccccccccccaaaaaggggggggfcccccccccccc +abccccccccccccaaaaaccccaacccccccccaaaacaaaaccccccccaaaaccccccccccccccaaaacaaagggggcccccccccaccc +abcccccccccccaaaaacccccaacccccccccaaaaaaaaaccccccccaaaaaaccccccccccccaaaccaaaacccccccccccccaaac +abcccccccccccaacaaccaaaaaaaacccaaaaaaaaaaaccccccccccaaaaccccccccccccccaccccaaacccccccccccccaaaa +abccccccccccccccaaccaaaaaaaaccaaaaaaaaaaaccccccccccaaaaacccccccccccccccccccccacccccccccccccaaaa +abccccccccccccccccccccaaaaacccaaaaaaaaaaaacccccccccaacaacccccccccccccccccccccccccccccccccaaaaaa diff --git a/2022/rust/src/main.rs b/2022/rust/src/main.rs index c970040..72e5b68 100644 --- a/2022/rust/src/main.rs +++ b/2022/rust/src/main.rs @@ -3,5 +3,5 @@ mod solutions; fn main() { - solutions::day11::run(); + solutions::day12::run(); } diff --git a/2022/rust/src/solutions/day12.rs b/2022/rust/src/solutions/day12.rs new file mode 100644 index 0000000..c964613 --- /dev/null +++ b/2022/rust/src/solutions/day12.rs @@ -0,0 +1,143 @@ +use std::cmp::Ordering; +use std::collections::{BinaryHeap, HashMap}; +use crate::utils; +use crate::utils::matrix::Matrix; + + +pub fn run() -> () { + let data = parse_data(&utils::read_lines(utils::Source::Day(12))); + + println!("Day 12"); + println!("Part 1: {}", solve1(&data)); + println!("Part 2: {}", solve2(&data)); +} + + +type Data = ((usize, usize), (usize, usize), Matrix); + +#[derive(Copy, Clone, Eq, PartialEq)] +struct State { + cost: i32, + position: (usize, usize), +} + +impl Ord for State { + fn cmp(&self, other: &Self) -> Ordering { + other.cost.cmp(&self.cost) + .then_with(|| self.position.cmp(&other.position)) + } +} + +impl PartialOrd for State { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +fn neighbours((row, col): (usize, usize), (rows, cols): (usize, usize)) -> Vec<(usize, usize)> { + let mut ns = Vec::with_capacity(4); + if row + 1 < rows { ns.push((row + 1, col)) }; + if 0 < row { ns.push((row - 1, col)) }; + if col + 1 < cols{ ns.push((row, col + 1)) }; + if 0 < col { ns.push((row, col - 1)) }; + ns +} + +fn manhattan(start: (usize, usize), goal: (usize, usize)) -> i32 { + (start.0.abs_diff(goal.0) + start.1.abs_diff(goal.1)) as i32 +} + +fn unwind_path( + parent_map: &HashMap<(usize, usize), (usize, usize)>, + start: (usize, usize), + goal: (usize, usize), +) -> Option> { + let mut path = vec![goal]; + while !path.last()?.eq(&start) { + path.push(*parent_map.get(path.last()?)?); + } + Some(path) +} + +fn a_star(start: (usize, usize), goal: (usize, usize), grid: &Matrix) -> Vec<(usize, usize)> { + let mut frontier: BinaryHeap = BinaryHeap::new(); + let mut parent: HashMap<(usize, usize), (usize, usize)> = HashMap::new(); + let mut cost: HashMap<(usize, usize), i32> = HashMap::from([(start, 0)]); + + frontier.push(State { cost: 0, position: start }); + while let Some(State { position: current, .. }) = frontier.pop() { + if current == goal { break }; + + for neighbour in neighbours(current, grid.shape()) { + // unreachable + let level_diff = grid[neighbour].abs_diff(grid[current]); + if grid[neighbour] > grid[current] && level_diff > 1 { continue }; + + let new_cost = cost.get(¤t).unwrap() + 1; + if !cost.contains_key(&neighbour) || new_cost < *cost.get(&neighbour).unwrap() { + cost.insert(neighbour, new_cost); + parent.insert(neighbour, current); + frontier.push(State { + cost: new_cost + manhattan(neighbour, goal), + position: neighbour, + }); + } + } + } + + unwind_path(&parent, start, goal).unwrap() +} + +fn solve1((start, goal, grid): &Data) -> usize { + a_star(*start, *goal, grid).len() - 1 +} + +fn solve2(data: &Data) -> i32 { + 2 +} + + +fn parse_data>(data: &[T]) -> Data { + const OFFSET: u8 = 'a' as u8; + let mut s = (0, 0); + let mut e = (0, 0); + let map = data.iter() + .enumerate() + .flat_map(|(row, line)| { + let line = line.as_ref(); + line.find("S").and_then(|col| Some(s = (row, col))); + line.find("E").and_then(|col| Some(e = (row, col))); + line.chars().map(|char| match char { + 'S' => 'a' as u8 - OFFSET, + 'E' => 'z' as u8 - OFFSET, + c => c as u8 - OFFSET + }) + }) + .collect::>() + .reshape_rows(data.len()); + (s, e, map) +} + + +#[cfg(test)] +mod tests { + use super::*; + + static DATA: &[&str] = &[ + "Sabqponm", + "abcryxxl", + "accszExk", + "acctuvwj", + "abdefghi", + ]; + + #[test] + fn part1() { + assert_eq!(31, solve1(&parse_data(DATA))); + } + + #[test] + fn part2() { + assert_eq!(2, solve2(&parse_data(DATA))); + } +} diff --git a/2022/rust/src/solutions/mod.rs b/2022/rust/src/solutions/mod.rs index 490893f..47112b7 100644 --- a/2022/rust/src/solutions/mod.rs +++ b/2022/rust/src/solutions/mod.rs @@ -9,3 +9,4 @@ pub mod day08; pub mod day09; pub mod day10; pub mod day11; +pub mod day12; diff --git a/2022/rust/src/utils/matrix.rs b/2022/rust/src/utils/matrix.rs index 6fcbeb3..6adf5c6 100644 --- a/2022/rust/src/utils/matrix.rs +++ b/2022/rust/src/utils/matrix.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +use std::fmt; use std::ops::{Index, IndexMut}; use std::slice::{ChunksExact, Iter}; @@ -111,3 +112,16 @@ impl FromIterator for Matrix { Matrix { array, cols, rows: 1 } } } + +impl fmt::Display for Matrix where T: fmt::Display { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for row in self.iter_rows() { + for item in row { + write!(f, "{}", item)? + }; + write!(f, "\n")?; + }; + Ok(()) + } +} +