aoc2022

Advent of Code 2022 solutions in Rust
git clone git://code.mfashby.net:/aoc2022
Log | Files | Refs

day15.rs (3191B)


      1 use regex::Regex;
      2 
      3 #[derive(Debug,Clone)]
      4 struct Pos {
      5     x: i32,
      6     y: i32
      7 }
      8 
      9 #[derive(Debug)]
     10 struct Sensor {
     11     sensor_pos: Pos,
     12     beacon_dist: u32
     13 }
     14 
     15 #[derive(Debug,Clone)]
     16 struct LineSeg {
     17     left: i32,
     18     right: i32, // Exclusive!
     19 }
     20 
     21 impl LineSeg {
     22     // fn len(&self) -> u32 {
     23     //     (self.right - self.left).try_into().unwrap()
     24     // }
     25     fn contains(&self, x: i32) -> bool {
     26         self.left <= x && x < self.right
     27     }
     28 }
     29 
     30 pub fn run(input: String) {
     31     // Am i trying to be too clever, or not clever enough? 
     32     // Where's my search space? I don't need to search _every_ integer 0-4_000_000 right? I can just search the 
     33     // edges of each beacon's outline surely.
     34     // But that's already what I'm doing -- 
     35     let re = Regex::new(r"Sensor at x=([-\d]+), y=([-\d]+): closest beacon is at x=([-\d]+), y=([-\d]+)").unwrap();
     36     let search_y = 2_890_000..4_000_000; // Cheat, narrow the search space...
     37     let search_x = 0..4_000_000;
     38 
     39     let sens: Vec<Sensor> = input.lines().map(|line| {
     40         let cap = re.captures(line).expect("line didn't match regex!");
     41         let sensor_x: i32 = cap[1].parse().expect("sx wasn't an i32!");
     42         let sensor_y: i32 = cap[2].parse().expect("sy wasn't an i32!");
     43         let beacon_x: i32 = cap[3].parse().expect("bx wasn't an i32!");
     44         let beacon_y: i32 = cap[4].parse().expect("by wasn't an i32!");
     45         let beacon_dist = sensor_x.abs_diff(beacon_x)+sensor_y.abs_diff(beacon_y);
     46         Sensor {
     47             sensor_pos: Pos { x: sensor_x, y: sensor_y },
     48             beacon_dist,
     49         }
     50     }).collect();
     51 
     52     let (x, y) = search_y.into_iter().filter_map(|y| {
     53         // if y % 10_000 == 0 {
     54         //     println!("checking y {}", y);
     55         // }
     56         let mut line_segments: Vec<LineSeg> = sens.iter().flat_map(|sen| {   
     57             // Map it to a line segment on the target line
     58             let target_y_dist = sen.sensor_pos.y.abs_diff(y);
     59             if target_y_dist >= sen.beacon_dist {
     60                 // It's too far from the target line entirely
     61                 None
     62             } else {
     63                 // Reach along the line is the remaining beacon dist after reachig target y
     64                 let reach = sen.beacon_dist  - target_y_dist;
     65                 let l = sen.sensor_pos.x-(reach as i32);
     66                 let r = sen.sensor_pos.x+(reach as i32);
     67                 //println!("{:?} yd {} reach {} l {} r {}", sen, yd, reach, l,r);
     68                 Some(LineSeg{left: l,right: r})
     69             }
     70         }).collect();
     71         line_segments.sort_by(|ls1,ls2| {ls1.left.cmp(&ls2.left)}); // not sure if this is necessary?
     72         // Iterate to find the gap, skipping forward rather than basically iterating
     73         let mut ix:i32 = 0;
     74         'lp: while ix < search_x.end {
     75             for l in &line_segments {
     76                 if l.contains(ix) {
     77                     ix = l.right;
     78                     continue 'lp
     79                 }
     80             }
     81             // No line segment contained this point, so it's our answer!
     82             return Some((ix+1, y));
     83         }
     84         None
     85     }).next().expect("no point found!");
     86     println!("Day 15: {}", (x as i64)*4_000_000 + (y as i64));
     87 }