diff --git a/crates/day03/src/main.rs b/crates/day03/src/main.rs index 7deffbd..3d40df1 100644 --- a/crates/day03/src/main.rs +++ b/crates/day03/src/main.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - #[cfg(not(feature = "regex"))] use std::{iter::Peekable, str::Chars}; @@ -7,26 +5,12 @@ use helpers::read_file; #[cfg(feature = "regex")] use regex::Regex; -#[derive(Debug, Eq, PartialEq)] -pub struct Problem { - program: String, -} - -impl FromStr for Problem { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(Self { program: s.into() }) - } -} - #[cfg(not(feature = "regex"))] /// Parses and counts the product of numbers within a "mul(a, b)" format. /// # Errors /// Returns an error if input parsing fails. pub fn count_mul(p: &str) -> Result> { - let program: Problem = p.parse()?; - let mut parser = ProgramParser::new(&program.program); + let mut parser = ProgramParser::new(p); Ok(parser.parse()) } @@ -87,11 +71,11 @@ impl<'a> ProgramParser<'a> { fn parse_mul(&mut self) -> bool { if self.iterator.peek() == Some(&'m') { - let _ = self.iterator.next(); + self.iterator.next(); if self.iterator.peek() == Some(&'u') { - let _ = self.iterator.next(); + self.iterator.next(); if self.iterator.peek() == Some(&'l') { - let _ = self.iterator.next(); + self.iterator.next(); return true; } @@ -109,7 +93,7 @@ impl<'a> ProgramParser<'a> { if c.is_ascii_digit() { digits.push(*c); - let _ = self.iterator.next(); + self.iterator.next(); continue; } diff --git a/crates/day04/src/main.rs b/crates/day04/src/main.rs index b7e50c0..876e57f 100644 --- a/crates/day04/src/main.rs +++ b/crates/day04/src/main.rs @@ -5,15 +5,19 @@ use std::{ use helpers::floored_division; +struct Grid { + grid: Vec>, +} + fn main() { let message = read_file("crates/day04/input.txt").unwrap(); // --- Part One --- - let mut count = count_word(&message, "XMAS"); + let grid = Grid::new(message); + let mut count = grid.count_word("XMAS"); println!("Part One solution: {count}"); - // --- Part Two --- - count = count_x_pattern(&message, "MAS").unwrap(); - println!("Part Two solution: {count}"); + count = grid.count_x_pattern("XMAS").unwrap(); + println!("Part One solution: {count}"); } fn read_file(input: &str) -> Result>, Box> { @@ -28,118 +32,127 @@ fn read_file(input: &str) -> Result>, Box> Ok(vec_of_vecs) } -fn count_x_pattern(grid: &[Vec], word: &str) -> Result { - let rows = grid.len(); - let cols = if rows > 0 { - grid[0].len() - } else { - return Err("Grid must be a valid grid".to_string()); - }; - let word_len = word.len(); - let mut count = 0; - - let bounded: usize = floored_division(word_len.try_into().unwrap(), 2) - .try_into() - .unwrap(); - let middle_char = word.chars().nth(bounded).unwrap(); - - let reverse = word.chars().rev().collect::(); - - for r in bounded..(rows - bounded) { - for c in bounded..(cols - bounded) { - if grid[r][c] == middle_char { - let mut first_diagonal = false; - let mut second_diagonal = false; - - // Check forward diagonal \ - if (0..word_len) - .all(|i| grid[r - bounded + i][c - bounded + i] == word.chars().nth(i).unwrap()) - { - first_diagonal = true; - } - // Check backward diagonal \ - if (0..word_len).all(|i| { - grid[r - bounded + i][c - bounded + i] == reverse.chars().nth(i).unwrap() - }) { - first_diagonal = true; - } +impl Grid { + const fn new(new_grid: Vec>) -> Self { + Self { grid: new_grid } + } - if first_diagonal { - // Check forward diagonal / + fn count_x_pattern(&self, word: &str) -> Result { + let rows = self.grid.len(); + let cols = if rows > 0 { + self.grid[0].len() + } else { + return Err("Grid must be a valid grid".to_string()); + }; + let word_len = word.len(); + let mut count = 0; + + let bounded: usize = floored_division(word_len.try_into().unwrap(), 2) + .try_into() + .unwrap(); + let middle_char = word.chars().nth(bounded).unwrap(); + + let reverse = word.chars().rev().collect::(); + + for r in bounded..(rows - bounded) { + for c in bounded..(cols - bounded) { + if self.grid[r][c] == middle_char { + let mut first_diagonal = false; + let mut second_diagonal = false; + + // Check forward diagonal \ if (0..word_len).all(|i| { - grid[r + bounded - i][c - bounded + i] == word.chars().nth(i).unwrap() + self.grid[r - bounded + i][c - bounded + i] == word.chars().nth(i).unwrap() }) { - second_diagonal = true; + first_diagonal = true; } - // Check backward diagonal / + // Check backward diagonal \ if (0..word_len).all(|i| { - grid[r + bounded - i][c - bounded + i] == reverse.chars().nth(i).unwrap() + self.grid[r - bounded + i][c - bounded + i] + == reverse.chars().nth(i).unwrap() }) { - second_diagonal = true; + first_diagonal = true; } - if second_diagonal { - count += 1; + if first_diagonal { + // Check forward diagonal / + if (0..word_len).all(|i| { + self.grid[r + bounded - i][c - bounded + i] + == word.chars().nth(i).unwrap() + }) { + second_diagonal = true; + } + // Check backward diagonal / + if (0..word_len).all(|i| { + self.grid[r + bounded - i][c - bounded + i] + == reverse.chars().nth(i).unwrap() + }) { + second_diagonal = true; + } + + if second_diagonal { + count += 1; + } } } } } - } - Ok(count) -} + Ok(count) + } -fn count_word(grid: &[Vec], word: &str) -> usize { - let word_chars: Vec = word.chars().collect(); - let word_len = word_chars.len(); - let rows = grid.len(); - let cols = grid[0].len(); - let mut count = 0; - - let directions = vec![ - (0, 1), // Horizontal right - (0, -1), // Horizontal left - (1, 0), // Vertical down - (-1, 0), // Vertical up - (1, 1), // Diagonal down-right - (1, -1), // Diagonal down-left - (-1, 1), // Diagonal up-right - (-1, -1), // Diagonal up-left - ]; - - for row in 0..rows { - for col in 0..cols { - for (dx, dy) in &directions { - let mut found = true; - - for (i, _) in word_chars.iter().enumerate().take(word_len) { - let x = isize::try_from(row).unwrap() + isize::try_from(i).unwrap() * dx; - let y = isize::try_from(col).unwrap() + isize::try_from(i).unwrap() * dy; - - if x < 0 - || y < 0 - || x >= rows.try_into().unwrap() - || y >= cols.try_into().unwrap() - { - found = false; - break; + fn count_word(&self, word: &str) -> usize { + let word_chars: Vec = word.chars().collect(); + let word_len = word_chars.len(); + let rows = self.grid.len(); + let cols = self.grid[0].len(); + let mut count = 0; + + let directions = vec![ + (0, 1), // Horizontal right + (0, -1), // Horizontal left + (1, 0), // Vertical down + (-1, 0), // Vertical up + (1, 1), // Diagonal down-right + (1, -1), // Diagonal down-left + (-1, 1), // Diagonal up-right + (-1, -1), // Diagonal up-left + ]; + + for row in 0..rows { + for col in 0..cols { + for (dx, dy) in &directions { + let mut found = true; + + for (i, _) in word_chars.iter().enumerate().take(word_len) { + let x = isize::try_from(row).unwrap() + isize::try_from(i).unwrap() * dx; + let y = isize::try_from(col).unwrap() + isize::try_from(i).unwrap() * dy; + + if x < 0 + || y < 0 + || x >= rows.try_into().unwrap() + || y >= cols.try_into().unwrap() + { + found = false; + break; + } + + let u_x: usize = usize::try_from(x).unwrap(); + let u_y: usize = usize::try_from(y).unwrap(); + + if self.grid[u_x][u_y] != word_chars[i] { + found = false; + break; + } } - let u_x: usize = usize::try_from(x).unwrap(); - let u_y: usize = usize::try_from(y).unwrap(); - - if grid[u_x][u_y] != word_chars[i] { - found = false; - break; + if found { + count += 1; } } - - if found { - count += 1; - } } } - } - count + count + } } diff --git a/crates/day05/src/main.rs b/crates/day05/src/main.rs index 23a32e3..a37a768 100644 --- a/crates/day05/src/main.rs +++ b/crates/day05/src/main.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, str::FromStr}; +use std::collections::HashMap; use helpers::read_file; @@ -10,18 +10,17 @@ struct PrintQueueChecker { fn main() { let message = read_file("crates/day05/input.txt").unwrap(); // --- Part One --- - let checker = PrintQueueChecker::from_str(&message).unwrap(); + let checker = PrintQueueChecker::new(&message); println!("Part One solution: {}", checker.check_page_order()); // --- Part Two --- println!("Part Two solution: {}", checker.check_and_sort_page_order()); } -impl FromStr for PrintQueueChecker { - type Err = String; - fn from_str(puzzle: &str) -> Result { +impl PrintQueueChecker { + fn new(content: &str) -> Self { let mut rules = HashMap::new(); - puzzle + content .lines() .take_while(|l| !l.is_empty()) .filter_map(|l| { @@ -34,21 +33,18 @@ impl FromStr for PrintQueueChecker { rules.entry(right).or_insert(vec![]).push(left); }); - let page_numbers = puzzle + let page_numbers = content .lines() .skip_while(|x| !x.is_empty()) .skip(1) .filter_map(|l| l.split(',').map(|x| x.parse().ok()).collect()) .collect(); - - Ok(Self { + Self { rules, page_numbers, - }) + } } -} -impl PrintQueueChecker { fn check_valid(&self, order: &[i32]) -> bool { assert!(order.len() % 2 == 1); for (idx, val) in order.iter().enumerate() {