|
| 1 | +struct Grid { |
| 2 | + cells: Vec<Vec<char>>, |
| 3 | +} |
| 4 | + |
| 5 | +impl Grid { |
| 6 | + fn new(input: &str) -> Self { |
| 7 | + Self { |
| 8 | + cells: input.lines().map(|l| l.trim().chars().collect()).collect(), |
| 9 | + } |
| 10 | + } |
| 11 | + |
| 12 | + fn width(&self) -> usize { |
| 13 | + self.cells.first().map_or(0, |r| r.len()) |
| 14 | + } |
| 15 | + |
| 16 | + fn height(&self) -> usize { |
| 17 | + self.cells.len() |
| 18 | + } |
| 19 | + |
| 20 | + fn get(&self, row: usize, col: usize) -> Option<char> { |
| 21 | + self.cells.get(row)?.get(col).copied() |
| 22 | + } |
| 23 | + |
| 24 | + fn paperolls(&self) -> PaperrollIterator { |
| 25 | + PaperrollIterator { |
| 26 | + grid: self, |
| 27 | + current_row: 0, |
| 28 | + current_col: 0, |
| 29 | + } |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +struct PaperrollIterator<'a> { |
| 34 | + grid: &'a Grid, |
| 35 | + current_row: usize, |
| 36 | + current_col: usize, |
| 37 | +} |
| 38 | + |
| 39 | +impl Iterator for PaperrollIterator<'_> { |
| 40 | + type Item = (usize, usize, char); |
| 41 | + |
| 42 | + fn next(&mut self) -> Option<Self::Item> { |
| 43 | + loop { |
| 44 | + if self.current_row >= self.grid.height() { |
| 45 | + return None; |
| 46 | + } |
| 47 | + if self.current_col >= self.grid.width() { |
| 48 | + self.current_col = 0; |
| 49 | + self.current_row += 1; |
| 50 | + continue; |
| 51 | + } |
| 52 | + |
| 53 | + let (x, y) = (self.current_row, self.current_col); |
| 54 | + let c = self.grid.get(x, y)?; |
| 55 | + |
| 56 | + if c != '@' { |
| 57 | + // no paperroll here, continue |
| 58 | + self.current_col += 1; |
| 59 | + continue; |
| 60 | + } |
| 61 | + |
| 62 | + // we are at (x, y) with '@', so we check now all the neighbors, |
| 63 | + // if a neigboar is also '@', we count it, |
| 64 | + // if the count is >= 4 we continue the loop on the next position |
| 65 | + |
| 66 | + let mut paperrolls = 0; |
| 67 | + for dx in -1..=1 { |
| 68 | + for dy in -1..=1 { |
| 69 | + if dx == 0 && dy == 0 { |
| 70 | + continue; |
| 71 | + } |
| 72 | + let nx = x as isize + dx; |
| 73 | + let ny = y as isize + dy; |
| 74 | + if nx >= 0 && ny >= 0 { |
| 75 | + if let Some(nc) = self.grid.get(nx as usize, ny as usize) { |
| 76 | + if nc == '@' { |
| 77 | + paperrolls += 1; |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + if paperrolls >= 4 { |
| 83 | + break; |
| 84 | + } |
| 85 | + } |
| 86 | + } |
| 87 | + |
| 88 | + self.current_col += 1; |
| 89 | + if paperrolls >= 4 { |
| 90 | + continue; // this was not a valid paperroll |
| 91 | + } |
| 92 | + // else we found a valid paperroll |
| 93 | + return Some((x, y, c)); |
| 94 | + } |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +#[cfg(test)] |
| 99 | +mod tests { |
| 100 | + use super::*; |
| 101 | + |
| 102 | + fn grid() -> Grid { |
| 103 | + Grid::new( |
| 104 | + r#"..@@.@@@@. |
| 105 | + @@@.@.@.@@ |
| 106 | + @@@@@.@.@@ |
| 107 | + @.@@@@..@. |
| 108 | + @@.@@@@.@@ |
| 109 | + .@@@@@@@.@ |
| 110 | + .@.@.@.@@@ |
| 111 | + @.@@@.@@@@ |
| 112 | + .@@@@@@@@. |
| 113 | + @.@.@@@.@."#, |
| 114 | + ) |
| 115 | + } |
| 116 | + |
| 117 | + #[test] |
| 118 | + fn test_grid() { |
| 119 | + let g = grid(); |
| 120 | + |
| 121 | + assert_eq!(g.height(), 10); |
| 122 | + assert_eq!(g.width(), 10); |
| 123 | + |
| 124 | + assert_eq!(g.get(0, 0), Some('.')); |
| 125 | + assert_eq!(g.get(0, 2), Some('@')); |
| 126 | + assert_eq!(g.get(1, 0), Some('@')); |
| 127 | + assert_eq!(g.get(1, 3), Some('.')); |
| 128 | + assert_eq!(g.get(1, 4), Some('@')); |
| 129 | + assert_eq!(g.get(9, 9), Some('.')); |
| 130 | + assert_eq!(g.get(10, 0), None); |
| 131 | + } |
| 132 | + |
| 133 | + #[test] |
| 134 | + fn test_iterator() { |
| 135 | + let g = grid(); |
| 136 | + |
| 137 | + for (x, y, c) in g.paperolls() { |
| 138 | + println!("({x}, {y}) = {c}"); |
| 139 | + } |
| 140 | + |
| 141 | + assert_eq!(g.paperolls().count(), 13); |
| 142 | + } |
| 143 | + |
| 144 | + #[test] |
| 145 | + fn test_input_final() { |
| 146 | + let g = Grid::new(include_str!("../../../input.txt")); |
| 147 | + let paperrolls = g.paperolls().count(); |
| 148 | + println!("Paperolls = {paperrolls}"); |
| 149 | + } |
| 150 | +} |
0 commit comments