2024 day-4 as completed
This commit is contained in:
4
2024/day-4/src/lib.rs
Normal file
4
2024/day-4/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod part1;
|
||||
pub use crate::part1::*;
|
||||
pub mod part2;
|
||||
pub use crate::part2::*;
|
||||
31
2024/day-4/src/main.rs
Normal file
31
2024/day-4/src/main.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_4::part1;
|
||||
use day_4::part2;
|
||||
|
||||
use error_stack::{Result, ResultExt};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
#[global_allocator]
|
||||
static ALLOC: dhat::Alloc = dhat::Alloc;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum Day4Error {
|
||||
#[error("Part 1 failed")]
|
||||
Part1Error,
|
||||
#[error("Part 2 failed")]
|
||||
Part2Error,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Day4Error> {
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
let _profiler = dhat::Profiler::new_heap();
|
||||
|
||||
let input = include_str!("./input.txt");
|
||||
let part1_result = part1(input).change_context(Day4Error::Part1Error)?;
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input).change_context(Day4Error::Part2Error)?;
|
||||
println!("part 2: {part2_result}");
|
||||
Ok(())
|
||||
}
|
||||
96
2024/day-4/src/part1.rs
Normal file
96
2024/day-4/src/part1.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use error_stack::Result;
|
||||
use glam::IVec2;
|
||||
use thiserror::Error;
|
||||
|
||||
// day-4
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Day4Part1Error {
|
||||
#[error("Problem parsing Day 4")]
|
||||
ParseError,
|
||||
}
|
||||
|
||||
pub fn part1(input: &str) -> Result<String, Day4Part1Error> {
|
||||
//read in grid
|
||||
let grid = input
|
||||
.lines()
|
||||
.map(|line| Vec::from(line.as_bytes()))
|
||||
.collect::<Vec<_>>();
|
||||
let num_of_rows = grid.len().try_into().unwrap();
|
||||
let num_of_cols = grid[0].len().try_into().unwrap(); //because we know it will be rectangular
|
||||
//window over each letter (skip over not x's
|
||||
let total: usize = grid
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(row_num, row)| {
|
||||
row.iter()
|
||||
.enumerate()
|
||||
.map(|(col_num, col)| {
|
||||
if *col == b'X' {
|
||||
//window over the rest
|
||||
let point =
|
||||
IVec2::new(row_num.try_into().unwrap(), col_num.try_into().unwrap());
|
||||
[
|
||||
IVec2::NEG_X,
|
||||
IVec2::NEG_ONE,
|
||||
IVec2::NEG_Y,
|
||||
IVec2::new(1, -1),
|
||||
IVec2::X,
|
||||
IVec2::ONE,
|
||||
IVec2::Y,
|
||||
IVec2::new(-1, 1),
|
||||
]
|
||||
.iter()
|
||||
.filter(|dir| {
|
||||
let extent = point + (*dir * 3);
|
||||
if extent.x < 0
|
||||
|| extent.x >= num_of_rows
|
||||
|| extent.y < 0
|
||||
|| extent.y >= num_of_cols
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let m = point + *dir;
|
||||
let a = point + 2 * *dir;
|
||||
let s = point + 3 * *dir;
|
||||
grid[m.x as u32 as usize][m.y as u32 as usize] == b'M'
|
||||
&& grid[a.x as u32 as usize][a.y as u32 as usize] == b'A'
|
||||
&& grid[s.x as u32 as usize][s.y as u32 as usize] == b'S'
|
||||
})
|
||||
.count()
|
||||
//todo!("at pos {row_num} - {col_num}")
|
||||
} else {
|
||||
0_usize
|
||||
}
|
||||
})
|
||||
.sum::<usize>()
|
||||
})
|
||||
.sum();
|
||||
//count
|
||||
Ok(total.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "MMMSXXMASM
|
||||
MSAMXMSMSA
|
||||
AMXSXMAAMM
|
||||
MSAMASMSMX
|
||||
XMASAMXAMM
|
||||
XXAMMXXAMA
|
||||
SMSMSASXSS
|
||||
SAXAMASAAA
|
||||
MAMMMXMMMM
|
||||
MXMXAXMASX";
|
||||
|
||||
#[test_log::test]
|
||||
#[test_log(default_log_filter = "trace")]
|
||||
fn part1_works() {
|
||||
let result = part1(INPUT).unwrap();
|
||||
assert_eq!(result, "18".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
100
2024/day-4/src/part2.rs
Normal file
100
2024/day-4/src/part2.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use error_stack::Result;
|
||||
use glam::IVec2;
|
||||
use thiserror::Error;
|
||||
|
||||
// day-4
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Day4Part2Error {
|
||||
#[error("Problem parsing Day 4")]
|
||||
ParseError,
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> Result<String, Day4Part2Error> {
|
||||
//read in grid
|
||||
let grid = input
|
||||
.lines()
|
||||
.map(|line| Vec::from(line.as_bytes()))
|
||||
.collect::<Vec<_>>();
|
||||
let num_of_rows = grid.len();
|
||||
let num_of_cols = grid[0].len();
|
||||
//window over each letter (skip over not x's
|
||||
let total: usize = grid
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(1)
|
||||
.take(num_of_rows - 2)
|
||||
.map(|(row_num, row)| {
|
||||
row.iter()
|
||||
.enumerate()
|
||||
.skip(1)
|
||||
.take(num_of_cols - 2)
|
||||
.map(|(col_num, col)| {
|
||||
if *col == b'A' {
|
||||
//window over the rest
|
||||
let point =
|
||||
IVec2::new(row_num.try_into().unwrap(), col_num.try_into().unwrap());
|
||||
let up_forward = point + IVec2::new(-1, 1);
|
||||
let up_back = point + IVec2::NEG_ONE;
|
||||
let down_forward = point + IVec2::ONE;
|
||||
let down_back = point + IVec2::new(1, -1);
|
||||
if ((grid[up_back.x as u32 as usize][up_back.y as u32 as usize] == b'M'
|
||||
&& grid[down_forward.x as u32 as usize]
|
||||
[down_forward.y as u32 as usize]
|
||||
== b'S')
|
||||
|| (grid[up_back.x as u32 as usize][up_back.y as u32 as usize] == b'S'
|
||||
&& grid[down_forward.x as u32 as usize]
|
||||
[down_forward.y as u32 as usize]
|
||||
== b'M'))
|
||||
&& ((grid[down_back.x as u32 as usize][down_back.y as u32 as usize]
|
||||
== b'M'
|
||||
&& grid[up_forward.x as u32 as usize]
|
||||
[up_forward.y as u32 as usize]
|
||||
== b'S')
|
||||
|| (grid[down_back.x as u32 as usize][down_back.y as u32 as usize]
|
||||
== b'S'
|
||||
&& grid[up_forward.x as u32 as usize]
|
||||
[up_forward.y as u32 as usize]
|
||||
== b'M'))
|
||||
{
|
||||
//println!(" found at {}-{}", point.x, point.y);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
// todo!("at pos {row_num} - {col_num}")
|
||||
} else {
|
||||
0_usize
|
||||
}
|
||||
})
|
||||
.sum::<usize>()
|
||||
})
|
||||
.sum();
|
||||
//count
|
||||
Ok(total.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "MMMSXXMASM
|
||||
MSAMXMSMSA
|
||||
AMXSXMAAMM
|
||||
MSAMASMSMX
|
||||
XMASAMXAMM
|
||||
XXAMMXXAMA
|
||||
SMSMSASXSS
|
||||
SAXAMASAAA
|
||||
MAMMMXMMMM
|
||||
MXMXAXMASX";
|
||||
|
||||
#[test_log::test]
|
||||
#[test_log(default_log_filter = "trace")]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT).unwrap();
|
||||
assert_eq!(result, "9".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user