feat(day4): init
This commit is contained in:
parent
06dc4402d1
commit
992756faa6
2 changed files with 134 additions and 1 deletions
127
src/solutions/day_04.rs
Normal file
127
src/solutions/day_04.rs
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,5 +3,11 @@ use crate::common::Solution;
|
||||||
mod day_01;
|
mod day_01;
|
||||||
mod day_02;
|
mod day_02;
|
||||||
mod day_03;
|
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,
|
||||||
|
];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue