Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
074d8df6c5 | |||
b7025c1dc2 | |||
e8894ad31d |
3 changed files with 354 additions and 1 deletions
|
@ -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
24
input10
Normal file
|
@ -0,0 +1,24 @@
|
|||
.###.#...#.#.##.#.####..
|
||||
.#....#####...#.######..
|
||||
#.#.###.###.#.....#.####
|
||||
##.###..##..####.#.####.
|
||||
###########.#######.##.#
|
||||
##########.#########.##.
|
||||
.#.##.########.##...###.
|
||||
###.#.##.#####.#.###.###
|
||||
##.#####.##..###.#.##.#.
|
||||
.#.#.#####.####.#..#####
|
||||
.###.#####.#..#..##.#.##
|
||||
########.##.#...########
|
||||
.####..##..#.###.###.#.#
|
||||
....######.##.#.######.#
|
||||
###.####.######.#....###
|
||||
############.#.#.##.####
|
||||
##...##..####.####.#..##
|
||||
.###.#########.###..#.##
|
||||
#.##.#.#...##...#####..#
|
||||
##.#..###############.##
|
||||
##.###.#####.##.######..
|
||||
##.#####.#.#.##..#######
|
||||
...#######.######...####
|
||||
#....#.#.#.####.#.#.#.##
|
325
src/day10/main.rs
Normal file
325
src/day10/main.rs
Normal file
|
@ -0,0 +1,325 @@
|
|||
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 angle(&self) -> f64 {
|
||||
(self.y as f64).atan2(self.x as f64) * (180 as f64 / std::f64::consts::PI)
|
||||
}
|
||||
}
|
||||
|
||||
struct MonitoringStation {
|
||||
map: HashMap<XY, Position>,
|
||||
size_x: usize,
|
||||
size_y: usize,
|
||||
}
|
||||
|
||||
impl MonitoringStation {
|
||||
fn laser(&self, root: &XY) -> impl Iterator<Item = XY> + '_ {
|
||||
let mut map: HashMap<XY, Vec<XY>> = HashMap::new();
|
||||
map = self
|
||||
.map
|
||||
.iter()
|
||||
.filter_map(|(xy, pos)| {
|
||||
if *pos == Position::Empty {
|
||||
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
|
||||
});
|
||||
let mut angles = map.keys().cloned().collect::<Vec<XY>>();
|
||||
angles.sort();
|
||||
|
||||
let mut popped = true;
|
||||
let mut cycles = 0;
|
||||
while popped {
|
||||
popped = false;
|
||||
cycles += 1;
|
||||
angles.iter().for_each(|xy| match map.get_mut(xy) {
|
||||
Some(xy) => {
|
||||
if let Some(xy) = xy.pop() {
|
||||
popped = true;
|
||||
println!("{:?}", xy)
|
||||
}
|
||||
}
|
||||
None => (),
|
||||
});
|
||||
}
|
||||
println!("cycles: {}", cycles);
|
||||
self.map.iter().map(|(xy, _)| xy.clone())
|
||||
}
|
||||
|
||||
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 mut size_y = 0;
|
||||
let map = reader
|
||||
.split(b'\n')
|
||||
.enumerate()
|
||||
.flat_map(|(y, line)| {
|
||||
size_y += 1;
|
||||
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
|
||||
});
|
||||
let size_x = map.iter().count() / size_y;
|
||||
MonitoringStation {
|
||||
map,
|
||||
size_x,
|
||||
size_y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
let test = station.laser(&best.1).next();
|
||||
println!("best: {:?}", best);
|
||||
println!("test: {:?}", test);
|
||||
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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue