diff --git a/days/2024/20.rs b/days/2024/20.rs new file mode 100644 index 0000000..f84e468 --- /dev/null +++ b/days/2024/20.rs @@ -0,0 +1,109 @@ +use std::{collections::HashMap, hash::Hash, vec}; + +use advent_of_code::{ + find_character, + strings::{convert_to_array, line_to_char}, + IntMul, Kartesian, Map, KD, +}; +use advent_of_code_macros::include_aoc; + +include_aoc!(DATA, 2024, 20); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +struct Progress { + step: u32, + pos: Kartesian, +} + +fn get_uncheated_course(map: &Map) -> Vec { + let mut course = Vec::new(); + let mut position = Progress { + pos: find_character(&map, 'S'), + step: 0, + }; + course.push(position); + let mut lastdir = KD::Top; + let mut dir; + 'raceloop: loop { + dir = lastdir; + loop { + let newpos = position.pos.move_dir(dir.vector(), dir).unwrap(); + if course.iter().filter(|x| x.pos == newpos).count() != 0 { + dir = dir.clockwise(false); + continue; + } + let dest = map.get(newpos).unwrap(); + match dest { + '.' | 'E' => { + position = Progress { + pos: newpos, + step: position.step + 1, + }; + course.push(position); + lastdir = dir; + if dest == '.' { + break; + } else { + break 'raceloop; + } + }, + _ => dir = dir.clockwise(false), + } + } + } + course +} + +fn cheat(map: &Map, course: &Vec, length: usize) -> Vec<(Kartesian, Kartesian)> { + let mut cheats = Vec::new(); + for i in 0..course.len() { + let start = course[i]; + loop { + + } + } + cheats +} + +fn main() { + let map = Map::from(convert_to_array::<_, _, '\n'>(DATA, line_to_char)); + let course = get_uncheated_course(&map); + print!("{}", map); + println!("The uncheated course needs {} Picoseconds", course.last().unwrap().step); + let mut cheats = Vec::new(); + for i in 0..course.len() - 1 { + let current = course[i]; + for dir in KD::iter(false, false, true) { + let wall = current.pos.move_dir(dir.vector(), dir).unwrap(); + if map.get(wall) != Some('#') { + continue; + } + let vector = dir.vector().mul(2_usize); + let newpos = match current.pos.move_dir_max(vector, dir, map.size()) { + None => continue, + Some(x) => x, + }; + if map.get(newpos) != Some('#') { + let possible_cheat = course.iter().filter(|x| x.pos == newpos).next().unwrap(); + if possible_cheat.step > current.step { + cheats.push((possible_cheat.step - current.step - 2, wall)); + } + } + } + } + let mut counter = HashMap::new(); + for cheat in cheats.clone() { + if !counter.contains_key(&cheat.0) { + counter.insert(cheat.0, 0_u32); + } + *counter.get_mut(&cheat.0).unwrap() += 1_u32; + } + let mut cs: Vec<_> = counter.iter().collect(); + cs.sort(); + println!("Found {} cheats that save more than 100 picoseconds", cs.iter().filter(|x| *x.0 >= 100).map(|x| *x.1).sum::()); +} + +#[cfg(test)] +mod test { + use super::*; +}