better Pos
This commit is contained in:
parent
bcefb1b68f
commit
651ccb9cba
11 changed files with 268 additions and 318 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use super::template::{DayTrait, ResultType};
|
||||
use crate::common::{
|
||||
parser::{eol_terminated, extract_result, ignore, trim0},
|
||||
pos::Pos,
|
||||
pos::Pos2D,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use nom::{
|
||||
|
|
@ -44,7 +44,7 @@ impl DayTrait for Day {
|
|||
.iter()
|
||||
.tuple_combinations()
|
||||
.filter_map(|(first, second)| first.cross(second))
|
||||
.filter(|pos| sensors.iter().all(|sensor| !sensor.contains(pos)))
|
||||
.filter(|pos| sensors.iter().all(|sensor| !sensor.contains(*pos)))
|
||||
.dedup()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ impl DayTrait for Day {
|
|||
}
|
||||
|
||||
impl Day {
|
||||
fn parse_all(lines: &str) -> Result<(HashSet<Sensor>, HashSet<Pos<i64>>), SensorError> {
|
||||
fn parse_all(lines: &str) -> Result<(HashSet<Sensor>, HashSet<Pos2D<i64>>), SensorError> {
|
||||
let data = extract_result(many0(eol_terminated(Sensor::parse)))(lines)?;
|
||||
|
||||
let mut sensors = HashSet::new();
|
||||
|
|
@ -70,7 +70,11 @@ impl Day {
|
|||
Ok((sensors, beacons))
|
||||
}
|
||||
|
||||
fn count_coverage_at(sensors: &HashSet<Sensor>, beacons: &HashSet<Pos<i64>>, row: i64) -> i64 {
|
||||
fn count_coverage_at(
|
||||
sensors: &HashSet<Sensor>,
|
||||
beacons: &HashSet<Pos2D<i64>>,
|
||||
row: i64,
|
||||
) -> i64 {
|
||||
let ranges = sensors
|
||||
.iter()
|
||||
.filter_map(|sensor| sensor.range_at(row))
|
||||
|
|
@ -117,7 +121,7 @@ impl From<Err<Error<&str>>> for SensorError {
|
|||
|
||||
#[derive(Debug)]
|
||||
struct Line {
|
||||
start: Pos<i64>,
|
||||
start: Pos2D<i64>,
|
||||
is_up: bool,
|
||||
steps: i64,
|
||||
}
|
||||
|
|
@ -139,16 +143,16 @@ impl Line {
|
|||
if one.pos.y() < two.pos.y() {
|
||||
is_up = true;
|
||||
if one.pos.y() + one.radius <= two.pos.y() {
|
||||
start = Pos::new(one.pos.x(), one.pos.y() + one.radius + 1);
|
||||
start = Pos2D::new(one.pos.x(), one.pos.y() + one.radius + 1);
|
||||
} else {
|
||||
start = Pos::new(two.pos.x() - two.radius - 1, two.pos.y());
|
||||
start = Pos2D::new(two.pos.x() - two.radius - 1, two.pos.y());
|
||||
}
|
||||
} else {
|
||||
is_up = false;
|
||||
if one.pos.y() - one.radius >= two.pos.y() {
|
||||
start = Pos::new(one.pos.x(), one.pos.y() - one.radius - 1);
|
||||
start = Pos2D::new(one.pos.x(), one.pos.y() - one.radius - 1);
|
||||
} else {
|
||||
start = Pos::new(two.pos.x() - two.radius - 1, two.pos.y());
|
||||
start = Pos2D::new(two.pos.x() - two.radius - 1, two.pos.y());
|
||||
}
|
||||
}
|
||||
let steps = two.pos.x().min(one.pos.x() + one.radius) - start.x();
|
||||
|
|
@ -160,7 +164,7 @@ impl Line {
|
|||
})
|
||||
}
|
||||
|
||||
fn cross(&self, other: &Line) -> Option<Pos<i64>> {
|
||||
fn cross(&self, other: &Line) -> Option<Pos2D<i64>> {
|
||||
if self.is_up == other.is_up {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -181,7 +185,7 @@ impl Line {
|
|||
return None;
|
||||
}
|
||||
|
||||
let pos = top_down.start + Pos::splat(r);
|
||||
let pos = top_down.start + Pos2D::splat(r);
|
||||
Some(pos)
|
||||
}
|
||||
}
|
||||
|
|
@ -227,7 +231,7 @@ impl Range {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
|
||||
struct Sensor {
|
||||
pos: Pos<i64>,
|
||||
pos: Pos2D<i64>,
|
||||
radius: i64,
|
||||
}
|
||||
|
||||
|
|
@ -239,21 +243,21 @@ impl Sensor {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_pos(input: &str) -> IResult<&str, Pos<i64>> {
|
||||
fn parse_pos(input: &str) -> IResult<&str, Pos2D<i64>> {
|
||||
let (input, (x, y)) = separated_pair(
|
||||
Sensor::component("x"),
|
||||
trim0(char(',')),
|
||||
Sensor::component("y"),
|
||||
)(input)?;
|
||||
Ok((input, Pos::new(x, y)))
|
||||
Ok((input, Pos2D::new(x, y)))
|
||||
}
|
||||
|
||||
pub fn parse(input: &str) -> IResult<&str, (Sensor, Pos<i64>)> {
|
||||
pub fn parse(input: &str) -> IResult<&str, (Sensor, Pos2D<i64>)> {
|
||||
let input = ignore(tag("Sensor at"))(input)?;
|
||||
let (input, pos) = trim0(Sensor::parse_pos)(input)?;
|
||||
let input = ignore(tag(": closest beacon is at"))(input)?;
|
||||
let (input, beacon) = trim0(Sensor::parse_pos)(input)?;
|
||||
let radius = pos.taxicab(&beacon);
|
||||
let radius = pos.taxicab_between(beacon);
|
||||
Ok((input, (Sensor { pos, radius }, beacon)))
|
||||
}
|
||||
|
||||
|
|
@ -268,12 +272,12 @@ impl Sensor {
|
|||
}
|
||||
|
||||
pub fn border_distance(&self, other: &Sensor) -> i64 {
|
||||
let distance = self.pos.taxicab(&other.pos);
|
||||
let distance = self.pos.taxicab_between(other.pos);
|
||||
distance - self.radius - other.radius
|
||||
}
|
||||
|
||||
pub fn contains(&self, pos: &Pos<i64>) -> bool {
|
||||
self.pos.taxicab(pos) <= self.radius
|
||||
pub fn contains(&self, pos: Pos2D<i64>) -> bool {
|
||||
self.pos.taxicab_between(pos) <= self.radius
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,10 +291,10 @@ mod test {
|
|||
let input = "Sensor at x=2, y=18: closest beacon is at x=-2, y=15";
|
||||
let expected = (
|
||||
Sensor {
|
||||
pos: Pos::new(2, 18),
|
||||
pos: Pos2D::new(2, 18),
|
||||
radius: 7,
|
||||
},
|
||||
Pos::new(-2, 15),
|
||||
Pos2D::new(-2, 15),
|
||||
);
|
||||
let result = extract_result(Sensor::parse)(input)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
@ -301,7 +305,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_width() {
|
||||
let sensor = Sensor {
|
||||
pos: Pos::new(8, 7),
|
||||
pos: Pos2D::new(8, 7),
|
||||
radius: 9,
|
||||
};
|
||||
assert_eq!(sensor.range_at(17), None);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue