--- /dev/null
+use std::error::Error;
+use std::path::Path;
+
+pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
+ let res = run_part1(&input)?;
+ println!("{res}");
+
+ let res = run_part2(&input)?;
+ println!("{res}");
+
+ Ok(())
+}
+
+struct Puzzle {
+ map: Vec<Vec<char>>,
+ x_pos: Vec<(usize, usize)>,
+}
+
+impl Puzzle {
+ pub fn new(input: &str) -> Self {
+ let mut map: Vec<Vec<char>> = input.lines()
+ .map(|l| {
+ let s = ".".to_owned() + l + ".";
+ s.chars().collect()
+ })
+ .collect();
+ map.insert(0, vec!['.'; map[0].len()]);
+ map.push(vec!['.'; map[0].len()]);
+
+ // 'X' coordinates
+ let mut x_pos = Vec::<(usize, usize)>::new();
+ map.iter().enumerate()
+ .for_each(|(r, row)| {
+ row.iter().enumerate()
+ .for_each(|(c, v)| {
+ if *v == 'X' {
+ x_pos.push((r, c));
+ }
+ });
+ });
+
+ Self {
+ map,
+ x_pos,
+ }
+ }
+}
+
+fn get_day() -> String {
+ let filename = file!();
+ Path::new(filename).file_stem().unwrap().to_str().unwrap().to_string()
+}
+
+fn run_part1(input: &str) -> Result<u32, Box<dyn Error>> {
+ println!("Running {} - part 1", get_day());
+
+ let dir = [
+ (-1,0), (-1,1), (0,1), (1,1),
+ (1,0), (1,-1), (0,-1), (-1,-1),
+ ];
+
+ let puzzle = Puzzle::new(input);
+
+ let mut res: u32 = 0;
+
+ // for each 'X' search for 'MAS' around and add 1 if found
+ for (row, col) in puzzle.x_pos {
+ for (dr, dc) in dir {
+ let (mut r, mut c) = (row, col);
+ for v in ['M', 'A', 'S'] {
+ r = ((r as i32) + dr) as usize;
+ c = ((c as i32) + dc) as usize;
+ if puzzle.map[r][c] != v {
+ break;
+ }
+ else if puzzle.map[r][c] == 'S' {
+ res += 1;
+ }
+ }
+ }
+ }
+
+ Ok(res)
+}
+
+fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
+ println!("Running {} - part 2", get_day());
+
+ Ok(0)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ static TEXT_INPUT_1: &str = "\
+..X...
+.SAMX.
+.A..A.
+XMAS.S
+.X....";
+ static TEXT_INPUT_2: &str = "\
+MMMSXXMASM
+MSAMXMSMSA
+AMXSXMAAMM
+MSAMASMSMX
+XMASAMXAMM
+XXAMMXXAMA
+SMSMSASXSS
+SAXAMASAAA
+MAMMMXMMMM
+MXMXAXMASX";
+
+ #[test]
+ fn test_part1() {
+ assert_eq!(4, run_part1(TEXT_INPUT_1).unwrap());
+ assert_eq!(18, run_part1(TEXT_INPUT_2).unwrap());
+ }
+
+ #[test]
+ fn test_part2() {
+ assert_eq!(0, run_part2(TEXT_INPUT_2).unwrap());
+ }
+}