use std::{ fs::File, io::{BufRead, BufReader}, path::Path, }; #[derive(Debug, Clone)] struct Map { tiles: Vec>, } impl Map { fn _print(&self) { for row in &self.tiles { for tile in row { match tile.tile_type { MapTileType::Empty => print!(". "), MapTileType::Antenna { frequency, also_antinode, } => print!("{}{}", frequency, if also_antinode { "!" } else { " " }), MapTileType::Antinode => print!("# "), } } println!(); } } fn find_antennas(&self, freq: char) -> Vec { (self .tiles .iter() .flatten() .filter(|tile| match tile.tile_type { MapTileType::Antenna { frequency, .. } => frequency == freq, _ => false, }) .cloned()) .collect() } fn set_antinode(&mut self, x: usize, y: usize) { if let Some(row) = self.tiles.get_mut(y) { if let Some(tile) = row.get_mut(x) { match tile.tile_type { MapTileType::Empty => self.tiles[y][x].tile_type = MapTileType::Antinode, MapTileType::Antenna { ref mut also_antinode, .. } => *also_antinode = true, _ => {} } } } } } #[derive(Debug, Clone)] struct MapTile { x: usize, y: usize, tile_type: MapTileType, } #[derive(Debug, Clone)] enum MapTileType { Empty, Antenna { also_antinode: bool, frequency: char, }, Antinode, } pub fn part_one(input: &Path) -> anyhow::Result { let reader = BufReader::new(File::open(input)?); let mut map: Map = Map { tiles: vec![] }; for (y, line) in reader.lines().enumerate() { let mut row = vec![]; for (x, c) in line?.chars().enumerate() { match c { '.' => row.push(MapTile { x, y, tile_type: MapTileType::Empty, }), _ => row.push(MapTile { x, y, tile_type: MapTileType::Antenna { frequency: c, also_antinode: false, }, }), } } map.tiles.push(row); } for (y, row) in map.clone().tiles.iter().enumerate() { for (x, tile) in row.iter().enumerate() { if let MapTileType::Antenna { frequency, .. } = tile.tile_type { let others = map.find_antennas(frequency); for other in others { let x_diff: i32 = -(x as i32 - other.x as i32); let y_diff: i32 = -(y as i32 - other.y as i32); if y_diff == 0 && x_diff == 0 { continue; } let antinode_x: i32 = other.x as i32 + x_diff; let antinode_y: i32 = other.y as i32 + y_diff; if antinode_x >= 0 && antinode_y >= 0 { map.set_antinode(antinode_x as usize, antinode_y as usize); } } } } } Ok(map .tiles .iter() .flatten() .filter(|tile| match tile.tile_type { MapTileType::Antenna { also_antinode, .. } => also_antinode, MapTileType::Antinode => true, _ => false, }) .collect::>() .len() as i32) }