This commit is contained in:
Stefan Schwarz 2020-05-13 00:40:38 +02:00
parent ccc5c8038a
commit f12c16a06a
3 changed files with 428 additions and 1 deletions

View file

@ -32,4 +32,8 @@ path = "src/day7/main.rs"
[[bin]]
name = "day9"
path = "src/day9/main.rs"
path = "src/day9/main.rs"
[[bin]]
name = "day10"
path = "src/day10/main.rs"

24
input10 Normal file
View file

@ -0,0 +1,24 @@
.###.#...#.#.##.#.####..
.#....#####...#.######..
#.#.###.###.#.....#.####
##.###..##..####.#.####.
###########.#######.##.#
##########.#########.##.
.#.##.########.##...###.
###.#.##.#####.#.###.###
##.#####.##..###.#.##.#.
.#.#.#####.####.#..#####
.###.#####.#..#..##.#.##
########.##.#...########
.####..##..#.###.###.#.#
....######.##.#.######.#
###.####.######.#....###
############.#.#.##.####
##...##..####.####.#..##
.###.#########.###..#.##
#.##.#.#...##...#####..#
##.#..###############.##
##.###.#####.##.######..
##.#####.#.#.##..#######
...#######.######...####
#....#.#.#.####.#.#.#.##

399
src/day10/main.rs Normal file
View file

@ -0,0 +1,399 @@
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::ops::Sub;
#[derive(Clone, Debug, PartialEq)]
enum Position {
Empty,
Astroid,
}
impl From<&u8> for Position {
fn from(c: &u8) -> Self {
match c {
b'.' => Position::Empty,
b'#' => Position::Astroid,
_ => panic!("invalid input"),
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct XY {
x: isize,
y: isize,
}
impl From<(usize, usize)> for XY {
fn from((x, y): (usize, usize)) -> Self {
XY {
x: x as isize,
y: y as isize,
}
}
}
impl Sub for &XY {
type Output = XY;
fn sub(self, other: &XY) -> Self::Output {
let xy = XY {
x: self.x - other.x,
y: self.y - other.y,
};
xy
}
}
impl PartialOrd for XY {
fn partial_cmp(&self, other: &XY) -> Option<Ordering> {
self.angle().partial_cmp(&other.angle())
}
}
impl Ord for XY {
fn cmp(&self, other: &XY) -> Ordering {
self.angle().partial_cmp(&other.angle()).unwrap()
}
}
impl XY {
fn direction(&self) -> Self {
let d = gcd(self.y, self.x).abs();
if d != 0 {
XY {
x: self.x / d,
y: self.y / d,
}
} else {
self.clone()
}
}
fn distance(&self) -> f64 {
let sum = (self.x.pow(2) + self.y.pow(2)) as f64;
(sum as f64).sqrt()
}
fn angle(&self) -> f64 {
let a = (-self.y as f64).atan2(-self.x as f64) * (180 as f64 / std::f64::consts::PI)
- 90 as f64;
if a < 0 as f64 {
a + 360 as f64
} else {
a
}
}
}
struct MonitoringStation {
map: HashMap<XY, Position>,
}
impl MonitoringStation {
fn laser(&self, root: &XY, skip: usize, n: usize) -> Vec<XY> {
let mut map: HashMap<XY, Vec<XY>> = HashMap::new();
// collect vec for each direction
map = self
.map
.iter()
.filter_map(|(xy, pos)| {
if *pos == Position::Empty {
return None;
}
if xy == root {
return None;
}
let rel = xy - &root;
Some((xy, rel.direction()))
})
.fold(map, |mut acc, (xy, dir)| {
acc.entry(dir).or_insert(vec![]).push(xy.clone());
acc
});
// order angle vecs by distance
map.iter_mut().for_each(|(_, val)| {
val.sort_by(|a, b| {
((root - b).distance().partial_cmp(&(root - a).distance())).unwrap()
});
});
// lets iterate over sorted angles
let mut angles = map.keys().cloned().collect::<Vec<XY>>();
angles.sort();
angles
.iter()
.cycle()
.map(|xy| match map.get_mut(xy) {
Some(xy) => {
if let Some(xy) = xy.pop() {
Some(xy)
} else {
None
}
}
None => None,
})
.flatten()
.skip(skip)
.take(n)
.collect::<Vec<XY>>()
}
fn find(&self) -> (usize, XY) {
let best = (0, XY::from((0, 0)));
self.map
.iter()
.filter(|(_, pos)| **pos == Position::Astroid)
.map(|(root, _)| {
let insight = self
.map
.iter()
// get direction to any of the astroids
.filter_map(|(xy, pos)| {
if *pos == Position::Empty {
return None;
}
let rel = xy - root;
Some(rel.direction())
})
// and keep only one in each direction
.fold(HashSet::new(), |mut acc, xy| {
acc.insert(xy);
acc
})
.len()
- 1;
(insight, root)
})
.fold(best, |acc, astroid| {
if astroid.0 > acc.0 {
return (astroid.0, astroid.1.clone());
}
acc
})
}
}
impl<T> From<T> for MonitoringStation
where
T: BufRead,
{
fn from(reader: T) -> Self {
let map: HashMap<XY, Position> = HashMap::new();
let map = reader
.split(b'\n')
.enumerate()
.flat_map(|(y, line)| {
line.unwrap()
.iter()
.enumerate()
.map(|(x, c)| {
let xy = XY::from((x, y));
let p = Position::from(c);
(xy, p)
})
.collect::<Vec<(XY, Position)>>()
})
.fold(map, |mut map, (xy, p)| {
map.insert(xy.clone(), p.clone());
map
});
MonitoringStation { map }
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let f = File::open("input10")?;
let reader = BufReader::new(f);
let station = MonitoringStation::from(reader);
let best = station.find();
println!("best: {:?}", best);
let lasered = station.laser(&best.1, 199, 1);
let lasered = lasered.iter().next().unwrap();
println!("lasered: {:?}", lasered);
Ok(())
}
fn gcd(x: isize, y: isize) -> isize {
let mut x = x;
let mut y = y;
while y != 0 {
let t = y;
y = x % y;
x = t;
}
x
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn example1() {
let reader = BufReader::new(".#..#\n.....\n#####\n....#\n...##".as_bytes());
let (count, xy) = MonitoringStation::from(reader).find();
assert_eq!(xy, XY { x: 3, y: 4 });
assert_eq!(count, 8);
}
#[test]
fn example2() {
let reader = BufReader::new(
"
......#.#.
#..#.#....
..#######.
.#.#.###..
.#..#.....
..#....#.#
#..#....#.
.##.#..###
##...#..#.
.#....####"
.trim()
.as_bytes(),
);
let (count, xy) = MonitoringStation::from(reader).find();
assert_eq!(xy, XY { x: 5, y: 8 });
assert_eq!(count, 33);
}
#[test]
fn example3() {
let reader = BufReader::new(
"
#.#...#.#.
.###....#.
.#....#...
##.#.#.#.#
....#.#.#.
.##..###.#
..#...##..
..##....##
......#...
.####.###."
.trim()
.as_bytes(),
);
let (count, xy) = MonitoringStation::from(reader).find();
assert_eq!(xy, XY { x: 1, y: 2 });
assert_eq!(count, 35);
}
#[test]
fn example4() {
let reader = BufReader::new(
"
.#..#..###
####.###.#
....###.#.
..###.##.#
##.##.#.#.
....###..#
..#.#..#.#
#..#.#.###
.##...##.#
.....#.#.."
.trim()
.as_bytes(),
);
let (count, xy) = MonitoringStation::from(reader).find();
assert_eq!(xy, XY { x: 6, y: 3 });
assert_eq!(count, 41);
}
#[test]
fn example5() {
let reader = BufReader::new(
"
.#..##.###...#######
##.############..##.
.#.######.########.#
.###.#######.####.#.
#####.##.#.##.###.##
..#####..#.#########
####################
#.####....###.#.#.##
##.#################
#####.##.###..####..
..######..##.#######
####.##.####...##..#
.#####..#.######.###
##...#.##########...
#.##########.#######
.####.#.###.###.#.##
....##.##.###..#####
.#.#.###########.###
#.#.#.#####.####.###
###.##.####.##.#..##"
.trim()
.as_bytes(),
);
let (count, xy) = MonitoringStation::from(reader).find();
assert_eq!(xy, XY { x: 11, y: 13 });
assert_eq!(count, 210);
}
#[test]
fn example6() {
let reader = BufReader::new(
"
.#....#####...#..
##...##.#####..##
##...#...#.#####.
..#.....#...###..
..#.#.....#....##
"
.trim()
.as_bytes(),
);
let ms = MonitoringStation::from(reader);
ms.find();
assert_eq!(
ms.laser(&XY::from((8, 3)), 0, 36),
vec![
XY { x: 8, y: 1 },
XY { x: 9, y: 0 },
XY { x: 9, y: 1 },
XY { x: 10, y: 0 },
XY { x: 9, y: 2 },
XY { x: 11, y: 1 },
XY { x: 12, y: 1 },
XY { x: 11, y: 2 },
XY { x: 15, y: 1 },
XY { x: 12, y: 2 },
XY { x: 13, y: 2 },
XY { x: 14, y: 2 },
XY { x: 15, y: 2 },
XY { x: 12, y: 3 },
XY { x: 16, y: 4 },
XY { x: 15, y: 4 },
XY { x: 10, y: 4 },
XY { x: 4, y: 4 },
XY { x: 2, y: 4 },
XY { x: 2, y: 3 },
XY { x: 0, y: 2 },
XY { x: 1, y: 2 },
XY { x: 0, y: 1 },
XY { x: 1, y: 1 },
XY { x: 5, y: 2 },
XY { x: 1, y: 0 },
XY { x: 5, y: 1 },
XY { x: 6, y: 1 },
XY { x: 6, y: 0 },
XY { x: 7, y: 0 },
XY { x: 8, y: 0 },
XY { x: 10, y: 1 },
XY { x: 14, y: 0 },
XY { x: 16, y: 1 },
XY { x: 13, y: 3 },
XY { x: 14, y: 3 }
]
)
}
}