advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git

main.rs (4366B)

    1 use regex::Regex;
    2 use std::collections::HashSet;
    3 
    4 #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
    5 struct Pos(i32, i32);
    6 
    7 #[derive(Debug)]
    8 struct Sensor {
    9     loc: Pos,
   10     beacon: Pos,
   11 }
   12 
   13 impl Sensor {
   14     fn from_str(s: &str) -> Option<Self> {
   15         if let Some(cap) = Regex::new(r"^Sensor at x=(?P<sensor_x>[-0-9]+), y=(?P<sensor_y>[-0-9]+): closest beacon is at x=(?P<beacon_x>[-0-9]+), y=(?P<beacon_y>[-0-9]+)$")
   16                 .unwrap()
   17                 .captures(s)
   18         {
   19             Some(Sensor{
   20                 loc: Pos(cap.name("sensor_x").unwrap().as_str().parse::<i32>().unwrap(), cap.name("sensor_y").unwrap().as_str().parse::<i32>().unwrap()),
   21                 beacon: Pos(cap.name("beacon_x").unwrap().as_str().parse::<i32>().unwrap(), cap.name("beacon_y").unwrap().as_str().parse::<i32>().unwrap()),
   22             })
   23         } else {
   24             None
   25         }
   26     }
   27 
   28     fn get_banned_range(&self, y: i32) -> Option<(i32, i32)> {
   29         let dist = (self.loc.0 - self.beacon.0).abs() + (self.loc.1 - self.beacon.1).abs();
   30         let y_dist = (self.loc.1 - y).abs();
   31         let x_dist = dist - y_dist;
   32         if x_dist >= 0 {
   33             Some((self.loc.0 - x_dist, self.loc.0 + x_dist))
   34         } else {
   35             None
   36         }
   37     }
   38 }
   39 
   40 fn main() {
   41     let input = std::fs::read_to_string("input.txt")
   42         .unwrap()
   43         .trim()
   44         .split('\n')
   45         .map(|s| Sensor::from_str(s).unwrap())
   46         .collect::<Vec<Sensor>>();
   47     // 6078701
   48     println!("Part 1: {}", part_1(&input, 2000000));
   49     // 12567351400528
   50     println!("Part 2: {}", part_2(&input, (0, 4000000)).unwrap());
   51 }
   52 
   53 fn union((s1, e1): (i32, i32), (s2, e2): (i32, i32)) -> Option<(i32, i32)> {
   54     if (s1 < s2 && e1 < s2) || (s1 > e2 && e1 > e2) {
   55         None
   56     } else {
   57         Some((s1.min(s2), e1.max(e2)))
   58     }
   59 }
   60 
   61 fn get_banned_ranges(input: &Vec<Sensor>, y: i32) -> Vec<(i32, i32)> {
   62     let mut banned_ranges = Vec::new();
   63     for sensor in input {
   64         if let Some(mut curr) = sensor.get_banned_range(y) {
   65             let mut banned_ranges_next = Vec::new();
   66             for br in banned_ranges {
   67                 if let Some(new) = union(br, curr) {
   68                     curr = new;
   69                 } else {
   70                     banned_ranges_next.push(br);
   71                 }
   72             }
   73             banned_ranges_next.push(curr);
   74             banned_ranges = banned_ranges_next;
   75         }
   76     }
   77     banned_ranges
   78 }
   79 
   80 fn part_1(input: &Vec<Sensor>, y: i32) -> i32 {
   81     let banned_ranges = get_banned_ranges(input, y);
   82     let beacon_xs = input
   83         .iter()
   84         .filter_map(|b| {
   85             if b.beacon.1 == y {
   86                 Some(b.beacon)
   87             } else {
   88                 None
   89             }
   90         })
   91         .collect::<HashSet<Pos>>()
   92         .iter()
   93         .map(|b| b.0)
   94         .collect::<Vec<i32>>();
   95     let beacon_count = {
   96         let mut tmp = 0;
   97         for x in beacon_xs.iter() {
   98             for r in banned_ranges.iter() {
   99                 if x >= &r.0 && x <= &r.1 {
  100                     tmp += 1;
  101                 }
  102             }
  103         }
  104         tmp
  105     };
  106     banned_ranges.iter().map(|(s, e)| e + 1 - s).sum::<i32>() - beacon_count
  107 }
  108 
  109 fn difference(
  110     (s1, e1): (i32, i32),
  111     (s2, e2): (i32, i32),
  112 ) -> (Option<(i32, i32)>, Option<(i32, i32)>) {
  113     match ((s2 <= s1 && s1 <= e2), (s2 <= e1 && e1 <= e2)) {
  114         (true, true) => (None, None),
  115         (true, false) => (Some((e2 + 1, e1)), None),
  116         (false, true) => (Some((s1, s2 - 1)), None),
  117         (false, false) => (Some((s1, s2 - 1)), Some((e2 + 1, e1))),
  118     }
  119 }
  120 
  121 fn part_2(input: &Vec<Sensor>, (pos_min, pos_max): (i32, i32)) -> Option<i64> {
  122     for y in pos_min..=pos_max {
  123         let banned_ranges = get_banned_ranges(input, y);
  124         let mut x_valid = vec![(pos_min, pos_max)];
  125         for br in banned_ranges {
  126             let mut x_valid_next = Vec::new();
  127             for xv in x_valid {
  128                 let (d1, d2) = difference(xv, br);
  129                 if let Some(r1) = d1 {
  130                     x_valid_next.push(r1);
  131                 }
  132                 if let Some(r2) = d2 {
  133                     x_valid_next.push(r2);
  134                 }
  135             }
  136             x_valid = x_valid_next;
  137         }
  138         if !x_valid.is_empty() {
  139             return Some(x_valid[0].0 as i64 * pos_max as i64 + y as i64);
  140         }
  141     }
  142     None
  143 }