Skip to content

Commit

Permalink
Modified day 4
Browse files Browse the repository at this point in the history
  • Loading branch information
3rfaan committed Dec 6, 2024
1 parent 2a15183 commit 7a86ecb
Showing 1 changed file with 47 additions and 60 deletions.
107 changes: 47 additions & 60 deletions src/bin/04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,15 @@ advent_of_code::solution!(4);

pub fn part_one(input: &str) -> Option<u32> {
let grid = Grid::from(input);
let offsets = vec![
(0, 1), // right
(0, -1), // left
(1, 0), // down
(-1, 0), // up
(1, 1), // up left
(-1, -1), // up right
(1, -1), // down left
(-1, 1), // down right
];

Some(
(0..grid.rows)
.flat_map(|row| (0..grid.cols).map(move |col| (row, col)))
.flat_map(|(row, col)| offsets.iter().map(move |dir| (row, col, dir)))
.filter(|&(row, col, dir)| grid.xmas_finder(row, col, &dir))
.count() as u32,
)
let mut count = 0;

(0..grid.rows)
.flat_map(|row| (0..grid.cols).map(move |col| (row, col)))
.filter(|&(row, col)| grid.bytes[row][col] == b'X')
.for_each(|(row, col)| count += grid.xmas_count(row, col));

Some(count as u32)
}

pub fn part_two(input: &str) -> Option<u32> {
Expand All @@ -28,70 +19,66 @@ pub fn part_two(input: &str) -> Option<u32> {
Some(
(0..grid.rows)
.flat_map(|row| (0..grid.cols).map(move |col| (row, col)))
.filter(|&(row, col)| grid.cross_finder(row, col))
.filter(|&(row, col)| grid.bytes[row][col] == b'A')
.filter(|&(row, col)| grid.crossmas_count(row, col))
.count() as u32,
)
}

macro_rules! off {
($self:expr,($row:ident $op1:tt $off1:literal),($col:ident $op2:tt $off2:literal)) => {
$self.grid
.get(($row as isize $op1 $off1) as usize)
.and_then(|c| c.get(($col as isize $op2 $off2) as usize))
};
}

struct Grid {
grid: Vec<Vec<char>>,
bytes: Vec<Vec<u8>>,
rows: usize,
cols: usize,
}

impl Grid {
fn xmas_finder(&self, row: usize, col: usize, off: &(isize, isize)) -> bool {
let word = "XMAS";
let (off_x, off_y) = off;

word.chars().enumerate().all(|(i, word_char)| {
let new_row = row as isize + i as isize * off_x;
let new_col = col as isize + i as isize * off_y;

let (nx, ny) = (new_row as usize, new_col as usize);
fn get(&self, r: usize, c: usize) -> u8 {
*self
.bytes
.get(r)
.and_then(|row| row.get(c))
.unwrap_or(&b'.')
}

match self.grid.get(nx).and_then(|row| row.get(ny)) {
Some(&letter) if letter == word_char => true,
_ => false,
}
fn xmas_count(&self, row: usize, col: usize) -> usize {
[
(0, 1),
(1, 0),
(1, 1),
(0, -1),
(-1, 0),
(-1, -1),
(1, -1),
(-1, 1),
]
.iter()
.filter(|(off_x, off_y)| {
(0..4).all(|i| {
let (new_row, new_col) = (row + (off_x * i) as usize, col + (off_y * i) as usize);
self.get(new_row, new_col) == b"XMAS"[i as usize]
})
})
.count()
}

fn cross_finder(&self, row: usize, col: usize) -> bool {
if self.grid[row][col] != 'A' {
return false;
}

let ul = off!(self, (row - 1), (col - 1)); // up left
let ur = off!(self, (row + 1), (col - 1)); // up right
let dl = off!(self, (row - 1), (col + 1)); // down left
let dr = off!(self, (row + 1), (col + 1)); // down right
fn crossmas_count(&self, row: usize, col: usize) -> bool {
let diag1 = [self.get(row - 1, col - 1), self.get(row + 1, col + 1)];
let diag2 = [self.get(row - 1, col + 1), self.get(row + 1, col - 1)];

let (mut ul_to_dr, mut ur_to_dl) = (false, false);

if let (Some(&ul), Some(&ur), Some(&dl), Some(&dr)) = (ul, ur, dl, dr) {
ul_to_dr = (ul == 'M' && dr == 'S') || (ul == 'S' && dr == 'M');
ur_to_dl = (ur == 'M' && dl == 'S') || (ur == 'S' && dl == 'M');
}

ul_to_dr && ur_to_dl
[diag1, diag2].iter().all(|w| w == b"MS" || w == b"SM")
}
}

impl From<&str> for Grid {
fn from(input: &str) -> Self {
let grid: Vec<Vec<char>> = input.lines().map(|row| row.chars().collect()).collect();
let (rows, cols) = (grid.len(), grid[0].len());
let grid: Vec<Vec<u8>> = input.lines().map(|row| row.bytes().collect()).collect();
let (rows, cols) = (grid.len(), grid.first().map_or(0, |row| row.len()));

Self { grid, rows, cols }
Self {
bytes: grid,
rows,
cols,
}
}
}

Expand Down

0 comments on commit 7a86ecb

Please sign in to comment.