day10
This commit is contained in:
parent
ccc5c8038a
commit
f12c16a06a
3 changed files with 428 additions and 1 deletions
|
@ -32,4 +32,8 @@ path = "src/day7/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "day9"
|
name = "day9"
|
||||||
path = "src/day9/main.rs"
|
path = "src/day9/main.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "day10"
|
||||||
|
path = "src/day10/main.rs"
|
24
input10
Normal file
24
input10
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
.###.#...#.#.##.#.####..
|
||||||
|
.#....#####...#.######..
|
||||||
|
#.#.###.###.#.....#.####
|
||||||
|
##.###..##..####.#.####.
|
||||||
|
###########.#######.##.#
|
||||||
|
##########.#########.##.
|
||||||
|
.#.##.########.##...###.
|
||||||
|
###.#.##.#####.#.###.###
|
||||||
|
##.#####.##..###.#.##.#.
|
||||||
|
.#.#.#####.####.#..#####
|
||||||
|
.###.#####.#..#..##.#.##
|
||||||
|
########.##.#...########
|
||||||
|
.####..##..#.###.###.#.#
|
||||||
|
....######.##.#.######.#
|
||||||
|
###.####.######.#....###
|
||||||
|
############.#.#.##.####
|
||||||
|
##...##..####.####.#..##
|
||||||
|
.###.#########.###..#.##
|
||||||
|
#.##.#.#...##...#####..#
|
||||||
|
##.#..###############.##
|
||||||
|
##.###.#####.##.######..
|
||||||
|
##.#####.#.#.##..#######
|
||||||
|
...#######.######...####
|
||||||
|
#....#.#.#.####.#.#.#.##
|
399
src/day10/main.rs
Normal file
399
src/day10/main.rs
Normal 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 }
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue