Add aoc 2022 day 15
This commit is contained in:
parent
e55389d3bb
commit
89461b9866
|
@ -0,0 +1,14 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "common"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day15"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"common",
|
||||||
|
]
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "day15"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
common = { path = "../common" }
|
|
@ -0,0 +1,40 @@
|
||||||
|
Sensor at x=1112863, y=496787: closest beacon is at x=1020600, y=2000000
|
||||||
|
Sensor at x=2980210, y=1712427: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=2799204, y=1425283: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=3999908, y=2754283: closest beacon is at x=4064129, y=2651511
|
||||||
|
Sensor at x=760990, y=1455625: closest beacon is at x=1020600, y=2000000
|
||||||
|
Sensor at x=3996490, y=3239979: closest beacon is at x=4064129, y=2651511
|
||||||
|
Sensor at x=3347352, y=3603589: closest beacon is at x=3621840, y=3614596
|
||||||
|
Sensor at x=2888433, y=2337157: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=3423261, y=2191958: closest beacon is at x=3153728, y=1862250
|
||||||
|
Sensor at x=1160237, y=3999960: closest beacon is at x=109153, y=3585462
|
||||||
|
Sensor at x=693519, y=3701289: closest beacon is at x=109153, y=3585462
|
||||||
|
Sensor at x=2615270, y=2824808: closest beacon is at x=2554122, y=2935074
|
||||||
|
Sensor at x=3046971, y=1755494: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=139591, y=1186912: closest beacon is at x=1020600, y=2000000
|
||||||
|
Sensor at x=2309134, y=47090: closest beacon is at x=3211831, y=-792661
|
||||||
|
Sensor at x=1849154, y=1377259: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=2515971, y=2851853: closest beacon is at x=2554122, y=2935074
|
||||||
|
Sensor at x=2524614, y=2738138: closest beacon is at x=2554122, y=2935074
|
||||||
|
Sensor at x=3811778, y=1370280: closest beacon is at x=3153728, y=1862250
|
||||||
|
Sensor at x=2615590, y=3819371: closest beacon is at x=2554122, y=2935074
|
||||||
|
Sensor at x=3996286, y=3719213: closest beacon is at x=3621840, y=3614596
|
||||||
|
Sensor at x=3963152, y=2368927: closest beacon is at x=4064129, y=2651511
|
||||||
|
Sensor at x=3495504, y=3076982: closest beacon is at x=3621840, y=3614596
|
||||||
|
Sensor at x=3725521, y=2560764: closest beacon is at x=4064129, y=2651511
|
||||||
|
Sensor at x=952643, y=2385401: closest beacon is at x=1020600, y=2000000
|
||||||
|
Sensor at x=3934384, y=2596106: closest beacon is at x=4064129, y=2651511
|
||||||
|
Sensor at x=3060628, y=3082730: closest beacon is at x=2554122, y=2935074
|
||||||
|
Sensor at x=3468382, y=3916817: closest beacon is at x=3621840, y=3614596
|
||||||
|
Sensor at x=3300107, y=469364: closest beacon is at x=3211831, y=-792661
|
||||||
|
Sensor at x=2306388, y=1932261: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=1965, y=3514070: closest beacon is at x=109153, y=3585462
|
||||||
|
Sensor at x=3081537, y=1841861: closest beacon is at x=3153728, y=1862250
|
||||||
|
Sensor at x=2997643, y=1729779: closest beacon is at x=2946825, y=1712605
|
||||||
|
Sensor at x=21714, y=3624181: closest beacon is at x=109153, y=3585462
|
||||||
|
Sensor at x=1549467, y=3109269: closest beacon is at x=2554122, y=2935074
|
||||||
|
Sensor at x=3722307, y=3839410: closest beacon is at x=3621840, y=3614596
|
||||||
|
Sensor at x=3848580, y=3544878: closest beacon is at x=3621840, y=3614596
|
||||||
|
Sensor at x=1189516, y=2153239: closest beacon is at x=1020600, y=2000000
|
||||||
|
Sensor at x=468190, y=1889204: closest beacon is at x=1020600, y=2000000
|
||||||
|
Sensor at x=270403, y=2762568: closest beacon is at x=109153, y=3585462
|
|
@ -0,0 +1,266 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use common::Point;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input_file = common::parse_args_input_file(&mut std::env::args());
|
||||||
|
let contents = std::fs::read_to_string(input_file.clone()).expect("Failed to read input file");
|
||||||
|
let mut sensors = std::vec::Vec::<(Point, Point)>::new();
|
||||||
|
let mut occupied = std::collections::HashMap::<Point, Thing>::new();
|
||||||
|
for line in contents.lines() {
|
||||||
|
let r = parse_line(line);
|
||||||
|
if r.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sensors.push(r.unwrap().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let skip_other_than_row_to_count = true;
|
||||||
|
let row_to_count = if input_file.eq("test_input") { 10 } else { 2_000_000 };
|
||||||
|
let coord_min = 0;
|
||||||
|
let coord_max = if input_file.eq("test_input") { 20 } else { 4_000_000 };
|
||||||
|
let mut x_min = i32::MAX;
|
||||||
|
let mut x_max = i32::MIN;
|
||||||
|
let mut y_min = i32::MAX;
|
||||||
|
let mut y_max = i32::MIN;
|
||||||
|
for (index, (sensor, beacon)) in sensors.iter().enumerate() {
|
||||||
|
let distance = sensor.manhattan_distance(beacon) as i32;
|
||||||
|
occupied.insert(*sensor, Thing::Sensor);
|
||||||
|
occupied.insert(*beacon, Thing::Beacon);
|
||||||
|
// if sensor.x != 8 && sensor.y != 7 {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// println!("{:?}", sensor);
|
||||||
|
for y in sensor.y-distance..=sensor.y+distance {
|
||||||
|
if skip_other_than_row_to_count && y != row_to_count {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for x in sensor.x-distance..=sensor.x+distance {
|
||||||
|
let p = Point { x: x, y: y };
|
||||||
|
if sensor.manhattan_distance(&p) <= distance.try_into().unwrap() {
|
||||||
|
if !occupied.contains_key(&p) {
|
||||||
|
occupied.insert(p, Thing::LogicallyEmpty);
|
||||||
|
x_min = std::cmp::min(x_min, p.x);
|
||||||
|
x_max = std::cmp::max(x_max, p.x);
|
||||||
|
y_min = std::cmp::min(y_min, p.y);
|
||||||
|
y_max = std::cmp::max(y_max, p.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Processed beacon {} of {}", index + 1, sensors.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for x in x_min..=x_max {
|
||||||
|
match occupied.get(&Point{ x: x, y: row_to_count }) {
|
||||||
|
Some(v) => {
|
||||||
|
match v {
|
||||||
|
Thing::LogicallyEmpty => {count += 1;},
|
||||||
|
_ => {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if input_file.eq("test_input") {
|
||||||
|
for y in y_min..y_max {
|
||||||
|
let mut s = String::new();
|
||||||
|
let prefix = format!("{:3} ", y);
|
||||||
|
s.push_str(prefix.as_str());
|
||||||
|
for x in x_min..x_max {
|
||||||
|
let p = Point { x: x, y: y };
|
||||||
|
match occupied.get(&p) {
|
||||||
|
Some(v) => {
|
||||||
|
match v {
|
||||||
|
Thing::Beacon => { s.push('B'); },
|
||||||
|
Thing::Sensor => { s.push('S'); },
|
||||||
|
Thing::LogicallyEmpty => { s.push('#'); },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
None => { s.push('.'); },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
println!("{}", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("[PART 1] {}", count);
|
||||||
|
|
||||||
|
// Brute force approach by checking each point.
|
||||||
|
if false {
|
||||||
|
let mut distress_beacon: Option<Point> = None;
|
||||||
|
for y in coord_min..=coord_max {
|
||||||
|
if distress_beacon.is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for x in coord_min..=coord_max {
|
||||||
|
let mut occupiable = true;
|
||||||
|
let p = Point {x: x, y: y};
|
||||||
|
for (sensor, beacon) in sensors.iter() {
|
||||||
|
let distance = sensor.manhattan_distance(beacon);
|
||||||
|
if sensor.manhattan_distance(&p) <= distance {
|
||||||
|
occupiable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if occupiable {
|
||||||
|
match occupied.get(&p) {
|
||||||
|
Some(v) => {
|
||||||
|
match v {
|
||||||
|
Thing::Sensor => { continue; },
|
||||||
|
Thing::Beacon => { continue; },
|
||||||
|
_ => {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
|
};
|
||||||
|
assert!(distress_beacon.is_none(), "Duplicate distress beacon");
|
||||||
|
distress_beacon = Some(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("[PART 2] {}", distress_beacon.unwrap().x * 4000000 + distress_beacon.unwrap().y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One though that I had is that is could be possible to create a polygon representing
|
||||||
|
// the acceptable area, and then "subtract" the intersecting areas from the other areas
|
||||||
|
// created by each sensor/beacon combination. Visually this makes a lot of sense. The points
|
||||||
|
// we have set up until now are integer coordinates, and we might have to switch or work
|
||||||
|
// around that in some way.
|
||||||
|
//
|
||||||
|
// Another approach could be to take a line from A->B, for example, and then see if it
|
||||||
|
// fits entirely within the bounds of a given sensor/beacon pair. If it does, the entire
|
||||||
|
// line can be excluded pretty easily. In the case that it doesn't, the line could be
|
||||||
|
// subdivded in two eg. A1->B1, A2->B2, and each of those smaller lines checked. For
|
||||||
|
// a given line of size the worst case (checking a line where the length is 1) would
|
||||||
|
// be slower than simply checking each point individually.
|
||||||
|
//
|
||||||
|
// Perhaps a property that could be exploitable is take advantage of the lines produced
|
||||||
|
// by sensor areas being "diagonal" with respect to the grid. Would checking diagonal lines
|
||||||
|
// be faster somehow?
|
||||||
|
//
|
||||||
|
// After reading some of the comments on reddit:
|
||||||
|
// * use squares instead of lines
|
||||||
|
// * calculate perimeter points + 1 for each sensor, and check only those to reduce
|
||||||
|
// the number of checks
|
||||||
|
// * there is some sort of geometric solution, but what I don't know
|
||||||
|
//
|
||||||
|
|
||||||
|
// This is a perimeter bounded solution
|
||||||
|
let mut potential_beacon_spots = std::vec::Vec::<Point>::new();
|
||||||
|
let mut sensor_distances = std::vec::Vec::<(Point, u32)>::new();
|
||||||
|
for (sensor, beacon) in sensors.iter() {
|
||||||
|
let d = sensor.manhattan_distance(beacon);
|
||||||
|
sensor_distances.push((sensor.clone(), d));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut potential_spots = std::collections::HashSet::<Point>::new();
|
||||||
|
for (sensor, distance) in sensor_distances.iter() {
|
||||||
|
let d = (distance + 1) as i32;
|
||||||
|
for i in 0..=d {
|
||||||
|
let offset = d - i;
|
||||||
|
// left to top
|
||||||
|
let left = Point{x: sensor.x - offset, y: sensor.y + i};
|
||||||
|
// top to right
|
||||||
|
let top = Point{x: sensor.x + i, y: sensor.y + offset};
|
||||||
|
// right to bottom
|
||||||
|
let right = Point{x: sensor.x + offset, y: sensor.y - i};
|
||||||
|
// bottom to left
|
||||||
|
let bottom = Point{x: sensor.x - i, y: sensor.y - offset};
|
||||||
|
|
||||||
|
for p in [left,top,right,bottom] {
|
||||||
|
if p.x > coord_max || p.x < coord_min || p.y > coord_max || p.y < coord_min {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
potential_spots.insert(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut potential_spots2 = std::collections::HashSet::<Point>::new();
|
||||||
|
let mut comparisons = 0;
|
||||||
|
for point in potential_spots.iter() {
|
||||||
|
let mut ok = true;
|
||||||
|
comparisons += 1;
|
||||||
|
for (index, (sensor, distance)) in sensor_distances.iter().enumerate() {
|
||||||
|
if sensor.manhattan_distance(point) <= *distance {
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
potential_spots2.insert(*point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for point in potential_spots2.iter() {
|
||||||
|
println!("[PART 2] ({:?}) {} comparisons: {}", point, comparisons, point.x as u64 * 4_000_000 + point.y as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Square {
|
||||||
|
top_left: Point,
|
||||||
|
bottom_right: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Square {
|
||||||
|
fn contains_line(&self, line: &Line) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Line {
|
||||||
|
start: Point,
|
||||||
|
end: Point
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Thing {
|
||||||
|
Beacon,
|
||||||
|
Sensor,
|
||||||
|
LogicallyEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_line(s: &str) -> Option<(Point, Point)> {
|
||||||
|
let divider = s.find(":");
|
||||||
|
if divider.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let sensor: Option<Point> = point_from_str(&s[0..=divider.unwrap()]);
|
||||||
|
let beacon: Option<Point> = point_from_str(&s[divider.unwrap()..s.len()]);
|
||||||
|
if sensor.is_none() || beacon.is_none() {
|
||||||
|
println!("Failed to find anything in line: '{}'", s);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
println!("Sensor at {:?}\nBeacon at {:?}\ndistance: {}\n", sensor, beacon, sensor.unwrap().manhattan_distance(&beacon.unwrap()));
|
||||||
|
return Some((sensor.unwrap(), beacon.unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn point_from_str(s: &str) -> Option<Point> {
|
||||||
|
let x = value_from_str(s, "x=");
|
||||||
|
let y = value_from_str(s, "y=");
|
||||||
|
if x.is_none() || y.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(Point { x: x.unwrap(), y: y.unwrap() });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_from_str(s: &str, delimiter: &str) -> Option<i32> {
|
||||||
|
let mut start = s.find(delimiter);
|
||||||
|
let mut length = 0;
|
||||||
|
if start.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
start = Some(start.unwrap() + 2);
|
||||||
|
for i in start.unwrap()..s.len() {
|
||||||
|
let c = s.chars().nth(i).unwrap();
|
||||||
|
if c.is_ascii_digit() || c.eq(&'-') {
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if length == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(i32::from_str(&s[start.unwrap()..start.unwrap()+length]).expect("Failed to parse"));
|
||||||
|
}
|
|
@ -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
|
|
@ -85,6 +85,12 @@ impl Point {
|
||||||
self.x = (self.x.abs() as f32 / larger).ceil() as i32;
|
self.x = (self.x.abs() as f32 / larger).ceil() as i32;
|
||||||
self.y = (self.y.abs() as f32 / larger).ceil() as i32;
|
self.y = (self.y.abs() as f32 / larger).ceil() as i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn manhattan_distance(&self, other: &Point) -> u32 {
|
||||||
|
let x = (self.x - other.x).abs() as u32;
|
||||||
|
let y = (self.y - other.y).abs() as u32;
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue