diff --git a/src/bin/d15p1.rs b/src/bin/d15p1.rs new file mode 100644 index 0000000..a30c2a7 --- /dev/null +++ b/src/bin/d15p1.rs @@ -0,0 +1,39 @@ +use aoc22::{day15, util}; +use itertools::Itertools; + +const ROW: isize = 2000000; + +pub fn main() { + let sensors = day15::parse_sensors(&util::parse_input()); + + let covered = sensors + .iter() + .map(|s| s.covered(ROW)) + .filter(|r| !r.is_empty()) + .sorted_by_key(|r| *r.start()); + + let mut max_x = isize::MIN; + let mut total_covered = 0; + for range in covered { + let (min, max) = range.into_inner(); + if min > max_x { + total_covered += max - min + 1; + } else if max > max_x { + total_covered += max - max_x; + } + max_x = max_x.max(max); + } + + let n_beacons = sensors + .iter() + .map(|s| s.loc_b) + .filter(|b| b.0 == ROW) + .unique() + .count() as isize; + + println!( + "Impossible positions in row {}: {}", + ROW, + total_covered - n_beacons + ); +} diff --git a/src/day15.rs b/src/day15.rs new file mode 100644 index 0000000..b9dfdf1 --- /dev/null +++ b/src/day15.rs @@ -0,0 +1,50 @@ +use std::ops::RangeInclusive; + +use regex::Regex; + +use crate::util::{Coordinate, SignedCoord}; + +#[derive(Debug)] +pub struct Sensor { + pub loc_s: SignedCoord, + pub loc_b: SignedCoord, + pub range: usize, +} + +impl Sensor { + pub fn covered(&self, y: isize) -> RangeInclusive { + let dy = self.loc_s.0.abs_diff(y); + if dy > self.range { + 1..=0 + } else { + let range_x = (self.range - dy) as isize; + (self.loc_s.1 - range_x)..=(self.loc_s.1 + range_x) + } + } +} + +pub fn parse_sensors(input: &String) -> Vec { + let mut result = Vec::new(); + + let re = + Regex::new(r"^Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)$") + .unwrap(); + for line in input.lines() { + let captures = re.captures(line).unwrap(); + let loc_s: SignedCoord = ( + captures.get(2).unwrap().as_str().parse().unwrap(), + captures.get(1).unwrap().as_str().parse().unwrap(), + ); + let loc_b: SignedCoord = ( + captures.get(4).unwrap().as_str().parse().unwrap(), + captures.get(3).unwrap().as_str().parse().unwrap(), + ); + result.push(Sensor { + loc_s, + loc_b, + range: loc_s.manhattan(&loc_b), + }); + } + + result +} diff --git a/src/lib.rs b/src/lib.rs index 8b2fb31..0a502f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ pub mod day11; pub mod day12; pub mod day13; pub mod day14; +pub mod day15; pub mod day2; pub mod day3; pub mod day4; diff --git a/src/util.rs b/src/util.rs index 051583d..8552297 100644 --- a/src/util.rs +++ b/src/util.rs @@ -37,3 +37,39 @@ pub fn max_n(slice: &[T], n: usize) -> Result, ()> { } pub type Coord = (usize, usize); + +pub trait Coordinate { + fn manhattan(&self, other: &Self) -> usize; + fn to_signed(&self) -> SignedCoord; + fn to_unsigned(&self) -> Coord; +} + +impl Coordinate for Coord { + fn manhattan(&self, other: &Self) -> usize { + return self.0.abs_diff(other.0) + self.1.abs_diff(other.1); + } + + fn to_signed(&self) -> SignedCoord { + (self.0 as isize, self.1 as isize) + } + + fn to_unsigned(&self) -> Coord { + *self + } +} + +pub type SignedCoord = (isize, isize); + +impl Coordinate for SignedCoord { + fn manhattan(&self, other: &Self) -> usize { + return self.0.abs_diff(other.0) + self.1.abs_diff(other.1); + } + + fn to_signed(&self) -> SignedCoord { + *self + } + + fn to_unsigned(&self) -> Coord { + (self.0 as usize, self.1 as usize) + } +}