[TASK] Day 15 pt 1
This commit is contained in:
83
Cargo.lock
generated
83
Cargo.lock
generated
@@ -8,6 +8,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
|
"num",
|
||||||
"regex",
|
"regex",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
@@ -21,6 +22,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -39,6 +46,82 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
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]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ edition = "2021"
|
|||||||
regex = "1"
|
regex = "1"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
nohash-hasher = "0.2.0"
|
nohash-hasher = "0.2.0"
|
||||||
|
num = "0.4.0"
|
||||||
|
|||||||
31
input/day15.txt
Normal file
31
input/day15.txt
Normal 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
14
input/day15_example.txt
Normal 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
126
src/day15.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ use crate::day11::Day11;
|
|||||||
use crate::day12::Day12;
|
use crate::day12::Day12;
|
||||||
use crate::day13::Day13;
|
use crate::day13::Day13;
|
||||||
use crate::day14::Day14;
|
use crate::day14::Day14;
|
||||||
|
use crate::day15::Day15;
|
||||||
use crate::day_solver::DaySolver;
|
use crate::day_solver::DaySolver;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
@@ -31,8 +32,9 @@ mod day11;
|
|||||||
mod day12;
|
mod day12;
|
||||||
mod day13;
|
mod day13;
|
||||||
mod day14;
|
mod day14;
|
||||||
|
mod day15;
|
||||||
|
|
||||||
const MAX_DAY: u8 = 14;
|
const MAX_DAY: u8 = 15;
|
||||||
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
|
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -110,6 +112,7 @@ fn build_day_solver(day: u8) -> Option<Box<dyn DaySolver>> {
|
|||||||
12 => Some(Box::new(Day12::create())),
|
12 => Some(Box::new(Day12::create())),
|
||||||
13 => Some(Box::new(Day13::create())),
|
13 => Some(Box::new(Day13::create())),
|
||||||
14 => Some(Box::new(Day14::create())),
|
14 => Some(Box::new(Day14::create())),
|
||||||
|
15 => Some(Box::new(Day15::create())),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
pub fn read_file(filename: &str) -> Vec<String> {
|
pub fn read_file(filename: &str) -> Vec<String> {
|
||||||
|
|
||||||
let contents = fs::read_to_string(filename)
|
let contents = fs::read_to_string(filename)
|
||||||
@@ -82,3 +84,9 @@ pub struct Coord<T> where T: Sized {
|
|||||||
pub y: T
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user