advent-of-code/2022/rust/src/day15.rs

149 lines
4.2 KiB
Rust

mod common;
use std::ops::Range;
type XY = (i64, i64);
#[derive(Debug)]
struct Sensor {
pos: XY,
nearest_beacon: XY,
taxi_dist_covered: u64,
}
type Input = Vec<Sensor>;
type Answer = usize;
fn taxi_dist(a: &XY, b: &XY) -> u64 {
(a.0.abs_diff(b.0) + a.1.abs_diff(b.1)).saturating_sub(1)
}
fn processed_input(input: &str) -> Input {
input
.lines()
.map(|s| {
let line_res = s
.split('=')
.skip(1)
.map(|s| {
s.chars()
.take_while(|c| *c == '-' || ('0'..='9').contains(c))
.collect::<String>()
.parse::<i64>()
.unwrap()
})
.collect::<Vec<i64>>();
line_res
})
.map(|coords| {
let pos = (coords[0], coords[1]);
let nearest_beacon = (coords[2], coords[3]);
let taxi_dist_covered = taxi_dist(&pos, &nearest_beacon);
Sensor {
pos,
nearest_beacon,
taxi_dist_covered,
}
})
.collect()
}
fn part1(input: &Input, y: i64) -> Answer {
let (mut minx, mut maxx) = (i64::MAX, i64::MIN);
for s in input {
let (nminx, nmaxx) = (
s.pos.0 - (s.taxi_dist_covered as i64),
s.pos.0 + (s.taxi_dist_covered as i64),
);
if nminx < minx {
minx = nminx;
}
if nmaxx > maxx {
maxx = nmaxx;
}
}
let mut unbeaconable_locs = 0;
for x in minx..=maxx {
for s in input {
if (x, y) == s.nearest_beacon {
break;
}
if taxi_dist(&s.pos, &(x, y)) <= s.taxi_dist_covered {
unbeaconable_locs += 1;
break;
}
}
}
println!("{:?}", input);
unbeaconable_locs
}
fn part2(input: &Input, max: i64) -> Answer {
let (miny, maxy) = (0, max);
for y in miny..=maxy {
let mut applicable_ranges = input
.iter()
.filter_map(|s| {
let delta_y = s.pos.1.abs_diff(y);
if delta_y > s.taxi_dist_covered {
None
} else {
let dx = (s.taxi_dist_covered - delta_y) as i64;
Some(s.pos.0 - dx..(s.pos.0 + dx + 1))
}
})
.collect::<Vec<Range<i64>>>();
applicable_ranges.sort_by(|a, b| a.start.cmp(&b.start));
let mut disjoint_max = applicable_ranges[0].end;
for r in applicable_ranges {
if disjoint_max < r.start - 1 {
return (((disjoint_max + 1) * 4000000) + y) as usize;
}
if r.end > disjoint_max {
disjoint_max = r.end;
}
}
}
0
}
fn main() {
let input_text = common::day_input(15);
eprintln!("{}\n\nAbove is your input file.\n\n", input_text);
let input = processed_input(&input_text);
common::show_answers(&part1(&input, 2000000), &part2(&input, 4000000))
// common::show_both_answers(&both_parts(&input))
}
// fn both_parts(input: &Input) -> (Answer, Answer) {
// (0, 0)
// }
#[cfg(test)]
mod tests {
use super::*;
const TEST_INPUT: &str = "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";
#[test]
fn test() {
let input = processed_input(TEST_INPUT);
assert_eq!(part1(&input, 10), 26);
assert_eq!(part2(&input, 20), 56000011);
// assert_eq!(both_parts(&input), (0, 0));
}
}