day10 task 2

This commit is contained in:
Johannes
2019-12-11 20:16:14 +01:00
parent 0f17084f18
commit f28caa727d

View File

@@ -1,3 +1,4 @@
use itertools::Itertools;
use std::collections::HashSet;
#[allow(dead_code)]
@@ -15,13 +16,88 @@ pub fn run() {
.flatten()
.collect();
task1(&asteroids);
task2(&asteroids);
}
fn task1(asteroids: &HashSet<(i32, i32)>) {
let max = asteroids
let (max, _) = get_best_station(&asteroids);
println!(
"Task 1: maximum visible asteroids from another asteroid are {}",
max
);
}
fn task2(asteroids: &HashSet<(i32, i32)>) {
let (_, station) = get_best_station(&asteroids);
println!("Task 2: The station is at {:?}", station);
let mut others = asteroids.clone();
others.remove(&station);
// map to polar coordinate
let mut others: Vec<((i32, i32), (f32, f32))> = others
.into_iter()
.map(|other| (other, to_polar(station, other)))
.collect();
use std::cmp::Ordering;
others.sort_by(|(_, a), (_, b)| {
// sort by angle
if a.0 < b.0 {
Ordering::Less
} else {
Ordering::Greater
}
});
let mut v: Vec<(f32, Vec<_>)> = others
.iter()
.group_by(|(_, (alpha, _))| alpha)
.into_iter()
.map(|(angle, group)| (*angle, group.collect()))
.collect();
let mut i = 0;
let mut shot = Vec::new();
while shot.len() < 200 {
while v[i].1.is_empty() {
i = (i + 1) % v.len();
}
shot.push(v[i].1.remove(0));
i = (i + 1) % v.len();
}
let ((x, y), _) = shot.last().unwrap();
println!("Task 2: {}", x * 100 + y);
}
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()
}
/**
* generate polar coordinate relative to POV.
* rotate angles such that "up" is 0.
*/
fn to_polar(pov: (i32, i32), other: (i32, i32)) -> (f32, f32) {
let mut alpha =
((other.1 - pov.1) as f32).atan2((other.0 - pov.0) as f32) + std::f32::consts::FRAC_PI_2;
if alpha < 0.0 {
alpha += 2.0 * std::f32::consts::PI;
}
(alpha, d(pov, other))
}
fn blocks_view(pov: (i32, i32), target: (i32, i32), occluder: (i32, i32)) -> bool {
if occluder == target {
return false;
}
// using polar coordinates
let (ao, d_o) = to_polar(pov, occluder);
let (at, d_t) = to_polar(pov, target);
(ao - at).abs() <= std::f32::EPSILON && d_t > d_o
}
fn get_best_station(asteroids: &HashSet<(i32, i32)>) -> (usize, (i32, i32)) {
asteroids
.iter()
.map(|asteroid| {
println!("inspecting {:?}", asteroid);
// map to number of other asteroids it sees
let mut others = asteroids.clone();
others.remove(&asteroid);
@@ -32,35 +108,13 @@ fn task1(asteroids: &HashSet<(i32, i32)>) {
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
(count, *asteroid)
})
.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)
.max_by_key(|(count, _)| *count)
.unwrap()
}
mod test {