diff options
Diffstat (limited to '2024_rust/src')
-rw-r--r-- | 2024_rust/src/day4.rs | 189 |
1 files changed, 96 insertions, 93 deletions
diff --git a/2024_rust/src/day4.rs b/2024_rust/src/day4.rs index 1ebe67b..448fe19 100644 --- a/2024_rust/src/day4.rs +++ b/2024_rust/src/day4.rs @@ -1,69 +1,104 @@ const XMAS: &str = "XMAS"; const MAS: &str = "MAS"; -type Matrix = Vec<Vec<char>>; type Position = (usize, usize); -type RowXmas = [Position; XMAS.len()]; -type RowMas = [Position; MAS.len()]; - -fn check_xmas<'a, I>(m: &Matrix, it: I) -> bool -where - I: Iterator<Item = &'a Position>, -{ - for (c, (i, j)) in XMAS.chars().zip(it) { - if m[*i][*j] != c { - return false; +type Row = Vec<Position>; +type Rows = Vec<Row>; +type Move = (Position, (usize, isize)); + +struct Matrix { + chars: Vec<Vec<char>>, + limit: Position, +} + +impl Matrix { + fn new(text: &str) -> Self { + let chars: Vec<Vec<char>> = text.lines().map(|row| row.chars().collect()).collect(); + let limit = (chars.len(), chars[0].len()); + Self { chars, limit } + } + + fn check_iter<'a, I>(&self, it: I, needle: &str) -> bool + where + I: Iterator<Item = &'a Position>, + { + for (c, (i, j)) in needle.chars().zip(it) { + if self.chars[*i][*j] != c { + return false; + } } + + true } - true + fn check_row(&self, row: &Row, needle: &str) -> bool { + self.check_iter(row.iter(), needle) || self.check_iter(row.iter().rev(), needle) + } } -fn offplus(x: usize, y: isize) -> usize { - (x as isize + y) as usize +struct Square<'a> { + pos: Position, + size: usize, + matrix: &'a Matrix, } -fn rows_latdiag_from(p: Position, max_x: usize, max_y: usize) -> Vec<RowXmas> { - let mut rs: Vec<RowXmas> = vec![]; - - // Horizontal / vertical / diagonal - for (p0, (di, dj)) in [ - (p, (0, 1)), // horizontal, left-to-right - (p, (1, 0)), // vertical, top-down - (p, (1, 1)), // diag from p, top-down and left-to-right - ((p.0, p.1 + XMAS.len() - 1), (1, -1isize)), // the other diag, top-down and right-to-left - ] { - // Bounds check - let max_off = XMAS.len(); - if p0.0 + di * max_off > max_x - || (dj > 0 && offplus(p0.1, dj * max_off as isize) > max_y) - || p0.1 >= max_y - { - continue; - } +impl Square<'_> { + fn rows<M>(&self, moves: M) -> Rows + where + M: Fn(&Square) -> Vec<Move>, + { + let mut rs: Rows = vec![]; + + // Horizontal / vertical / diagonal + for (p0, (di, dj)) in moves(self) { + // Bounds check + if p0.0 + di * self.size > self.matrix.limit.0 + || (dj > 0 && offplus(p0.1, dj * self.size as isize) > self.matrix.limit.1) + || p0.1 >= self.matrix.limit.1 + { + continue; + } - let mut p_acc = p0; - let mut ps = [(0, 0); XMAS.len()]; - for idx in 0..ps.len() { - ps[idx].0 = p_acc.0; - ps[idx].1 = p_acc.1; - p_acc = (p_acc.0 + di, offplus(p_acc.1, dj)); + let mut p_acc = p0; + let mut row: Row = vec![]; + for _idx in 0..self.size { + row.push(p_acc); + p_acc = (p_acc.0 + di, offplus(p_acc.1, dj)); + } + rs.push(row); } - rs.push(ps); + + rs } +} - rs +fn offplus(x: usize, y: isize) -> usize { + (x as isize + y) as usize +} + +fn moves_xmas(Square { pos, size, .. }: &Square) -> Vec<Move> { + let v = vec![ + (*pos, (0, 1)), // diag from pos, top-down and left-to-right + (*pos, (1, 0)), // diag from pos, top-down and left-to-right + (*pos, (1, 1)), // diag from pos, top-down and left-to-right + ((pos.0, pos.1 + size - 1), (1, -1)), // the other diag, top-down and right-to-left + ]; + v } pub fn p1(input: &str) -> String { - let m: Matrix = input.lines().map(|row| row.chars().collect()).collect(); + let matrix: Matrix = Matrix::new(input); let mut result = 0; - for i in 0..m.len() { - for j in 0..m[i].len() { - let p = (i, j); - for row in rows_latdiag_from(p, m.len(), m[i].len()) { - if check_xmas(&m, row.iter()) || check_xmas(&m, row.iter().rev()) { + for i in 0..matrix.limit.0 { + for j in 0..matrix.limit.1 { + let sq = Square { + pos: (i, j), + size: XMAS.len(), + matrix: &matrix, + }; + for row in sq.rows(moves_xmas) { + if matrix.check_row(&row, XMAS) { result += 1; } } @@ -73,58 +108,26 @@ pub fn p1(input: &str) -> String { result.to_string() } -fn check_mas<'a, I>(m: &Matrix, it: I) -> bool -where - I: Iterator<Item = &'a Position>, -{ - for (c, (i, j)) in MAS.chars().zip(it) { - if m[*i][*j] != c { - return false; - } - } - - true -} - -fn rows_diag_from(p: Position, max_x: usize, max_y: usize) -> Vec<RowMas> { - let mut rs: Vec<RowMas> = vec![]; - - // Horizontal / vertical / diagonal - for (p0, (di, dj)) in [ - (p, (1, 1)), // diag from p, top-down and left-to-right - ((p.0, p.1 + MAS.len() - 1), (1, -1isize)), // the other diag, top-down and right-to-left - ] { - // Bounds check - let max_off = MAS.len(); - if p0.0 + di * max_off > max_x - || (dj > 0 && offplus(p0.1, dj * max_off as isize) > max_y) - || p0.1 >= max_y - { - continue; - } - - let mut p_acc = p0; - let mut ps = [(0, 0); MAS.len()]; - for idx in 0..ps.len() { - ps[idx].0 = p_acc.0; - ps[idx].1 = p_acc.1; - p_acc = (p_acc.0 + di, offplus(p_acc.1, dj)); - } - rs.push(ps); - } - - rs +fn moves_mas(Square { pos, size, .. }: &Square) -> Vec<Move> { + let v = vec![ + (*pos, (1, 1)), // diag from pos, top-down and left-to-right + ((pos.0, pos.1 + size - 1), (1, -1)), // the other diag, top-down and right-to-left + ]; + v } pub fn p2(input: &str) -> String { - let m: Matrix = input.lines().map(|row| row.chars().collect()).collect(); + let matrix: Matrix = Matrix::new(input); let mut result = 0; - for i in 0..=m.len() - MAS.len() { - for j in 0..=m[i].len() - MAS.len() { - let p = (i, j); - let rows = rows_diag_from(p, m.len(), m[i].len()); - if rows.iter().all(|r| check_mas(&m, r.iter()) || check_mas(&m, r.iter().rev())) { + for i in 0..=matrix.limit.0 - MAS.len() { + for j in 0..=matrix.limit.1 - MAS.len() { + let sq = Square { + pos: (i, j), + size: MAS.len(), + matrix: &matrix, + }; + if sq.rows(moves_mas).iter().all(|r| matrix.check_row(r, MAS)) { result += 1; } } |