refactor: day-04

This commit is contained in:
Kristofers Solo 2024-12-04 10:31:35 +02:00
parent 2e1cd400da
commit c28bd8a08a
7 changed files with 139 additions and 123 deletions

View File

@ -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

4
2024/day-04/bench.txt Normal file
View File

@ -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

36
2024/day-04/src/grid.rs Normal file
View File

@ -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<Vec<char>>);
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<Self, Self::Err> {
let data = s
.lines()
.filter(|line| !line.is_empty())
.map(|line| line.chars().collect::<Vec<_>>())
.collect::<Vec<_>>();
Ok(Grid(data))
}
}

View File

@ -1,2 +1,4 @@
mod grid;
pub mod part1;
pub mod part2;
mod vec;

View File

@ -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<Vec<char>>,
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<Self, Self::Err> {
let data = s
.lines()
.map(|line| line.chars().collect::<Vec<_>>())
.collect::<Vec<_>>();
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<usize> {
let grid = Grid::from_str(input)?;

View File

@ -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<Vec<char>>,
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<Self, Self::Err> {
let data = s
.lines()
.filter(|line| !line.is_empty())
.map(|line| line.chars().collect::<Vec<_>>())
.collect::<Vec<_>>();
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<usize> {
let grid = Grid::from_str(input)?;

24
2024/day-04/src/vec.rs Normal file
View File

@ -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)
}
}