[TASK] Solved day 15 part 2 (but it's not very fast yet)
This commit is contained in:
19
.run/run-day-15.run.xml
Normal file
19
.run/run-day-15.run.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="run-day-15" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
|
<option name="command" value="run --package advent-of-code-2022-rust --bin advent-of-code-2022-rust -- -d 15" />
|
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="requiredFeatures" value="true" />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="emulateTerminal" value="false" />
|
||||||
|
<option name="withSudo" value="false" />
|
||||||
|
<option name="buildTarget" value="REMOTE" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
|
<envs />
|
||||||
|
<option name="isRedirectInput" value="false" />
|
||||||
|
<option name="redirectInputPath" value="" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
102
src/day15.rs
102
src/day15.rs
@@ -7,7 +7,7 @@ use crate::{day_solver::DaySolver, util::Coord};
|
|||||||
use super::util;
|
use super::util;
|
||||||
|
|
||||||
pub struct Day15 {
|
pub struct Day15 {
|
||||||
beacon_scanners: Vec<BeaconScanner>
|
beacon_scanners: Vec<BeaconSensor>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Day15 {
|
impl Day15 {
|
||||||
@@ -23,49 +23,34 @@ impl Day15 {
|
|||||||
return Day15 {
|
return Day15 {
|
||||||
beacon_scanners: lines.iter().map(|s| {
|
beacon_scanners: lines.iter().map(|s| {
|
||||||
let cap = re.captures_iter(s).next().unwrap();
|
let cap = re.captures_iter(s).next().unwrap();
|
||||||
BeaconScanner {
|
BeaconSensor::new(
|
||||||
sensor: Coord { x: cap[1].parse::<i32>().unwrap(), y: cap[2].parse::<i32>().unwrap() },
|
Coord { x: cap[1].parse::<i32>().unwrap(), y: cap[2].parse::<i32>().unwrap() },
|
||||||
closest_beacon: Coord { x: cap[3].parse::<i32>().unwrap(), y: cap[4].parse::<i32>().unwrap() }
|
Coord { x: cap[3].parse::<i32>().unwrap(), y: cap[4].parse::<i32>().unwrap() }
|
||||||
}
|
)
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
fn find_ranges_without_beacons_at_y(&mut self, y: i32) -> Vec<Range> {
|
||||||
|
self.beacon_scanners.iter().filter_map(|bs| {
|
||||||
impl DaySolver for Day15 {
|
let dist_to_check_y = bs.sensor.y.abs_diff(y) as i32;
|
||||||
|
let coverage_width = bs.distance - dist_to_check_y;
|
||||||
|
|
||||||
fn solve_part1(&mut self) -> String {
|
|
||||||
|
|
||||||
// print!("{:?}", self.beacon_scanners);
|
|
||||||
|
|
||||||
let check_y = if self.beacon_scanners.len() < 20 { 10 } else { 2_000_000 };
|
|
||||||
|
|
||||||
let mut ranges_covered: Vec<Range> = self.beacon_scanners.iter().filter_map(|bs| {
|
|
||||||
let sensor_dist = bs.sensor.manhattan_dist(&bs.closest_beacon);
|
|
||||||
let dist_to_check_y = bs.sensor.y.abs_diff(check_y) as i32;
|
|
||||||
let coverage_width = sensor_dist - dist_to_check_y;
|
|
||||||
// println!("Sensor at {},{} sees beacon {},{} at distance {}, and distance {} to check_y. So it covers {} cells",
|
// println!("Sensor at {},{} sees beacon {},{} at distance {}, and distance {} to check_y. So it covers {} cells",
|
||||||
// bs.sensor.x, bs.sensor.y, bs.closest_beacon.x, bs.closest_beacon.y, sensor_dist, dist_to_check_y, coverage_width);
|
// bs.sensor.x, bs.sensor.y, bs.closest_beacon.x, bs.closest_beacon.y, sensor_dist, dist_to_check_y, coverage_width);
|
||||||
if coverage_width < 0 {
|
if coverage_width < 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// println!("Adding");
|
// println!("Adding");
|
||||||
Some(Range{
|
Some(Range {
|
||||||
min: bs.sensor.x - coverage_width,
|
min: bs.sensor.x - coverage_width,
|
||||||
max: bs.sensor.x + coverage_width
|
max: bs.sensor.x + coverage_width
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect()
|
||||||
|
|
||||||
if ranges_covered.is_empty() {
|
|
||||||
return 0.to_string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// println!("Ranges covered: {:?}", ranges_covered);
|
fn merge_overlapping_ranges(ranges_covered: &mut Vec<Range>) -> Vec<Range> {
|
||||||
|
// Now we need to merge all overlapping ranges into one, so we don't count any double ones:
|
||||||
// Now we need to merge all overlapping rangen into one, so we don't count any double ones:
|
|
||||||
// Note: there can be no beacons inside the sensor ranges, because if there were, the sensor
|
// Note: there can be no beacons inside the sensor ranges, because if there were, the sensor
|
||||||
// would pick up that one and have a smaller range
|
// would pick up that one and have a smaller range
|
||||||
ranges_covered.sort_by_key(|r| r.min);
|
ranges_covered.sort_by_key(|r| r.min);
|
||||||
@@ -85,6 +70,31 @@ impl DaySolver for Day15 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
merged_ranges.push(current_range);
|
merged_ranges.push(current_range);
|
||||||
|
merged_ranges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DaySolver for Day15 {
|
||||||
|
|
||||||
|
|
||||||
|
fn solve_part1(&mut self) -> String {
|
||||||
|
|
||||||
|
// print!("{:?}", self.beacon_scanners);
|
||||||
|
|
||||||
|
// If we sort the beacon scanner by their x-coordinate, range-merging will be faster later on in the process
|
||||||
|
self.beacon_scanners.sort_by_key(|bs| bs.sensor.x);
|
||||||
|
|
||||||
|
let check_y = if self.beacon_scanners.len() < 20 { 10 } else { 2_000_000 };
|
||||||
|
|
||||||
|
let mut ranges_covered = self.find_ranges_without_beacons_at_y(check_y);
|
||||||
|
|
||||||
|
if ranges_covered.is_empty() {
|
||||||
|
return 0.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// println!("Ranges covered: {:?}", ranges_covered);
|
||||||
|
|
||||||
|
let merged_ranges = Self::merge_overlapping_ranges(&mut ranges_covered);
|
||||||
|
|
||||||
let beacons_on_check_y = self.beacon_scanners.iter()
|
let beacons_on_check_y = self.beacon_scanners.iter()
|
||||||
.filter(|bs| bs.closest_beacon.y == check_y)
|
.filter(|bs| bs.closest_beacon.y == check_y)
|
||||||
@@ -99,14 +109,41 @@ impl DaySolver for Day15 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn solve_part2(&mut self) -> String {
|
fn solve_part2(&mut self) -> String {
|
||||||
return 0.to_string();
|
|
||||||
|
// println!("{:?}", self.beacon_scanners.iter().filter(|bs| bs.distance > 2_000_000).collect::<Vec<&BeaconSensor>>());
|
||||||
|
let check_until = if self.beacon_scanners.len() < 20 { 20 } else { 4_000_000 };
|
||||||
|
let target_range = Range { min: 0, max: check_until };
|
||||||
|
for y in 0..(check_until+1) {
|
||||||
|
let ranges_covered = Self::merge_overlapping_ranges(&mut self.find_ranges_without_beacons_at_y(y));
|
||||||
|
if !ranges_covered.iter().any(|r| r.covers(&target_range)) {
|
||||||
|
// println!("Found solution at y={}", y);
|
||||||
|
let x = ranges_covered.iter()
|
||||||
|
.filter(|r| r.max < check_until && r.max >= 0)
|
||||||
|
.next()
|
||||||
|
.unwrap().max + 1;
|
||||||
|
return (4000000i64 * x as i64 + y as i64).to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Couldn't find the answer :(")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct BeaconScanner {
|
struct BeaconSensor {
|
||||||
sensor: Coord<i32>,
|
sensor: Coord<i32>,
|
||||||
closest_beacon: Coord<i32>
|
closest_beacon: Coord<i32>,
|
||||||
|
distance: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BeaconSensor {
|
||||||
|
fn new(sensor: Coord<i32>, closest_beacon: Coord<i32>) -> Self {
|
||||||
|
BeaconSensor {
|
||||||
|
sensor, closest_beacon,
|
||||||
|
distance: sensor.manhattan_dist(&closest_beacon)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -119,6 +156,9 @@ impl Range {
|
|||||||
pub fn overlaps(&self, other: &Range) -> bool {
|
pub fn overlaps(&self, other: &Range) -> bool {
|
||||||
self.min <= other.max && self.max >= other.min
|
self.min <= other.max && self.max >= other.min
|
||||||
}
|
}
|
||||||
|
pub fn covers(&self, other: &Range) -> bool {
|
||||||
|
self.min <= other.min && self.max >= other.max
|
||||||
|
}
|
||||||
|
|
||||||
pub fn in_range(&self, x: &i32) -> bool {
|
pub fn in_range(&self, x: &i32) -> bool {
|
||||||
self.min.le(&x) && self.max.ge(&x)
|
self.min.le(&x) && self.max.ge(&x)
|
||||||
|
|||||||
Reference in New Issue
Block a user