feat(day4): init

This commit is contained in:
uku 2024-12-04 21:57:40 +01:00
parent 06dc4402d1
commit 992756faa6
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
2 changed files with 134 additions and 1 deletions

127
src/solutions/day_04.rs Normal file
View file

@ -0,0 +1,127 @@
use itertools::Itertools;
use crate::common::{Answer, Solution};
pub struct Day04;
impl Solution for Day04 {
fn name(&self) -> &'static str {
"Ceres Search"
}
fn part_a(&self, input: &str) -> Answer {
let horizontal = input.lines().map(xmas_count).sum::<usize>();
let vertical = rotate_90(input).map(xmas_count).sum::<usize>();
let diag_45 = rotate_45(input).map(xmas_count).sum::<usize>();
let diag_135 = rotate_45(&rotate_90(input).join("\n"))
.map(xmas_count)
.sum::<usize>();
let sum = horizontal + vertical + diag_45 + diag_135;
Answer::Number(sum as u64)
}
fn part_b(&self, input: &str) -> Answer {
let input_90 = rotate_90(input).join("\n");
let input_180 = rotate_90(&input_90).join("\n");
let input_270 = rotate_90(&input_180).join("\n");
let sum = cross_mas_count(input)
+ cross_mas_count(&input_90)
+ cross_mas_count(&input_180)
+ cross_mas_count(&input_270);
Answer::Number(sum as u64)
}
}
fn rotate_90(input: &str) -> impl Iterator<Item = String> + use<'_> {
let col_count = input.lines().next().unwrap().chars().count();
(0..col_count)
.rev() // this is important otherwise 135 rotation doesn't work
.map(|i| input.lines().map(|l| l.chars().nth(i).unwrap()).join(""))
}
fn rotate_45(input: &str) -> impl Iterator<Item = String> + use<'_> {
let line_count = input.lines().count();
let col_count = input.lines().next().unwrap().chars().count();
let cols = (0..col_count).map(|i| traverse_diagonal(input, (0, i)));
let lines = (1..line_count).map(|i| traverse_diagonal(input, (i, 0)));
cols.chain(lines)
}
fn traverse_diagonal(input: &str, start: (usize, usize)) -> String {
(start.0..)
.zip(start.1..)
.map_while(|(x, y)| input.lines().nth(x).and_then(|l| l.chars().nth(y)))
.collect()
}
fn xmas_count(line: impl AsRef<str>) -> usize {
line.as_ref().matches("XMAS").count() + line.as_ref().matches("SAMX").count()
}
fn cross_mas_count(input: &str) -> usize {
let mut sum = 0;
for (x, line) in input.lines().enumerate() {
for (y, _) in line.match_indices('A') {
let prev_line = x.checked_sub(1).and_then(|n| input.lines().nth(n));
let next_line = input.lines().nth(x + 1);
if let (Some(prev_line), Some(next_line)) = (prev_line, next_line) {
let prev_y = y.checked_sub(1);
let next_y = y + 1;
let prev_prev = prev_y.and_then(|n| prev_line.chars().nth(n));
let prev_next = prev_line.chars().nth(next_y);
let next_prev = prev_y.and_then(|n| next_line.chars().nth(n));
let next_next = next_line.chars().nth(next_y);
if let (Some('M'), Some('M'), Some('S'), Some('S')) =
(prev_prev, prev_next, next_prev, next_next)
{
sum += 1;
}
}
}
}
sum
}
#[cfg(test)]
mod test {
use super::Day04;
use crate::common::Solution;
use indoc::indoc;
const INPUT: &str = indoc! {"
MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
"};
#[test]
fn part_a() {
assert_eq!(Day04.part_a(INPUT), 18.into());
}
#[test]
fn part_b() {
assert_eq!(Day04.part_b(INPUT), 9.into());
}
}

View file

@ -3,5 +3,11 @@ use crate::common::Solution;
mod day_01;
mod day_02;
mod day_03;
mod day_04;
pub const SOLUTIONS: &[&dyn Solution] = &[&day_01::Day01, &day_02::Day02, &day_03::Day03];
pub const SOLUTIONS: &[&dyn Solution] = &[
&day_01::Day01,
&day_02::Day02,
&day_03::Day03,
&day_04::Day04,
];