cargo fmt
parent
224ed7e7c4
commit
4fd8a76698
192
src/main.rs
192
src/main.rs
|
@ -1,20 +1,20 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::thread;
|
|
||||||
use std::ops::RangeInclusive;
|
|
||||||
use std::panic;
|
|
||||||
use std::str;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ops::Sub;
|
use std::collections::HashMap;
|
||||||
use std::ops::{Deref};
|
|
||||||
use std::fs;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::fs;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
use std::ops::Sub;
|
||||||
|
use std::panic;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
use std::str;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
#[derive(Default,Debug,PartialEq)]
|
#[derive(Default, Debug, PartialEq)]
|
||||||
struct Location {
|
struct Location {
|
||||||
x: isize,
|
x: isize,
|
||||||
y: isize
|
y: isize,
|
||||||
}
|
}
|
||||||
impl<'a> Sub for &'a Location {
|
impl<'a> Sub for &'a Location {
|
||||||
type Output = isize;
|
type Output = isize;
|
||||||
|
@ -23,29 +23,29 @@ impl<'a> Sub for &'a Location {
|
||||||
(self.x - other.x).abs() + (self.y - other.y).abs()
|
(self.x - other.x).abs() + (self.y - other.y).abs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Default,PartialEq)]
|
#[derive(Default, PartialEq)]
|
||||||
struct Sensor {
|
struct Sensor {
|
||||||
loc: Location,
|
loc: Location,
|
||||||
visibility: usize,
|
visibility: usize,
|
||||||
}
|
}
|
||||||
#[derive(Default,Debug,PartialEq)]
|
#[derive(Default, Debug, PartialEq)]
|
||||||
struct Beacon {
|
struct Beacon {
|
||||||
loc: Location
|
loc: Location,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ComparableRange(RangeInclusive<isize>);
|
struct ComparableRange(RangeInclusive<isize>);
|
||||||
|
|
||||||
impl ComparableRange {
|
impl ComparableRange {
|
||||||
pub fn intersects(&self, other:&ComparableRange) -> bool {
|
pub fn intersects(&self, other: &ComparableRange) -> bool {
|
||||||
self.contains(other.start()) ||
|
self.contains(other.start()) || other.contains(self.start())
|
||||||
other.contains(self.start())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intersection(&self, other:&ComparableRange) -> ComparableRange {
|
pub fn intersection(&self, other: &ComparableRange) -> ComparableRange {
|
||||||
match self.intersects(other) {
|
match self.intersects(other) {
|
||||||
false => panic!("Ranges do not intersect"),
|
false => panic!("Ranges do not intersect"),
|
||||||
true => ComparableRange(cmp::min(*self.start(), *other.start())..=cmp::max(*self.end(),*other.end()))
|
true => ComparableRange(
|
||||||
|
cmp::min(*self.start(), *other.start())..=cmp::max(*self.end(), *other.end()),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@ impl Deref for ComparableRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PART_1_CONST:isize = 2000000;
|
const PART_1_CONST: isize = 2000000;
|
||||||
const PART_2_CONST:isize = 4000000;
|
const PART_2_CONST: isize = 4000000;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
run();
|
run();
|
||||||
|
@ -71,7 +71,10 @@ fn run() {
|
||||||
process_part_2(contents.lines());
|
process_part_2(contents.lines());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_part_2<'a, T>(lines: T) where T: IntoIterator<Item = &'a str> {
|
fn process_part_2<'a, T>(lines: T)
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = &'a str>,
|
||||||
|
{
|
||||||
let (sensors, worker_bundles) = prep_work(lines);
|
let (sensors, worker_bundles) = prep_work(lines);
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
|
@ -81,13 +84,18 @@ fn process_part_2<'a, T>(lines: T) where T: IntoIterator<Item = &'a str> {
|
||||||
let worker_bundles = Arc::clone(&bundle_storage);
|
let worker_bundles = Arc::clone(&bundle_storage);
|
||||||
let sensors = Arc::clone(&sensor_storage);
|
let sensors = Arc::clone(&sensor_storage);
|
||||||
let bounds = 0..=PART_2_CONST;
|
let bounds = 0..=PART_2_CONST;
|
||||||
let handle = thread::spawn(move || {do_part2_work(worker_bundles, worker, &bounds, sensors)} );
|
let handle = thread::spawn(move || do_part2_work(worker_bundles, worker, &bounds, sensors));
|
||||||
handles.push(handle);
|
handles.push(handle);
|
||||||
}
|
}
|
||||||
handles.into_iter().for_each(|handle|{ handle.join();});
|
handles.into_iter().for_each(|handle| {
|
||||||
|
handle.join();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prep_work<'a, T>(lines: T) -> (Vec<Sensor>, HashMap<isize, Vec<usize>>) where T: IntoIterator<Item = &'a str> {
|
fn prep_work<'a, T>(lines: T) -> (Vec<Sensor>, HashMap<isize, Vec<usize>>)
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = &'a str>,
|
||||||
|
{
|
||||||
let (sensors, _) = parse(lines);
|
let (sensors, _) = parse(lines);
|
||||||
let mut worker_bundles = HashMap::new();
|
let mut worker_bundles = HashMap::new();
|
||||||
for worker in 0..99 {
|
for worker in 0..99 {
|
||||||
|
@ -97,38 +105,56 @@ fn prep_work<'a, T>(lines: T) -> (Vec<Sensor>, HashMap<isize, Vec<usize>>) where
|
||||||
work_item.push(chunk_s);
|
work_item.push(chunk_s);
|
||||||
}
|
}
|
||||||
worker_bundles.insert(worker, work_item);
|
worker_bundles.insert(worker, work_item);
|
||||||
};
|
}
|
||||||
// remainder worker
|
// remainder worker
|
||||||
let worker = 99;
|
let worker = 99;
|
||||||
let mut work_item = Vec::new();
|
let mut work_item = Vec::new();
|
||||||
for sensor in &sensors {
|
for sensor in &sensors {
|
||||||
let chunk_s = sensor.visibility / 100;
|
let chunk_s = sensor.visibility / 100;
|
||||||
let remainder = sensor.visibility - (99*chunk_s);
|
let remainder = sensor.visibility - (99 * chunk_s);
|
||||||
work_item.push(remainder);
|
work_item.push(remainder);
|
||||||
}
|
}
|
||||||
worker_bundles.insert(worker, work_item);
|
worker_bundles.insert(worker, work_item);
|
||||||
(sensors, worker_bundles)
|
(sensors, worker_bundles)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_part2_work(worker_bundles: Arc<HashMap<isize, Vec<usize>>>, worker: isize, bounds: &RangeInclusive<isize>, sensors: Arc<Vec<Sensor>>) {
|
fn do_part2_work(
|
||||||
worker_bundles.get(&worker).and_then(
|
worker_bundles: Arc<HashMap<isize, Vec<usize>>>,
|
||||||
|x| {
|
worker: isize,
|
||||||
|
bounds: &RangeInclusive<isize>,
|
||||||
|
sensors: Arc<Vec<Sensor>>,
|
||||||
|
) {
|
||||||
|
worker_bundles.get(&worker).and_then(|x| {
|
||||||
for (work_idx, work_item) in x.into_iter().enumerate() {
|
for (work_idx, work_item) in x.into_iter().enumerate() {
|
||||||
for idx in 0..*work_item {
|
for idx in 0..*work_item {
|
||||||
let dist = isize::try_from(idx).unwrap() + worker*isize::try_from(*work_item).unwrap();
|
let dist =
|
||||||
|
isize::try_from(idx).unwrap() + worker * isize::try_from(*work_item).unwrap();
|
||||||
let sensor = &sensors[work_idx];
|
let sensor = &sensors[work_idx];
|
||||||
let visibility = isize::try_from(sensor.visibility).unwrap();
|
let visibility = isize::try_from(sensor.visibility).unwrap();
|
||||||
let x_left = sensor.loc.x-dist;
|
let x_left = sensor.loc.x - dist;
|
||||||
let x_right = sensor.loc.x+dist;
|
let x_right = sensor.loc.x + dist;
|
||||||
let y_lower = sensor.loc.y + (visibility-dist) + 1;
|
let y_lower = sensor.loc.y + (visibility - dist) + 1;
|
||||||
let y_upper = sensor.loc.y - (visibility-dist) - 1;
|
let y_upper = sensor.loc.y - (visibility - dist) - 1;
|
||||||
[(x_left, y_upper), (x_right, y_upper), (x_left, y_lower), (x_right, y_lower)].into_iter().for_each(|coord| {
|
[
|
||||||
if !(bounds).contains(&coord.0) || !(bounds).contains(&coord.1) { return }
|
(x_left, y_upper),
|
||||||
if (sensors).iter().all(|tgt_sensor| {
|
(x_right, y_upper),
|
||||||
&tgt_sensor.loc - &Location{x:coord.0, y:coord.1} > isize::try_from(tgt_sensor.visibility).unwrap()
|
(x_left, y_lower),
|
||||||
|
(x_right, y_lower),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|coord| {
|
||||||
|
if !(bounds).contains(&coord.0) || !(bounds).contains(&coord.1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if sensors.iter().all(|tgt_sensor| {
|
||||||
|
&tgt_sensor.loc
|
||||||
|
- &Location {
|
||||||
|
x: coord.0,
|
||||||
|
y: coord.1,
|
||||||
|
}
|
||||||
|
> isize::try_from(tgt_sensor.visibility).unwrap()
|
||||||
}) {
|
}) {
|
||||||
println!("{:?}", coord.0*4000000+coord.1);
|
println!("{:?}", coord.0 * 4000000 + coord.1);
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -138,40 +164,61 @@ fn do_part2_work(worker_bundles: Arc<HashMap<isize, Vec<usize>>>, worker: isize,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_part_1<'a, T>(lines: T) where T: IntoIterator<Item = &'a str> {
|
fn process_part_1<'a, T>(lines: T)
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = &'a str>,
|
||||||
|
{
|
||||||
let (sensors, beacons) = parse(lines);
|
let (sensors, beacons) = parse(lines);
|
||||||
let target_row = PART_1_CONST;
|
let target_row = PART_1_CONST;
|
||||||
let mut impossible_ranges:Vec<ComparableRange> = Vec::new();
|
let mut impossible_ranges: Vec<ComparableRange> = Vec::new();
|
||||||
for sensor in (&sensors).into_iter() {
|
for sensor in (&sensors).into_iter() {
|
||||||
let visibility = isize::try_from(sensor.visibility).unwrap();
|
let visibility = isize::try_from(sensor.visibility).unwrap();
|
||||||
let dist_to_target = &sensor.loc - &(Location {x:sensor.loc.x, y:target_row});
|
let dist_to_target = &sensor.loc
|
||||||
if dist_to_target > visibility { continue }
|
- &(Location {
|
||||||
|
x: sensor.loc.x,
|
||||||
|
y: target_row,
|
||||||
|
});
|
||||||
|
if dist_to_target > visibility {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let impossible_width = visibility - dist_to_target;
|
let impossible_width = visibility - dist_to_target;
|
||||||
let impossible_range = sensor.loc.x-impossible_width..=sensor.loc.x+impossible_width;
|
let impossible_range = sensor.loc.x - impossible_width..=sensor.loc.x + impossible_width;
|
||||||
impossible_ranges.push(ComparableRange(impossible_range));
|
impossible_ranges.push(ComparableRange(impossible_range));
|
||||||
};
|
}
|
||||||
impossible_ranges.sort_by(|a,b| a.start().cmp(b.start()));
|
impossible_ranges.sort_by(|a, b| a.start().cmp(b.start()));
|
||||||
|
|
||||||
merge(&mut impossible_ranges);
|
merge(&mut impossible_ranges);
|
||||||
|
|
||||||
let beacons_in_row = beacons.into_iter().filter(|b| {
|
let beacons_in_row = beacons
|
||||||
|
.into_iter()
|
||||||
|
.filter(|b| {
|
||||||
if b.loc.y != target_row {
|
if b.loc.y != target_row {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
(&impossible_ranges).into_iter().any(|r| r.contains(&b.loc.x))
|
(&impossible_ranges)
|
||||||
}).count();
|
.into_iter()
|
||||||
println!("{}", impossible_ranges.into_iter().map(|r| r.end()-r.start()+1).sum::<isize>()-isize::try_from(beacons_in_row).unwrap());
|
.any(|r| r.contains(&b.loc.x))
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
impossible_ranges
|
||||||
|
.into_iter()
|
||||||
|
.map(|r| r.end() - r.start() + 1)
|
||||||
|
.sum::<isize>()
|
||||||
|
- isize::try_from(beacons_in_row).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge(impossible_ranges: &mut Vec<ComparableRange>) {
|
fn merge(impossible_ranges: &mut Vec<ComparableRange>) {
|
||||||
let mut merge_idx = 0;
|
let mut merge_idx = 0;
|
||||||
while merge_idx < impossible_ranges.len()-1 {
|
while merge_idx < impossible_ranges.len() - 1 {
|
||||||
if (*impossible_ranges)[merge_idx].intersects(&impossible_ranges[merge_idx+1]) {
|
if (*impossible_ranges)[merge_idx].intersects(&impossible_ranges[merge_idx + 1]) {
|
||||||
let r1 = &impossible_ranges[merge_idx];
|
let r1 = &impossible_ranges[merge_idx];
|
||||||
let r2 = &impossible_ranges[merge_idx+1];
|
let r2 = &impossible_ranges[merge_idx + 1];
|
||||||
impossible_ranges.insert(merge_idx+2,r1.intersection(&r2));
|
impossible_ranges.insert(merge_idx + 2, r1.intersection(&r2));
|
||||||
impossible_ranges.remove(merge_idx+1);
|
impossible_ranges.remove(merge_idx + 1);
|
||||||
impossible_ranges.remove(merge_idx);
|
impossible_ranges.remove(merge_idx);
|
||||||
} else {
|
} else {
|
||||||
merge_idx += 1;
|
merge_idx += 1;
|
||||||
|
@ -180,27 +227,32 @@ fn merge(impossible_ranges: &mut Vec<ComparableRange>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse<'a, T>(lines: T) -> (Vec<Sensor>, Vec<Beacon>)
|
fn parse<'a, T>(lines: T) -> (Vec<Sensor>, Vec<Beacon>)
|
||||||
where T: IntoIterator<Item = &'a str> {
|
where
|
||||||
|
T: IntoIterator<Item = &'a str>,
|
||||||
|
{
|
||||||
let mut sensors = Vec::new();
|
let mut sensors = Vec::new();
|
||||||
let mut beacons = Vec::new();
|
let mut beacons = Vec::new();
|
||||||
let extract_ints = |s: &str| {
|
let extract_ints = |s: &str| {
|
||||||
s
|
s.split(&['=', ',', ':'][..])
|
||||||
.split(&['=',',',':'][..])
|
|
||||||
.filter_map(|s| s.parse::<isize>().ok())
|
.filter_map(|s| s.parse::<isize>().ok())
|
||||||
.collect::<Vec<isize>>()
|
.collect::<Vec<isize>>()
|
||||||
};
|
};
|
||||||
let loc_sets = lines.into_iter().map(extract_ints);
|
let loc_sets = lines.into_iter().map(extract_ints);
|
||||||
loc_sets.for_each(|loc_set| {
|
loc_sets.for_each(|loc_set| {
|
||||||
let sensor_loc = Location {x:loc_set[0], y:loc_set[1]};
|
let sensor_loc = Location {
|
||||||
let beacon_loc = Location {x:loc_set[2], y:loc_set[3]};
|
x: loc_set[0],
|
||||||
let visibility = usize::try_from(&sensor_loc-&beacon_loc).unwrap();
|
y: loc_set[1],
|
||||||
sensors.push(Sensor{
|
|
||||||
loc: sensor_loc,
|
|
||||||
visibility: visibility
|
|
||||||
});
|
|
||||||
let beacon = Beacon{
|
|
||||||
loc: beacon_loc
|
|
||||||
};
|
};
|
||||||
|
let beacon_loc = Location {
|
||||||
|
x: loc_set[2],
|
||||||
|
y: loc_set[3],
|
||||||
|
};
|
||||||
|
let visibility = usize::try_from(&sensor_loc - &beacon_loc).unwrap();
|
||||||
|
sensors.push(Sensor {
|
||||||
|
loc: sensor_loc,
|
||||||
|
visibility: visibility,
|
||||||
|
});
|
||||||
|
let beacon = Beacon { loc: beacon_loc };
|
||||||
if !beacons.contains(&beacon) {
|
if !beacons.contains(&beacon) {
|
||||||
beacons.push(beacon);
|
beacons.push(beacon);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue