use advent_of_code::{ strings::{char_to_num, convert_to_array}, Kartesian, KartesianDirection, MaximumFromMap, }; use advent_of_code_macros::include_aoc; include_aoc!(2024, 10); type Trail = Vec>; type Map = Vec>; fn get_height(line: &str) -> Vec { let mut numbers = Vec::new(); for c in line.chars() { numbers.push(match c { '.' => 11, c => char_to_num(c), }); } numbers } fn follow_trail(position: Kartesian, number: u32, current: Trail, trails: &mut Vec, map: &Map) { let max = Kartesian::maximum(map); let mut new; #[cfg(debug_assertions)] if map[position.x as usize][position.y as usize] != number { panic!("Positition is not correct") } let mut newposition; let mut found = false; for dir in KartesianDirection::iter(false, false, true) { newposition = match position.move_dir(dir.vector_abs(), dir) { None => continue, Some(pos) => { if pos.x >= max.x || pos.y >= max.y { continue; } pos }, }; if map[newposition.x as usize][newposition.y as usize] == number + 1 { found = true; new = current.clone(); new.push(newposition); follow_trail(newposition, number + 1, new, trails, map); } } if !found { trails.push(current); } } fn find_trails(map: &Map) -> Vec> { let mut trails = Vec::new(); for (x, line) in map.iter().enumerate() { for (y, column) in line.iter().cloned().enumerate() { if column == 0 { let trailhead = Kartesian::new(x as u32, y as u32); let mut traillist = Vec::::new(); follow_trail(trailhead, 0, vec![trailhead], &mut traillist, map); trails.push(traillist); } } } trails } fn score_trail(trails: &Vec) -> u32 { let mut highest_points = Vec::new(); let mut last; for trail in trails { last = trail.last().unwrap().clone(); if trail.len() == 10 && !highest_points.contains(&last) { highest_points.push(last); } } highest_points.len() as u32 } fn main() { let map = convert_to_array::<_, _, '\n'>(DATA, get_height); let trails = find_trails(&map); let mut score = 0; let mut rating = 0; for traillist in trails { score += score_trail(&traillist); rating += traillist.iter().filter(|x| x.len() == 10).count(); } println!("Total Score of Map: {}", score); println!("Total Rating of Map: {}", rating); } #[cfg(test)] mod test { use super::*; include_aoc!(MAP, 2024, 10, true); const SCORE: u32 = 36; #[test] fn test_simple() { let mut score = 0; for trails in find_trails(&convert_to_array::<_, _, '\n'>(MAP, get_height)).values().cloned() { for trail in trails.clone() { for (i, point) in trail.iter().enumerate() { print!("{}", point); if i != trail.len() - 1 { print!(" -> ") } } println!(); } score += score_trail(trails); } assert!(score == SCORE, "Score of the map did not match the expected value: {} == {}\n{}", score, SCORE, MAP); } }