use std::{
fs::File,
io::{BufRead, BufReader},
path::Path,
};
#[derive(Debug, Clone)]
struct Map {
tiles: Vec<Vec<MapTile>>,
}
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<MapTile> {
(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) -> bool {
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,
_ => {}
}
return true;
}
return false;
}
false
}
}
#[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_two(input: &Path) -> anyhow::Result<i32> {
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 mut any = false;
let mut antinode_x: i32 = other.x as i32 + x_diff;
let mut antinode_y: i32 = other.y as i32 + y_diff;
while antinode_x >= 0
&& antinode_y >= 0
&& map.set_antinode(antinode_x as usize, antinode_y as usize)
{
antinode_x += x_diff;
antinode_y += y_diff;
any = true;
}
if any {
let _ = map.set_antinode(x, y);
}
}
}
}
}
Ok(map
.tiles
.iter()
.flatten()
.filter(|tile| match tile.tile_type {
MapTileType::Antenna { also_antinode, .. } => also_antinode,
MapTileType::Antinode => true,
_ => false,
})
.collect::<Vec<_>>()
.len() as i32)
}