[TASK] Day 15 pt 1

This commit is contained in:
2022-12-17 17:40:02 +01:00
parent 56cc1a53f3
commit 2171307f5f
7 changed files with 268 additions and 2 deletions

83
Cargo.lock generated
View File

@@ -8,6 +8,7 @@ version = "0.1.0"
dependencies = [
"lazy_static",
"nohash-hasher",
"num",
"regex",
"rustc-hash",
]
@@ -21,6 +22,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -39,6 +46,82 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "regex"
version = "1.7.0"

View File

@@ -11,3 +11,4 @@ regex = "1"
lazy_static = "1.4.0"
rustc-hash = "1.1.0"
nohash-hasher = "0.2.0"
num = "0.4.0"

31
input/day15.txt Normal file
View File

@@ -0,0 +1,31 @@
Sensor at x=3923513, y=2770279: closest beacon is at x=3866712, y=2438950
Sensor at x=675683, y=3223762: closest beacon is at x=-224297, y=2997209
Sensor at x=129453, y=2652332: closest beacon is at x=92656, y=2629486
Sensor at x=3906125, y=2154618: closest beacon is at x=3866712, y=2438950
Sensor at x=65723, y=902062: closest beacon is at x=92656, y=2629486
Sensor at x=3137156, y=2876347: closest beacon is at x=2907507, y=3100765
Sensor at x=32848, y=2676435: closest beacon is at x=92656, y=2629486
Sensor at x=3272472, y=3445147: closest beacon is at x=2907507, y=3100765
Sensor at x=2926008, y=128948: closest beacon is at x=3089364, y=-501737
Sensor at x=2975, y=2769838: closest beacon is at x=92656, y=2629486
Sensor at x=3540455, y=2469135: closest beacon is at x=3866712, y=2438950
Sensor at x=3674809, y=2062166: closest beacon is at x=3719980, y=2000000
Sensor at x=3693706, y=2027384: closest beacon is at x=3719980, y=2000000
Sensor at x=3869683, y=2291983: closest beacon is at x=3866712, y=2438950
Sensor at x=2666499, y=2796436: closest beacon is at x=2650643, y=2489479
Sensor at x=492, y=2601991: closest beacon is at x=92656, y=2629486
Sensor at x=2710282, y=3892347: closest beacon is at x=2907507, y=3100765
Sensor at x=28974, y=3971342: closest beacon is at x=-224297, y=2997209
Sensor at x=3990214, y=2399722: closest beacon is at x=3866712, y=2438950
Sensor at x=3853352, y=1009020: closest beacon is at x=3719980, y=2000000
Sensor at x=1231833, y=3999338: closest beacon is at x=1313797, y=4674300
Sensor at x=2083669, y=875035: closest beacon is at x=1369276, y=-160751
Sensor at x=1317274, y=2146819: closest beacon is at x=2650643, y=2489479
Sensor at x=3712875, y=2018770: closest beacon is at x=3719980, y=2000000
Sensor at x=963055, y=23644: closest beacon is at x=1369276, y=-160751
Sensor at x=3671967, y=64054: closest beacon is at x=3089364, y=-501737
Sensor at x=3109065, y=2222392: closest beacon is at x=2650643, y=2489479
Sensor at x=3218890, y=1517419: closest beacon is at x=3719980, y=2000000
Sensor at x=3856777, y=3987650: closest beacon is at x=4166706, y=3171774
Sensor at x=1912696, y=3392788: closest beacon is at x=2907507, y=3100765
Sensor at x=3597620, y=3100104: closest beacon is at x=4166706, y=3171774

14
input/day15_example.txt Normal file
View File

@@ -0,0 +1,14 @@
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
Sensor at x=9, y=16: closest beacon is at x=10, y=16
Sensor at x=13, y=2: closest beacon is at x=15, y=3
Sensor at x=12, y=14: closest beacon is at x=10, y=16
Sensor at x=10, y=20: closest beacon is at x=10, y=16
Sensor at x=14, y=17: closest beacon is at x=10, y=16
Sensor at x=8, y=7: closest beacon is at x=2, y=10
Sensor at x=2, y=0: closest beacon is at x=2, y=10
Sensor at x=0, y=11: closest beacon is at x=2, y=10
Sensor at x=20, y=14: closest beacon is at x=25, y=17
Sensor at x=17, y=20: closest beacon is at x=21, y=22
Sensor at x=16, y=7: closest beacon is at x=15, y=3
Sensor at x=14, y=3: closest beacon is at x=15, y=3
Sensor at x=20, y=1: closest beacon is at x=15, y=3

126
src/day15.rs Normal file
View File

@@ -0,0 +1,126 @@
use std::collections::HashSet;
use regex::Regex;
use crate::{day_solver::DaySolver, util::Coord};
use super::util;
pub struct Day15 {
beacon_scanners: Vec<BeaconScanner>
}
impl Day15 {
pub fn create() -> Self {
// let lines = util::read_file("input/day15_example.txt");
let lines = util::read_file("input/day15.txt");
// Lines look like:
// "Sensor at x=2, y=18: closest beacon is at x=-2, y=15"
let re = Regex::new(r"Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)").unwrap();
// Put the input into the day struct
return Day15 {
beacon_scanners: lines.iter().map(|s| {
let cap = re.captures_iter(s).next().unwrap();
BeaconScanner {
sensor: 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() }
}
}).collect()
}
}
}
impl DaySolver for Day15 {
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",
// 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 {
None
} else {
// println!("Adding");
Some(Range{
min: bs.sensor.x - coverage_width,
max: bs.sensor.x + coverage_width
})
}
}).collect();
if ranges_covered.is_empty() {
return 0.to_string();
}
// println!("Ranges covered: {:?}", ranges_covered);
// 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
// would pick up that one and have a smaller range
ranges_covered.sort_by_key(|r| r.min);
// println!("Ranges covered: {:?}", ranges_covered);
let mut merged_ranges: Vec<Range> = Vec::new();
let mut ranges_covered_iter = ranges_covered.iter();
let mut current_range = ranges_covered_iter.next().unwrap().clone();
while let Some(next_range) = ranges_covered_iter.next() {
if current_range.overlaps(next_range) {
current_range.max = next_range.max.max(current_range.max);
} else {
// New range!
merged_ranges.push(current_range);
current_range = next_range.clone();
}
}
merged_ranges.push(current_range);
let beacons_on_check_y = self.beacon_scanners.iter()
.filter(|bs| bs.closest_beacon.y == check_y)
.map(|bs| bs.closest_beacon.x)
.filter(|x| merged_ranges.iter().any(|r| r.in_range(&x)))
.collect::<HashSet<i32>>();
// println!("Merged ranges: {:?}", merged_ranges);
return (merged_ranges.iter().map(|r| r.max - r.min + 1).sum::<i32>() - beacons_on_check_y.len() as i32).to_string();
}
fn solve_part2(&mut self) -> String {
return 0.to_string();
}
}
#[derive(Debug, Clone)]
struct BeaconScanner {
sensor: Coord<i32>,
closest_beacon: Coord<i32>
}
#[derive(Debug, Clone)]
struct Range {
min: i32,
max: i32
}
impl Range {
pub fn overlaps(&self, other: &Range) -> bool {
self.min <= other.max && self.max >= other.min
}
pub fn in_range(&self, x: &i32) -> bool {
self.min.le(&x) && self.max.ge(&x)
}
}

View File

@@ -13,6 +13,7 @@ use crate::day11::Day11;
use crate::day12::Day12;
use crate::day13::Day13;
use crate::day14::Day14;
use crate::day15::Day15;
use crate::day_solver::DaySolver;
mod util;
@@ -31,8 +32,9 @@ mod day11;
mod day12;
mod day13;
mod day14;
mod day15;
const MAX_DAY: u8 = 14;
const MAX_DAY: u8 = 15;
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
fn main() {
@@ -110,6 +112,7 @@ fn build_day_solver(day: u8) -> Option<Box<dyn DaySolver>> {
12 => Some(Box::new(Day12::create())),
13 => Some(Box::new(Day13::create())),
14 => Some(Box::new(Day14::create())),
15 => Some(Box::new(Day15::create())),
_ => None
}
}

View File

@@ -1,6 +1,8 @@
use std::fmt::Display;
use std::fs;
use num::Integer;
pub fn read_file(filename: &str) -> Vec<String> {
let contents = fs::read_to_string(filename)
@@ -82,3 +84,9 @@ pub struct Coord<T> where T: Sized {
pub y: T
}
impl <T> Coord<T> where T: Integer + Copy {
pub fn manhattan_dist(&self, other: &Coord<T>) -> T {
self.x.max(other.x).sub(self.x.min(other.x)) + self.y.max(other.y).sub(self.y.min(other.y))
}
}