mirror of
https://github.com/peter-tanner/advent-of-code-2022.git
synced 2024-11-30 14:20:22 +08:00
day 15
got both answers first try! slow af solution. I hoped that keeping the solution O(j) would be quick enough and seems like it is, takes around ~10 seconds to complete but that is achievable. For each j it breaks the row into intervals generated based on the taxicab radius. The intervals are simplified by sorting and joining.
This commit is contained in:
parent
2ae5cce33d
commit
98eeb321d1
|
@ -1,3 +1,162 @@
|
|||
use std::{
|
||||
collections::{hash_map::Entry, HashMap, HashSet},
|
||||
fs::read_to_string,
|
||||
};
|
||||
|
||||
const PATH: &str = "src/input";
|
||||
// const SCAN_DEPTH: i32 = 10;
|
||||
const SCAN_DEPTH: i32 = 2000000;
|
||||
const P2_SCAN_MAX: i32 = 4000000;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let binding = read_to_string(PATH).expect("Error reading file");
|
||||
let data = binding.trim();
|
||||
parse_lines(data);
|
||||
}
|
||||
|
||||
fn parse_lines(data: &str) {
|
||||
let mut sensors = HashSet::<(i32, i32)>::new();
|
||||
let mut bacons = HashSet::<(i32, i32)>::new();
|
||||
let mut bacons_count = HashMap::<i32, HashSet<i32>>::new();
|
||||
let mut horizontal_slices = HashMap::<i32, Vec<(i32, i32)>>::new();
|
||||
|
||||
let binding = data.replace(|c: char| c.is_alphabetic() || c == ' ' || c == '=', "");
|
||||
let mut lines = binding.split('\n').into_iter();
|
||||
while let Some(line) = lines.next() {
|
||||
let mut parts = line.split([',', ':']).into_iter();
|
||||
let mut parse_token = || parts.next().unwrap().parse::<i32>().unwrap();
|
||||
let sensor = (parse_token(), parse_token());
|
||||
let beacon = (parse_token(), parse_token());
|
||||
let taxicab_radius: i32 = (sensor.0.abs_diff(beacon.0) + sensor.1.abs_diff(beacon.1))
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
sensors.insert(sensor);
|
||||
bacons.insert(beacon);
|
||||
|
||||
let bacon_count = match bacons_count.entry(beacon.1) {
|
||||
Entry::Vacant(entry) => entry.insert(HashSet::new()),
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
};
|
||||
bacon_count.insert(beacon.0);
|
||||
|
||||
// println!(
|
||||
// "{} {} {} {} -> {}",
|
||||
// sensor.0, sensor.1, beacon.0, beacon.1, taxicab_radius
|
||||
// );
|
||||
|
||||
// can we do this in reverse from the beacon to sensors? does that improve anything?
|
||||
for j in 0..=taxicab_radius {
|
||||
let l = sensor.0 - (taxicab_radius - j) as i32;
|
||||
let u = sensor.0 + (taxicab_radius - j) as i32;
|
||||
let entry = match horizontal_slices.entry(sensor.1 + j) {
|
||||
Entry::Vacant(entry) => entry.insert(Vec::new()),
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
};
|
||||
entry.push((l, u));
|
||||
|
||||
let entry = match horizontal_slices.entry(sensor.1 - j) {
|
||||
Entry::Vacant(entry) => entry.insert(Vec::new()),
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
};
|
||||
entry.push((l, u));
|
||||
|
||||
// println!(
|
||||
// "{} {} {}",
|
||||
// sensor.0 - (taxicab_radius - j.abs()) as i32,
|
||||
// sensor.0 + taxicab_radius - j.abs() as i32,
|
||||
// sensor.1 + j
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
part_1(
|
||||
horizontal_slices
|
||||
.get_mut(&SCAN_DEPTH)
|
||||
.unwrap_or(&mut vec![]),
|
||||
bacons_count.get(&SCAN_DEPTH).unwrap().len() as i32,
|
||||
);
|
||||
|
||||
for j in 0..=P2_SCAN_MAX {
|
||||
let big_intervals =
|
||||
simplify_intervals(horizontal_slices.get_mut(&j).unwrap_or(&mut vec![]));
|
||||
if big_intervals.len() > 1 {
|
||||
let bacon_obtained = big_intervals.get(0).unwrap();
|
||||
let freq: i64 = (bacon_obtained.1 as i64 + 1) * 4000000 + j as i64;
|
||||
println!("PART 2 {}", freq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// print_grid(sensors, bacons, horizontal_slices);
|
||||
}
|
||||
|
||||
fn part_1(intervals: &mut Vec<(i32, i32)>, bacons_row_count: i32) {
|
||||
let big_intervals = simplify_intervals(intervals);
|
||||
let mut sum = 0;
|
||||
for biginterval in big_intervals {
|
||||
sum += biginterval.1 - biginterval.0 + 1;
|
||||
}
|
||||
sum -= bacons_row_count;
|
||||
println!("PART 1 {}", sum);
|
||||
}
|
||||
|
||||
fn simplify_intervals(intervals: &mut Vec<(i32, i32)>) -> Vec<(i32, i32)> {
|
||||
if intervals.len() == 0 {
|
||||
return intervals.to_vec();
|
||||
}
|
||||
intervals.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
let mut big_intervals = Vec::<(i32, i32)>::new();
|
||||
let mut intervals_iter = intervals.iter_mut();
|
||||
let biginterval = intervals_iter.next().unwrap();
|
||||
while let Some(interval) = intervals_iter.next() {
|
||||
// print!("[{} {}", biginterval.0, biginterval.1);
|
||||
// println!("|{} {}]", interval.0, interval.1);
|
||||
// println!(
|
||||
// "{} {}",
|
||||
// biginterval.1 >= interval.0,
|
||||
// interval.1 >= biginterval.1
|
||||
// );
|
||||
// if interval_joined(&biginterval, interval) {
|
||||
if biginterval.1 >= interval.0 && interval.1 >= biginterval.1 {
|
||||
*biginterval = (biginterval.0, interval.1);
|
||||
} else if interval.1 >= biginterval.1 {
|
||||
// intervals.push(biginterval);
|
||||
big_intervals.push(biginterval.clone());
|
||||
*biginterval = interval.clone();
|
||||
// println!("-> {} {}", biginterval.0, biginterval.1);
|
||||
}
|
||||
}
|
||||
big_intervals.push(biginterval.clone());
|
||||
return big_intervals;
|
||||
}
|
||||
|
||||
fn print_grid(
|
||||
sensors: HashSet<(i32, i32)>,
|
||||
bacons: HashSet<(i32, i32)>,
|
||||
horizontal_slices: HashMap<i32, Vec<(i32, i32)>>,
|
||||
) {
|
||||
for j in -2..22 {
|
||||
for i in -2..=25 {
|
||||
let mut break_outer = false;
|
||||
if sensors.contains(&(i, j)) {
|
||||
print!("S");
|
||||
continue;
|
||||
} else if bacons.contains(&(i, j)) {
|
||||
print!("B");
|
||||
continue;
|
||||
} else {
|
||||
for v in horizontal_slices.get(&j).unwrap_or(&vec![]) {
|
||||
if (v.0..=v.1).contains(&i) {
|
||||
print!("#");
|
||||
break_outer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !break_outer {
|
||||
print!(".");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user