diff options
| author | Guillermo Ramos | 2024-12-05 10:11:47 +0100 | 
|---|---|---|
| committer | Guillermo Ramos | 2024-12-05 10:11:47 +0100 | 
| commit | dda2007b776bbfd7a190f0e89c9abfac9d4363f8 (patch) | |
| tree | 25ec7cfd9d1a6dd80c861c003fa712b038f810ef /2024_rust/src | |
| parent | 127145ac655848edf81c901adf37e569efd0a50e (diff) | |
| download | AoC-dda2007b776bbfd7a190f0e89c9abfac9d4363f8.tar.gz | |
Refactor
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;              }          } | 
