[Mark Doyle's Website]

[Advent of Code]

Day 4

use aoc::around::{Around, OFFSETS};

use crate::*;
use std::fmt::Display;

impl Day4 for Year2024 {
    fn part1(input: String) -> impl Display {
        find_xmas(input)
    }

    fn part2(input: String) -> impl Display {
        find_mas(input)
    }
}

fn find_xmas(input: String) -> i32 {
    let grid = input
        .lines()
        .map(|l| l.chars().collect::<Vec<_>>())
        .collect::<Vec<_>>();

    let mut sum = 0;
    for (i, line) in grid.clone().into_iter().enumerate() {
        for (j, ch) in line.into_iter().enumerate() {
            if ch == 'X' {
                for offset in &OFFSETS {
                    let mut next = 'M';
                    let offset = (1..=3).map(|n| (offset.0 * n, offset.1 * n));

                    for adj in grid.around_offsets(i, j, offset.collect()) {
                        if *adj != next {
                            continue;
                        }

                        match next {
                            'M' => next = 'A',
                            'A' => next = 'S',
                            'S' => sum += 1,
                            _ => panic!("next reached infallible state"),
                        }
                    }
                }
            }
        }
    }

    sum
}

fn find_mas(input: String) -> impl Display {
    let grid = input
        .lines()
        .map(|l| l.chars().collect::<Vec<_>>())
        .collect::<Vec<_>>();

    let mut sum = 0;
    for (i, line) in grid.clone().into_iter().enumerate() {
        for (j, ch) in line.into_iter().enumerate() {
            if ch == 'A' {
                let offsets = vec![(-1, -1), (1, 1), (1, -1), (-1, 1)];

                let mut seen = 0;
                let mut prev = None;

                for corner in grid.around_offsets(i, j, offsets) {
                    match (prev, corner) {
                        (None, 'M' | 'S') => prev = Some(*corner),
                        (Some('M'), 'S') | (Some('S'), 'M') => {
                            seen += 1;
                            prev = None
                        }
                        _ => break,
                    }
                }

                if seen == 2 {
                    sum += 1;
                }
            }
        }
    }

    sum
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn dir_checks_south() {
        let tcs = ["...", ".X.", ".M.", ".A.", ".S."].join("\n");
        assert_eq!(find_xmas(tcs), 1);
    }

    #[test]
    fn dir_checks_east() {
        let tcs = ["......", "..XMAS", "..M...", "..A...", "..S..."].join("\n");

        assert_eq!(find_xmas(tcs), 2);
    }

    #[test]
    fn dir_checks_west() {
        let tcs = [".......", "SAMXMAS", "...M...", "...A...", "...S..."].join("\n");

        assert_eq!(find_xmas(tcs), 3);
    }

    #[test]
    fn dir_checks_north() {
        let tcs = [
            "...S...", "...A...", "...M...", "SAMXMAS", "...M...", "...A...", "...S...",
        ]
        .join("\n");

        assert_eq!(find_xmas(tcs), 4);
    }

    #[test]
    fn dir_checks_north_east() {
        let tcs = [
            "...S..S", "...A.A.", "...MM..", "SAMXMAS", "...M...", "...A...", "...S...",
        ]
        .join("\n");

        assert_eq!(find_xmas(tcs), 5);
    }

    #[test]
    fn dir_checks_north_west() {
        let tcs = [
            "S......", ".A.....", "..M....", "...XMAS", "....M..", ".....A.", "......S",
        ]
        .join("\n");

        assert_eq!(find_xmas(tcs), 3);
    }

    #[test]
    fn dir_checks_south_east() {
        let tcs = [
            "......S", ".....A.", "....M..", "...XMAS", "..M....", ".A.....", "S......",
        ]
        .join("\n");

        assert_eq!(find_xmas(tcs), 3);
    }

    #[test]
    fn dir_checks_south_west() {
        let tcs = [
            "S......", ".A.....", "..M....", "SAMX...", "....M..", ".....A.", "......S",
        ]
        .join("\n");

        assert_eq!(find_xmas(tcs), 3);
    }

    #[test]
    fn dir_checks_all_directions() {
        let tcs = [
            "S..S..S", ".A.A.A.", "..MMM..", "SAMXMAS", "..MMM..", ".A.A.A.", "S..S..S",
        ]
        .join("\n");

        assert_eq!(find_xmas(tcs), 8);
    }
}
*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|*/_\/_*_\/__*__\/___*___\|