use std::collections::HashSet; #[allow(dead_code)] pub fn run() { let asteroids: HashSet<(i32, i32)> = std::fs::read_to_string("input/day10.txt") .unwrap() .lines() .enumerate() .map(|(y, line)| { line.chars() .enumerate() .filter(|(_, it)| *it == '#') .map(move |(x, _)| (x as i32, y as i32)) }) .flatten() .collect(); task1(&asteroids); } fn task1(asteroids: &HashSet<(i32, i32)>) { let max = asteroids .iter() .map(|asteroid| { println!("inspecting {:?}", asteroid); // map to number of other asteroids it sees let mut others = asteroids.clone(); others.remove(&asteroid); // count those asteroids that are not blocked by another let count = others .iter() .filter(|target| { let blocker = others .iter() .find(|occluder| blocks_view(*asteroid, **target, **occluder)); if let Some(occluder) = blocker { println!("{:?} -> X{:?}X -> {:?}", asteroid, occluder, target); } !blocker.is_some() }) .inspect(|target| println!("sees {:?}", target)) .count(); println!("{:?}: {}", asteroid, count); count }) .max() .unwrap(); println!( "Task 1: maximum visible asteroids from another asteroid are {}", max ); } fn blocks_view(pov: (i32, i32), target: (i32, i32), occluder: (i32, i32)) -> bool { if occluder == target { return false; } fn d(a: (i32, i32), b: (i32, i32)) -> f32 { ((a.0 - b.0) as f32).powi(2) + ((a.1 - b.1) as f32).powi(2).sqrt() } // using polar coordinates let alpha_occluder = ((occluder.1 - pov.1) as f32).atan2((occluder.0 - pov.0) as f32); let alpha_target = ((target.1 - pov.1) as f32).atan2((target.0 - pov.0) as f32); (alpha_occluder - alpha_target).abs() <= std::f32::EPSILON && d(pov, target) > d(pov, occluder) } mod test { #[test] fn block_test() { assert_eq!(true, super::blocks_view((3, 4), (1, 0), (2, 2))); assert_eq!(false, super::blocks_view((3, 4), (2, 2), (1, 0))); assert_eq!(false, super::blocks_view((3, 4), (1, 0), (1, 2))); assert_eq!(true, super::blocks_view((4, 4), (4, 0), (4, 3))); assert_eq!(false, super::blocks_view((3, 2), (1, 0), (4, 3))); } }