Advent of Code solutions
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Day 4

Ben C 8a3ec5d4 f4cc148b

+196 -10
+2 -2
advent_core/src/day.rs
··· 110 110 _ => panic!("Invalid part number"), 111 111 }; 112 112 println!( 113 - "Day {} Part {}: {} ({:?}ms)", 113 + "Day {} Part {}: {} ({:?})", 114 114 Self::DAY, 115 115 part, 116 116 solution.as_ref().unwrap_or(&"Not implemented".to_string()), ··· 158 158 _ => panic!("Invalid part number"), 159 159 }; 160 160 println!( 161 - "{extra_indent} Part {}: {} ({:?}ms)", 161 + "{extra_indent} Part {}: {} ({:?})", 162 162 part, 163 163 solution.as_ref().unwrap_or(&"Not implemented".to_string()), 164 164 part_time.elapsed()
+19
utils/src/dir.rs
··· 1 + use std::ops::Range; 2 + 1 3 /// Module containing utilities related to direction and movement. 2 4 use crate::pos::Position; 3 5 ··· 36 38 /// 37 39 pub trait Movement: std::fmt::Debug + Copy + Clone + PartialEq + std::hash::Hash { 38 40 fn get_kernel(&self) -> Position; 41 + 42 + /// Repeat the given movement across the range `range`. 43 + fn repeat(&self, range: Range<isize>) -> impl Iterator<Item = Position> { 44 + let k = self.get_kernel(); 45 + range.map(move |i| k.multiply_comp(i)) 46 + } 39 47 } 40 48 41 49 /// The four cardinal directions. ··· 144 152 } 145 153 } 146 154 } 155 + 156 + pub const ALL_8: [Position; 8] = [ 157 + Position::new(0, -1), 158 + Position::new(0, 1), 159 + Position::new(1, 0), 160 + Position::new(-1, 0), 161 + Position::new(1, 1), 162 + Position::new(1, -1), 163 + Position::new(-1, 1), 164 + Position::new(-1, -1), 165 + ];
+61
utils/src/grid.rs
··· 3 3 pos::Position, 4 4 }; 5 5 6 + #[derive(Clone)] 6 7 /// A 2D integer grid of values. 7 8 /// 8 9 /// This grid is represented by a vector of vectors. ··· 396 397 ) -> impl Iterator<Item = (M, Position, &'a T)> + 'a { 397 398 pos.relatives(kernels) 398 399 .filter_map(move |(pos, dir)| self.get(pos).map(|v| (dir, pos, v))) 400 + } 401 + 402 + /// Get all positions relative to the given position, returning [None] if the relatives would 403 + /// go out of bounds 404 + /// 405 + /// # Examples 406 + /// 407 + /// ``` 408 + /// use utils::prelude::*; 409 + /// 410 + /// let data = vec![ 411 + /// vec![1, 2, 3], 412 + /// vec![4, 5, 6], 413 + /// vec![7, 8, 9], 414 + /// ]; 415 + /// 416 + /// let grid = Grid::new(data); 417 + /// 418 + /// let pos = Position::new(1, 1); 419 + /// let kernels = &[ 420 + /// Direction::North, 421 + /// Direction::East, 422 + /// ]; 423 + /// 424 + /// let mut relatives = grid.relatives_strict(pos, kernels); 425 + /// if let Some(relatives) = relatives { 426 + /// assert_eq!(relatives.get(0), Some((Direction::North, Position::new(1, 0), &2)).as_ref()); 427 + /// assert_eq!(relatives.get(1), Some((Direction::East, Position::new(2, 1), &6)).as_ref()); 428 + /// } else { panic!("Relatives should be Some!") } 429 + /// ``` 430 + /// 431 + /// ``` 432 + /// use utils::prelude::*; 433 + /// 434 + /// let data = vec![ 435 + /// vec![1, 2, 3], 436 + /// vec![4, 5, 6], 437 + /// vec![7, 8, 9], 438 + /// ]; 439 + /// 440 + /// let grid = Grid::new(data); 441 + /// 442 + /// let pos = Position::new(1, 0); 443 + /// let kernels = &[ 444 + /// Direction::North, // This will result in [None], as (1, -1) is out of bounds 445 + /// Direction::East, 446 + /// ]; 447 + /// 448 + /// let mut relatives = grid.relatives_strict(pos, kernels); 449 + /// 450 + /// assert!(relatives.is_none()); 451 + /// ``` 452 + pub fn relatives_strict<M: Movement>( 453 + &self, 454 + pos: Position, 455 + kernels: &[M], 456 + ) -> Option<Vec<(M, Position, &T)>> { 457 + pos.relatives(kernels) 458 + .map(move |(pos, dir)| self.get(pos).map(|v| (dir, pos, v))) 459 + .collect::<Option<Vec<_>>>() 399 460 } 400 461 401 462 /// Get all positions relative to the given position in the grid based off the given kernels.
+33 -1
utils/src/pos.rs
··· 20 20 pub y: CompType, 21 21 } 22 22 23 + #[macro_export] 24 + macro_rules! mpos { 25 + ($x:expr, $y:expr) => { 26 + $crate::pos::Position::new($x, $y) 27 + }; 28 + } 29 + 30 + #[macro_export] 31 + macro_rules! kern { 32 + 33 + (@builtin N) => { $crate::dir::ALL_8[0] }; 34 + (@builtin S) => { $crate::dir::ALL_8[1] }; 35 + (@builtin E) => { $crate::dir::ALL_8[2] }; 36 + (@builtin W) => { $crate::dir::ALL_8[3] }; 37 + (@builtin SE) => { $crate::dir::ALL_8[4] }; 38 + (@builtin NE) => { $crate::dir::ALL_8[5] }; 39 + (@builtin SW) => { $crate::dir::ALL_8[6] }; 40 + (@builtin NW) => { $crate::dir::ALL_8[7] }; 41 + 42 + (@builtin ($x:expr, $y: expr)) => { $crate::pos::pos!($x, $y) }; 43 + 44 + [$($s:tt),*] => { 45 + [$(kern!(@builtin $s),)*] 46 + }; 47 + } 48 + 23 49 impl Position { 24 50 /// Create a new position 25 - pub fn new(x: CompType, y: CompType) -> Self { 51 + pub const fn new(x: CompType, y: CompType) -> Self { 26 52 Self { x, y } 27 53 } 28 54 ··· 770 796 dir.get_kernel() 771 797 } 772 798 } 799 + 800 + impl Movement for Position { 801 + fn get_kernel(&self) -> Position { 802 + *self 803 + } 804 + }
+61 -7
years/2024/src/day_4.rs
··· 1 + use advent_core::{day_stuff, ex_for_day, Day}; 2 + use utils::{ 3 + dir::{Movement, ALL_8}, 4 + grid::Grid, 5 + kern, 6 + pos::Position, 7 + }; 8 + 9 + pub struct Day4; 1 10 2 - use advent_core::{Day, day_stuff, ex_for_day}; 11 + const SEARCH: &str = "XMAS"; 3 12 4 - pub struct Day4; 13 + const PART_2_FORWARD_DIAG: [Position; 2] = kern![NE, SW]; 14 + const PART_2_BACKWARD_DIAG: [Position; 2] = kern![NW, SE]; 15 + 16 + fn check_diag_good(grid: &Grid<char>, pos: Position, kerns: &[impl Movement]) -> bool { 17 + grid.relatives_strict(pos, kerns).is_some_and(|relatives| { 18 + let (_, _, x) = relatives[0]; 19 + let (_, _, y) = relatives[1]; 20 + (*x == 'S' || *x == 'M') && (*y == 'S' || *y == 'M') && (*x != *y) 21 + }) 22 + } 5 23 6 24 impl Day for Day4 { 25 + day_stuff!(4, "18", "9", Grid::<char>); 7 26 8 - day_stuff!(4, "", ""); 27 + fn part_1(input: Self::Input) -> Option<String> { 28 + let ans = input 29 + .iter() 30 + .map(|(pos, c)| { 31 + if SEARCH.starts_with(*c) { 32 + ALL_8 33 + .iter() 34 + .filter(|dir| { 35 + let kerns = dir.repeat(1..(SEARCH.len() as isize)).collect::<Vec<_>>(); 9 36 10 - fn part_1(_input: Self::Input) -> Option<String> { 11 - None 37 + input 38 + .relatives_strict(pos, &kerns) 39 + .is_some_and(|relatives| { 40 + relatives 41 + .into_iter() 42 + .map(|(_, _, c)| *c) 43 + .zip(SEARCH[1..].chars()) 44 + .all(|(l, r)| l == r) 45 + }) 46 + }) 47 + .count() 48 + } else { 49 + 0 50 + } 51 + }) 52 + .sum::<usize>(); 53 + Some(ans.to_string()) 12 54 } 13 55 14 - fn part_2(_input: Self::Input) -> Option<String> { 15 - None 56 + fn part_2(input: Self::Input) -> Option<String> { 57 + let ans = input 58 + .iter() 59 + .filter(|(pos, c)| { 60 + **c == 'A' 61 + && check_diag_good(&input, *pos, &PART_2_FORWARD_DIAG) 62 + && check_diag_good(&input, *pos, &PART_2_BACKWARD_DIAG) 63 + }) 64 + .count(); 65 + Some(ans.to_string()) 66 + } 67 + 68 + fn parse_input(input: &str) -> Self::Input { 69 + Grid::parse(input) 16 70 } 17 71 }
+10
years/2024/src/examples/day_4/1.txt
··· 1 + MMMSXXMASM 2 + MSAMXMSMSA 3 + AMXSXMAAMM 4 + MSAMASMSMX 5 + XMASAMXAMM 6 + XXAMMXXAMA 7 + SMSMSASXSS 8 + SAXAMASAAA 9 + MAMMMXMMMM 10 + MXMXAXMASX
+10
years/2024/src/examples/day_4/2.txt
··· 1 + MMMSXXMASM 2 + MSAMXMSMSA 3 + AMXSXMAAMM 4 + MSAMASMSMX 5 + XMASAMXAMM 6 + XXAMMXXAMA 7 + SMSMSASXSS 8 + SAXAMASAAA 9 + MAMMMXMMMM 10 + MXMXAXMASX
years/Cargo.toml

This is a binary file and will not be displayed.