diff --git a/2024/benchmarks.txt b/2024/benchmarks.txt index c09b51e..6f21035 100644 --- a/2024/benchmarks.txt +++ b/2024/benchmarks.txt @@ -14,8 +14,8 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s day_01_bench fastest │ slowest │ median │ mean │ samples │ iters -├─ part1 52.85 µs │ 149.3 µs │ 53.19 µs │ 65.21 µs │ 100 │ 100 -╰─ part2 154.8 µs │ 507.2 µs │ 157.5 µs │ 199.9 µs │ 100 │ 100 +├─ part1 54.79 µs │ 195.1 µs │ 56.06 µs │ 70.49 µs │ 100 │ 100 +╰─ part2 156.2 µs │ 202.6 µs │ 157.3 µs │ 160.7 µs │ 100 │ 100 running 2 tests @@ -33,8 +33,8 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s day_02_bench fastest │ slowest │ median │ mean │ samples │ iters -├─ part1 82.71 µs │ 142.8 µs │ 92.24 µs │ 97 µs │ 100 │ 100 -╰─ part2 128.9 µs │ 170.9 µs │ 131.4 µs │ 133.2 µs │ 100 │ 100 +├─ part1 81.18 µs │ 325.1 µs │ 83.12 µs │ 122.7 µs │ 100 │ 100 +╰─ part2 130.1 µs │ 172.9 µs │ 131.2 µs │ 134.1 µs │ 100 │ 100 running 2 tests @@ -52,6 +52,25 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s day_03_bench fastest │ slowest │ median │ mean │ samples │ iters -├─ part1 253 µs │ 1.206 ms │ 289.4 µs │ 350.7 µs │ 100 │ 100 -╰─ part2 363.5 µs │ 1.285 ms │ 411.9 µs │ 508.2 µs │ 100 │ 100 +├─ part1 253.9 µs │ 796.2 µs │ 279.8 µs │ 305.1 µs │ 100 │ 100 +╰─ part2 363.1 µs │ 1.209 ms │ 417.6 µs │ 536.8 µs │ 100 │ 100 + + +running 2 tests +ii +test result: ok. 0 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +day_04_bench fastest │ slowest │ median │ mean │ samples │ iters +├─ part1 598 µs │ 2.157 ms │ 611 µs │ 800.4 µs │ 100 │ 100 +╰─ part2 632.9 µs │ 886 µs │ 640.8 µs │ 646.7 µs │ 100 │ 100 diff --git a/2024/day-04/bench.txt b/2024/day-04/bench.txt new file mode 100644 index 0000000..6724e7f --- /dev/null +++ b/2024/day-04/bench.txt @@ -0,0 +1,4 @@ +day_04_bench fastest │ slowest │ median │ mean │ samples │ iters +├─ part1 599.5 µs │ 2.275 ms │ 605.1 µs │ 770.3 µs │ 100 │ 100 +╰─ part2 648.7 µs │ 674.5 µs │ 657.9 µs │ 658.7 µs │ 100 │ 100 + diff --git a/2024/day-04/src/grid.rs b/2024/day-04/src/grid.rs new file mode 100644 index 0000000..7d2463e --- /dev/null +++ b/2024/day-04/src/grid.rs @@ -0,0 +1,36 @@ +use crate::vec::Vec2; +use miette::Diagnostic; +use std::str::FromStr; +use thiserror::Error; + +#[derive(Debug, Error, Diagnostic)] +pub(crate) enum GridError {} + +#[derive(Debug)] +pub(crate) struct Grid(pub(crate) Vec>); + +impl Grid { + pub(crate) fn is_valid_position(&self, pos: &Vec2) -> bool { + pos.x >= 0 && pos.x < self.cols() as i32 && pos.y >= 0 && pos.y < self.rows() as i32 + } + + pub(crate) fn rows(&self) -> usize { + self.0.len() + } + pub(crate) fn cols(&self) -> usize { + self.0[0].len() + } +} + +impl FromStr for Grid { + type Err = GridError; + fn from_str(s: &str) -> std::result::Result { + let data = s + .lines() + .filter(|line| !line.is_empty()) + .map(|line| line.chars().collect::>()) + .collect::>(); + + Ok(Grid(data)) + } +} diff --git a/2024/day-04/src/lib.rs b/2024/day-04/src/lib.rs index faaf542..60c5999 100644 --- a/2024/day-04/src/lib.rs +++ b/2024/day-04/src/lib.rs @@ -1,2 +1,4 @@ +mod grid; pub mod part1; pub mod part2; +mod vec; diff --git a/2024/day-04/src/part1.rs b/2024/day-04/src/part1.rs index f83ac7e..39a4511 100644 --- a/2024/day-04/src/part1.rs +++ b/2024/day-04/src/part1.rs @@ -1,6 +1,7 @@ -use miette::{Diagnostic, Result}; +use miette::Result; use std::str::FromStr; -use thiserror::Error; + +use crate::{grid::Grid, vec::Vec2}; enum Direction { Right, // (1, 0) @@ -14,16 +15,16 @@ enum Direction { } impl Direction { - const fn get_vector(&self) -> (i32, i32) { + const fn get_vector(&self) -> Vec2 { match self { - Direction::Right => (1, 0), - Direction::Left => (-1, 0), - Direction::Up => (0, -1), - Direction::Down => (0, 1), - Direction::UpRight => (1, -1), - Direction::UpLeft => (-1, -1), - Direction::DownRight => (1, 1), - Direction::DownLeft => (-1, 1), + Direction::Right => Vec2::new(1, 0), + Direction::Left => Vec2::new(-1, 0), + Direction::Up => Vec2::new(0, -1), + Direction::Down => Vec2::new(0, 1), + Direction::UpRight => Vec2::new(1, -1), + Direction::UpLeft => Vec2::new(-1, -1), + Direction::DownRight => Vec2::new(1, 1), + Direction::DownLeft => Vec2::new(-1, 1), } } @@ -41,42 +42,30 @@ impl Direction { } } -#[derive(Debug, Error, Diagnostic)] -enum GridError { - #[error("Error parsing")] - ParseError, +trait Part1 { + fn check_direction(&self, pos: Vec2, direction: &Direction, word: &str) -> bool; + fn count_word(&self, word: &str) -> usize; } -#[derive(Debug)] -struct Grid { - data: Vec>, - rows: usize, - cols: usize, -} - -impl Grid { - fn check_direction(&self, row: i32, col: i32, direction: &Direction, word: &str) -> bool { - let (dx, dy) = direction.get_vector(); +impl Part1 for Grid { + fn check_direction(&self, pos: Vec2, direction: &Direction, word: &str) -> bool { + let dir_vec = direction.get_vector(); word.chars().enumerate().all(|(idx, char)| { - let new_row = row + dy * idx as i32; - let new_col = col + dx * idx as i32; - self.is_valid_position(new_row, new_col) - && self.data[new_row as usize][new_col as usize] == char + let new_pos = pos + dir_vec.scale(idx as i32); + self.is_valid_position(&new_pos) + && self.0[new_pos.y as usize][new_pos.x as usize] == char }) } - fn is_valid_position(&self, row: i32, col: i32) -> bool { - row >= 0 && row < self.rows as i32 && col >= 0 && col < self.cols as i32 - } - fn count_word(&self, word: &str) -> usize { - (0..self.rows) + (0..self.rows()) .flat_map(|row| { - (0..self.cols).flat_map(move |col| { + (0..self.cols()).flat_map(move |col| { Direction::all_directions() .into_iter() .filter(move |direction| { - self.check_direction(row as i32, col as i32, direction, word) + let pos = Vec2::new(col as i32, row as i32); + self.check_direction(pos, direction, word) }) }) }) @@ -84,28 +73,6 @@ impl Grid { } } -impl FromStr for Grid { - type Err = GridError; - fn from_str(s: &str) -> std::result::Result { - let data = s - .lines() - .map(|line| line.chars().collect::>()) - .collect::>(); - - let rows = data.len(); - if rows == 0 { - return Err(GridError::ParseError); - } - let cols = data[0].len(); - - if data.iter().any(|row| row.len() != cols) { - return Err(GridError::ParseError); - } - - Ok(Grid { data, rows, cols }) - } -} - #[tracing::instrument] pub fn process(input: &str) -> Result { let grid = Grid::from_str(input)?; diff --git a/2024/day-04/src/part2.rs b/2024/day-04/src/part2.rs index 1ea4c03..e85b828 100644 --- a/2024/day-04/src/part2.rs +++ b/2024/day-04/src/part2.rs @@ -1,7 +1,7 @@ +use crate::{grid::Grid, vec::Vec2}; use itertools::Itertools; -use miette::{Diagnostic, Result}; +use miette::Result; use std::str::FromStr; -use thiserror::Error; #[derive(Debug, Clone, Copy)] enum Direction { @@ -12,12 +12,12 @@ enum Direction { } impl Direction { - const fn get_vector(&self) -> (i32, i32) { + const fn get_vector(&self) -> Vec2 { match self { - Direction::UpRight => (1, -1), - Direction::UpLeft => (-1, -1), - Direction::DownRight => (1, 1), - Direction::DownLeft => (-1, 1), + Direction::UpRight => Vec2::new(1, -1), + Direction::UpLeft => Vec2::new(-1, -1), + Direction::DownRight => Vec2::new(1, 1), + Direction::DownLeft => Vec2::new(-1, 1), } } @@ -29,46 +29,33 @@ impl Direction { } } -#[derive(Debug, Error, Diagnostic)] -enum GridError { - #[error("Error parsing")] - ParseError, +trait Part2 { + fn check_direction(&self, pos: Vec2, direction: &Direction, word: &str) -> bool; + fn count_word(&self, word: &str) -> usize; } -#[derive(Debug)] -struct Grid { - data: Vec>, - rows: usize, - cols: usize, -} - -impl Grid { - fn check_direction(&self, row: i32, col: i32, direction: &Direction, word: &str) -> bool { - let (dx, dy) = direction.get_vector(); - let start_row = row - dy; - let start_col = col - dx; +impl Part2 for Grid { + fn check_direction(&self, pos: Vec2, direction: &Direction, word: &str) -> bool { + let dir_vec = direction.get_vector(); + let start_pos = pos + dir_vec.scale(-1); // Move back one position word.chars().enumerate().all(|(idx, char)| { - let new_row = start_row + dy * idx as i32; - let new_col = start_col + dx * idx as i32; - self.is_valid_position(new_row, new_col) - && self.data[new_row as usize][new_col as usize] == char + let new_pos = start_pos + dir_vec.scale(idx as i32); + self.is_valid_position(&new_pos) + && self.0[new_pos.y as usize][new_pos.x as usize] == char }) } - fn is_valid_position(&self, row: i32, col: i32) -> bool { - row >= 0 && row < self.rows as i32 && col >= 0 && col < self.cols as i32 - } - fn count_word(&self, word: &str) -> usize { - (0..self.rows) + (0..self.rows()) .flat_map(|row| { - (0..self.cols).filter(move |&col| { - if self.data[row][col] != 'A' { + (0..self.cols()).filter(move |&col| { + let pos = Vec2::new(col as i32, row as i32); + if self.0[row][col] != 'A' { return false; } Direction::pairs().any(|(dir1, dir2)| { - self.check_direction(row as i32, col as i32, &dir1, word) - && self.check_direction(row as i32, col as i32, &dir2, word) + self.check_direction(pos, &dir1, word) + && self.check_direction(pos, &dir2, word) }) }) }) @@ -76,29 +63,6 @@ impl Grid { } } -impl FromStr for Grid { - type Err = GridError; - fn from_str(s: &str) -> std::result::Result { - let data = s - .lines() - .filter(|line| !line.is_empty()) - .map(|line| line.chars().collect::>()) - .collect::>(); - - let rows = data.len(); - if rows == 0 { - return Err(GridError::ParseError); - } - let cols = data[0].len(); - - if data.iter().any(|row| row.len() != cols) { - return Err(GridError::ParseError); - } - - Ok(Grid { data, rows, cols }) - } -} - #[tracing::instrument] pub fn process(input: &str) -> Result { let grid = Grid::from_str(input)?; diff --git a/2024/day-04/src/vec.rs b/2024/day-04/src/vec.rs new file mode 100644 index 0000000..bb08da2 --- /dev/null +++ b/2024/day-04/src/vec.rs @@ -0,0 +1,24 @@ +use std::ops::Add; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct Vec2 { + pub(crate) x: i32, + pub(crate) y: i32, +} + +impl Vec2 { + pub(crate) const fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + pub(crate) fn scale(&self, factor: i32) -> Self { + Self::new(self.x * factor, self.y * factor) + } +} + +impl Add for Vec2 { + type Output = Vec2; + fn add(self, rhs: Self) -> Self::Output { + Vec2::new(self.x + rhs.x, self.y + rhs.y) + } +}