pub mod matrix { pub type Pos = (usize, usize); pub type PosDelta = (isize, isize); #[derive(Clone)] pub struct Matrix { dots: Vec>, pub limit: Pos, } impl Matrix { pub fn new(text: &str, parse: F) -> Self where F: Fn(char) -> T, { let dots: Vec> = text .lines() .map(|row| row.chars().map(|c| parse(c)).collect()) .collect(); let limit = (dots.len(), dots[0].len()); Self { dots, limit } } pub fn get(&self, (x, y): Pos) -> &T { &self.dots[x][y] } pub fn set(&mut self, (x, y): Pos, dot: T) { self.dots[x][y] = dot; } pub fn pos_move(&self, (x, y): Pos, (dx, dy): PosDelta) -> Option { let x2 = x as isize + dx; if x2 < 0 || x2 >= self.limit.0 as isize { return None; } let y2 = y as isize + dy; if y2 < 0 || y2 >= self.limit.1 as isize { return None; } Some((x2 as usize, y2 as usize)) } } use std::fmt; impl fmt::Display for Matrix where T: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for row in &self.dots { write!( f, "{}\n", row.iter().map(|c| c.to_string()).collect::() )?; } fmt::Result::Ok(()) } } } pub fn run_day(day: &str, p1: S1, p2: S2) where S1: FnOnce(&str) -> String, S2: FnOnce(&str) -> String, { let input_file = format!("inputs/{day}"); let input = std::fs::read_to_string(input_file).unwrap(); println!("==== DAY {day}"); println!("Result (P1): {}", p1(&input)); println!("Result (P2): {}", p2(&input)); }