diff --git a/day12/Cargo.lock b/day12/Cargo.lock new file mode 100644 index 0000000..5e9bbe3 --- /dev/null +++ b/day12/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day12" +version = "0.1.0" diff --git a/day12/input.txt b/day12/input.txt new file mode 100644 index 0000000..4ff75ee --- /dev/null +++ b/day12/input.txt @@ -0,0 +1,41 @@ +abcccccccccccccccccccccccccccccccccccccaaaaaaacccccccaaaaaaaaaaaccccccccccccccccccccaaacaaaaaaaacccccccccccccccccccccccccccccccccccaaaaa +abccccccccccccccccccaaccaacccccccccccccaaaaaaaccccccccaaaaaaaaaaacccccccaaaaccccccccaaaaaaaaaaaaacccccccccccccccccccccccccccccccccaaaaaa +abccccccccccccccccccaaaaaaccccccccccaaaccaaaaaacccccccaaaaaaaaaaccccccccaaaaccccccaaaaaaaaaaaaaaacccccccccccccccccccaaacccccccccccaaaaaa +abcccccccccccccccccccaaaaacccccccccccaaccaacaaaccccccaaaaaaaaaaaccccccccaaaacccccaaaaaaaaacaaaaaaacccccccccccccccccaaaacccccccccccaaacaa +abccccccccccccccccccaaaaaaccccccccaacaaaaaacccccccccaaaaaaaaaaaaacaaaccccaaccccccaaaaaaaaacaacccccccccccccccccaaaccaaaacccccccccccccccaa +abcccccccccccccccccaaaaaaaacccccccaaaaaaaaccccccaaaaaaaacaaaacaaaaaaacccccccccaaccccaaaaaacaaacccccccccccccccaaaakkkaaccccccccccccccccaa +abcccccccccccccccccaaaaaaaaccccccccaaaaaccccaacccaaaaaaaaaaaacaaaaaaccccccccccaacccaaaaaaaaaaaacccccccccccccccakkkkkklcccccccccccccccccc +abaaacccccccccccaaccccaaccccccccccccaaaaaccaaacccaaaaaaaaaaaaaaaaaaaaccccccaaaaaaaacaacccaaaaaaccccccccccccccckkkkkkkllcccccccaaaccccccc +abaaaacccccccaacaaccccaacccccccccccaaacaaaaaaaccccaaaaaaaaaaaaaaaaaaaacccccaaaaaaaaaaaccccaaaaacccccccccccccckkkksssllllccccccaaaaaacccc +abaaaacccccccaaaaacccccccccccaaaccccaacaaaaaaccccaaaaaacaaaaaaaaaaaaaacccccccaaaaccccccccaaaaacccccccccccccckkkksssssllllcccccaaaaaacccc +abaaacccccccccaaaaaaccccccccaaaaccccccccaaaaaaaacaaaaaaaaaaaaacaaacaaacccccccaaaaacccccccaaaaacccccccccccccjkkkrssssssllllccccccaaaccccc +abccccccccccaaaaaaaaccccccccaaaacccccccaaaaaaaaacaacaaaaaaaaaacaaaccccccccccaaacaaccccccccccccccccccccccccjjkkrrsuuussslllllcccccaaccccc +abccaaacccccaaaaacccccccccccaaaaccccccaaaaaaaaaacccccaaaaaaaaaacaaccccccccccaacccacccccccccccccccccccccjjjjjjrrrsuuuussslllllmcccddacccc +abcccaaaccaccacaaaccccccccccccccccccccaaaaaaaccccccccccaaaaaaaaccccccaacccccccccccaaaaacccccccccccccccjjjjjjrrrruuuuuusssllmmmmmddddcccc +abccaaaaaaaacccaaaccccccccccccccccaaacccccaaaccccccccccccaaacccccccccaacccccccccccaaaaacccccccccccccjjjjjrrrrrruuuxuuussqqqqmmmmmdddcccc +abcaaaaaaaacccaaaaaacaaaaaccccccaaaaaaccccaaacccaaccccccccaaccccccaaaaaaaaccaaacccaaaaaaccccccccccccjjjjrrrrrruuuxxxuuuqqqqqqqmmmdddcccc +abaaaaaaaaaccccaaaaacaaaaaccccccaaaaaaaaccccccaaaaaaccccccccccccccaaaaaaaaccaaacaaaaaaaacccccccccccjjjjrrrtttuuuuxxxyvvvvvqqqqmmmdddcccc +abaaaaaaaaaccaaaaaaacaaaaaaccccccaaaaaaaacccccaaaaaaccccccccccccccccaaaaccaaaaaaaaaaaaaacccccccccaaiijqqqrttttuuuxxyyvvvvvvvqqmmmdddcccc +abcaaaaaaaaccaaaaaaaaaaaaaacccccaaaaaaaacccccccaaaacccccaaaaccccccccaaaaacaaaaaaaaccaaccccccccccaaaiiiqqqttttxxxxxxyyyyyyvvvqqmmmdddcccc +abcccaaaaaaacaaaaaaaaaaaaaacccccaaaaaaaaaaaccccaaaaccccaaaaacccccccaaaaaacaaaaaaacccccccccccccccaaaiiiqqqtttxxxxxxxyyyyyyvvqqqmmmdddcccc +SbcccaacccaccccaaacacccaaacccccccccaaaaaaaaacccaccaccccaaaaaaccccccaaccaacccaaaaaccccccccccccccccaaiiiiqqtttxxxxEzzzyyyyvvvqqqmmmddccccc +abccaaaccccccccaaccccccccccccccccccaaaaaaaaccccccccccccaaaaaaccccccccccccccaaacaaaccaacccccccccccccciiiqqqttttxxxyyyyyvvvvqqqmmmdddccccc +abccccccccccccccccccccccccccccccccaaaaaaaccccccccccccccaaaaaacccccccccccccccaacccccaaaaaaaccccccccccciiiqqqttttxxyyyyyvvvrrrnnneeecccccc +abcaaaaccccccccccccccccccccccccccaaaaaaaaccccccccccccccccaacccccccccccccccccccccccccaaaaacccccccccccciiiqqqqttxxyyyyyyyvvrrnnnneeecccccc +abcaaaaacccccccccccccccccccccccccaaaacaaacccaccaaacccccccccccccccccccccccccaaaccccaaaaaaaccccccccccccciiiqqqttwwyywwyyywwrrnnneeeccccccc +abaaaaaacccaccaccccccccccccccccccaaaaccaacccaaaaaaccccccccccccccccaaaccccaaaaaacccaaaaaaaacccccccccccciiiqqqtswwwwwwwwwwwrrnnneeeccccccc +abaaaaaacccaaaaccccccccaaaacccccccaaacccccccaaaaaacccccccccccccccaaaaaaccaaaaaacccaaaaaaaacaaccccccaaciiiqppsswwwwsswwwwwrrrnneeeccccccc +abcaaaaacccaaaaacccccccaaaacccccccccccccccccaaaaaaaccccccccccccccaaaaaaccaaaaaacccccaaaaaaaaaccccccaaaahhpppssswwsssswwwwrrrnneeeacccccc +abcaaaccccaaaaaacccccccaaaaccccccccccccccccaaaaaaaaccccccccccccccaaaaacccaaaaaccccccaacaaaaaaaaccaaaaaahhpppsssssssssrrrrrrnnneeeacccccc +abccccccccaaaaaaccccccccaacccccccccccccccccaaaaaaaaccccaacccccccccaaaaaccaaaaacccccccccaaaaaaaaccaaaaachhpppssssssoosrrrrrrnnneeeaaacccc +abccccccccccaaccccccccccccccccaaaaaccccccaacccaaacccaaaaacccccccccaacaacccccccccccccccccaaaaaaacccaaaaahhhppppssppooooorroonnffeaaaacccc +abaaccccccccccccccccccccccccccaaaaaccccccaacccaaaccccaaaaacccccccccccccccccccccccccccaacaaaaacccccaacaahhhppppppppoooooooooonfffaaaacccc +abaccccccccccccccccccccccccccaaaaaacccaaaaaaaacccccccaaaaaccccccccccccccccccccccccaaaaaaaaaaaccccccccccchhhpppppppgggoooooooffffaacccccc +abaccccccccccccccccccccccccccaaaaaacccaaaaaaaaccccccaaaaaccccccacccaacccccccccccccaaaaaccccaaccccccccccchhhhhhggggggggfffffffffaaacccccc +abaacccccccccccccccccccccccccaaaaaacccccaaaacccccccccaaaacccaacaacaaacccccccccccccaaaaaaacccccccccccccccchhhhgggggggggffffffffccaacccccc +abcccccccaacccccccccccccccccccaaaccccccaaaaaccccccccaaaaccaaaacaaaaacccccccccccccaaaaaaaaccccccccccccccccchhhggggaaaagffffffcccccccccccc +abcccccccaacccccccccccccaacccccccccccccaaaaaaccaaccccaaaaaaaaacaaaaaacccccccaaaacaaaaaaaacccccccccccaacccccccaaaacaaaacccccccccccccccccc +abccccaaaaaaaacccccccaacaaaccccccccccccaaccaacaaaacccaaaaaaaacaaaaaaaaccccccaaaaccacaaaccaaaccccaaaaaacccccccaacccaaaacccccccccccccaaaaa +abccccaaaaaaaacccccccaaaaaccccccccccccccccccccaaaaccccaaaaaaacaaaaaaaaccccccaaaaccccaaaccaaaaaccaaaaaaaacccccccccccaaaccccccccccccccaaaa +abccccccaaaaccccccccccaaaaaaccccccccccccccccccaaaacccaaaaaaaaaaccaaccccccccccaacccccccccaaaaacccaaaaaaaacccccccccccaaaccccccccccccccaaaa +abcccccaaaaaacccccccaaaaaaaacccccccccccccccccccccccaaaaaaaaaaaaaaaacccccccccccccccccccccaaaaaacccaaaaaaaccccccccccccccccccccccccccaaaaaa diff --git a/day12/src/main.rs b/day12/src/main.rs index e7a11a9..564abc8 100644 --- a/day12/src/main.rs +++ b/day12/src/main.rs @@ -1,3 +1,178 @@ -fn main() { - println!("Hello, world!"); +use std::{collections::HashSet, fs::read_to_string}; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum Tile { + Start, + End, + Hight(u8), +} + +impl From for Tile { + fn from(input: char) -> Self { + match input { + 'S' => Self::Start, + 'E' => Self::End, + h => Self::Hight(('a'..='z').position(|c| c == h).unwrap() as u8), + } + } +} + +impl Tile { + fn can_move_to(self, other: Tile) -> bool { + if let Self::Hight(h1) = self { + if let Self::Hight(h2) = other { + return h1 + 1 >= h2; + } + } + if self == Self::Start { + return other == Self::Hight(0) || other == Self::Hight(1); + } + if other == Self::End { + return self == Self::Hight(('a'..='z').position(|c| c == 'z').unwrap() as u8); + } + false + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct Map { + map: Vec, + width: usize, + height: usize, +} + +impl From<&str> for Map { + fn from(input: &str) -> Self { + let width = input.lines().map(|line| line.len()).next().unwrap(); + let height = input.lines().count(); + let map = input + .lines() + .flat_map(|line| line.chars().map(Tile::from).collect::>()) + .collect::>(); + Self { map, width, height } + } +} + +impl Map { + fn at(&self, point: (usize, usize)) -> &T { + let (x, y) = point; + let index = x + y * self.width; + &self.map[index] + } + + fn at_mut(&mut self, point: (usize, usize)) -> &mut T { + let (x, y) = point; + let index = x + y * self.width; + &mut self.map[index] + } +} + +fn update( + from: (usize, usize), + to: (usize, usize), + path: &mut Map>, + map: &Map, + changed: &mut bool, +) { + if !map.at(from).can_move_to(*map.at(to)) { + return; + } + + let Some(c) = path.at(from) else {return}; + let cost = path.at(to); + let cost = cost.unwrap_or(u32::MAX); + if cost <= c + 1 { + return; + } + + *path.at_mut(to) = Some(c + 1); + *changed = true; +} + +fn find_shortest_path(map: &Map) -> Option { + let mut path = Map { + map: vec![None; map.width * map.height], + width: map.width, + height: map.height, + }; + let mut start = (0, 0); + let mut end = (0, 0); + for x in 0..map.width { + for y in 0..map.height { + match map.at((x, y)) { + Tile::Start => start = (x, y), + Tile::End => end = (x, y), + _ => (), + } + } + } + *path.at_mut(start) = Some(0); + + let mut changing = true; + while changing { + changing = false; + for x in 0..map.width { + for y in 0..map.height { + let point = (x, y); + if x != 0 { + update((x - 1, y), point, &mut path, map, &mut changing); + } + if y != 0 { + update((x, y - 1), point, &mut path, map, &mut changing); + } + if x != map.width - 1 { + update((x + 1, y), point, &mut path, map, &mut changing); + } + if y != map.height - 1 { + update((x, y + 1), point, &mut path, map, &mut changing); + } + } + } + } + *path.at(end) +} + +fn find_best_start(map: &Map) -> u32 { + let mut start = (0, 0); + let mut possible_starts = HashSet::new(); + for x in 0..map.width { + for y in 0..map.height { + match map.at((x, y)) { + Tile::Start => { + possible_starts.insert((x, y)); + start = (x, y); + } + Tile::Hight(0) => { + possible_starts.insert((x, y)); + } + _ => (), + } + } + } + let mut map = map.clone(); + *map.at_mut(start) = Tile::Hight(0); + + possible_starts + .iter() + .flat_map(|&start| { + let mut map = map.clone(); + *map.at_mut(start) = Tile::Start; + find_shortest_path(&map) + }) + .min() + .unwrap() +} + +fn main() { + let input = "Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi"; + let input = read_to_string("input.txt").unwrap_or_else(|_| input.to_owned()); + let map: Map<_> = (&*input).into(); + let cost = find_shortest_path(&map); + println!("{cost:?}"); + let cost = find_best_start(&map); + println!("{cost}"); }