advent-of-code

Perserverance, or the lack thereof

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

main.rs (7647B)

    1 use std::collections::{HashSet, VecDeque};
    2 
    3 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    4 enum Axis {
    5     X,
    6     Y,
    7     Z,
    8 }
    9 
   10 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
   11 struct Mapping {
   12     axis: [Axis; 3],
   13     flip: [bool; 3],
   14 }
   15 
   16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
   17 struct Pos([i32; 3]);
   18 
   19 impl Pos {
   20     fn new(s: &str) -> Pos {
   21         let coord = s
   22             .split(",")
   23             .map(|c| c.parse::<i32>().unwrap())
   24             .collect::<Vec<_>>();
   25         Pos([coord[0], coord[1], coord[2]])
   26     }
   27 
   28     fn remap(&self, mapping: Mapping) -> Self {
   29         let mut coord = [0; 3];
   30         for i in 0..3 {
   31             match mapping.axis[i] {
   32                 Axis::X => {
   33                     coord[i] = self.0[0] * (if mapping.flip[i] { -1 } else { 1 });
   34                 }
   35                 Axis::Y => {
   36                     coord[i] = self.0[1] * (if mapping.flip[i] { -1 } else { 1 });
   37                 }
   38                 Axis::Z => {
   39                     coord[i] = self.0[2] * (if mapping.flip[i] { -1 } else { 1 });
   40                 }
   41             }
   42         }
   43         Pos(coord)
   44     }
   45 
   46     fn project(&self, mapping: Mapping, src: Pos, dest: Pos) -> Self {
   47         // remaps self, then applies projection same as from mapped(src) -> dest
   48         let mapped_src = src.remap(mapping);
   49         let mapped_self = self.remap(mapping);
   50         Pos([
   51             mapped_self.0[0] + (dest.0[0] - mapped_src.0[0]),
   52             mapped_self.0[1] + (dest.0[1] - mapped_src.0[1]),
   53             mapped_self.0[2] + (dest.0[2] - mapped_src.0[2]),
   54         ])
   55     }
   56 
   57     fn dist(&self, other: &Pos) -> (i32, i32) {
   58         (
   59             (self.0[0] - other.0[0]).abs()
   60                 + (self.0[1] - other.0[1]).abs()
   61                 + (self.0[2] - other.0[2]).abs(),
   62             (self.0[0] - other.0[0]).pow(2)
   63                 + (self.0[1] - other.0[1]).pow(2)
   64                 + (self.0[2] - other.0[2]).pow(2),
   65         )
   66     }
   67 }
   68 
   69 fn main() {
   70     let scanner_data = {
   71         let mut tmp = Vec::<Vec<Pos>>::new();
   72         let mut curr_scanner = Vec::<Pos>::new();
   73         for l in std::fs::read_to_string("input.txt")
   74             .unwrap()
   75             .trim()
   76             .split('\n')
   77         {
   78             if l == "" {
   79                 tmp.push(curr_scanner);
   80                 curr_scanner = Vec::new();
   81             } else if !l.starts_with("--") {
   82                 curr_scanner.push(Pos::new(l));
   83             }
   84         }
   85         tmp.push(curr_scanner);
   86         tmp
   87     };
   88     // 425
   89     let (count, scanner_coord) = part_1(&scanner_data);
   90     println!("Part 1: {}", count);
   91     // 13354
   92     println!("Part 2: {}", part_2(&scanner_coord));
   93 }
   94 
   95 fn part_1(scanner_data: &Vec<Vec<Pos>>) -> (usize, Vec<Pos>) {
   96     let all_mapping = {
   97         let mut tmp = Vec::<Mapping>::new();
   98         let basic = vec![
   99             Mapping {
  100                 axis: [Axis::X, Axis::Y, Axis::Z],
  101                 flip: [false, false, false],
  102             },
  103             Mapping {
  104                 axis: [Axis::X, Axis::Y, Axis::Z],
  105                 flip: [true, false, true],
  106             },
  107             Mapping {
  108                 axis: [Axis::Y, Axis::X, Axis::Z],
  109                 flip: [false, true, false],
  110             },
  111             Mapping {
  112                 axis: [Axis::Y, Axis::X, Axis::Z],
  113                 flip: [true, false, false],
  114             },
  115             Mapping {
  116                 axis: [Axis::Z, Axis::Y, Axis::X],
  117                 flip: [false, false, true],
  118             },
  119             Mapping {
  120                 axis: [Axis::Z, Axis::Y, Axis::X],
  121                 flip: [true, false, false],
  122             },
  123         ];
  124         for m in basic {
  125             // generate all 4 rotations
  126             tmp.push(m);
  127             tmp.push(Mapping {
  128                 axis: [m.axis[0], m.axis[2], m.axis[1]],
  129                 flip: [m.flip[0], m.flip[2], !m.flip[1]],
  130             });
  131             tmp.push(Mapping {
  132                 axis: [m.axis[0], m.axis[1], m.axis[2]],
  133                 flip: [m.flip[0], !m.flip[1], !m.flip[2]],
  134             });
  135             tmp.push(Mapping {
  136                 axis: [m.axis[0], m.axis[2], m.axis[1]],
  137                 flip: [m.flip[0], !m.flip[2], m.flip[1]],
  138             });
  139         }
  140         tmp
  141     };
  142 
  143     let mut scanner_coord = vec![None; scanner_data.len()];
  144     scanner_coord[0] = Some(Pos([0, 0, 0]));
  145     let mut all_beacons = HashSet::<Pos>::new();
  146     for x in scanner_data[0].iter() {
  147         all_beacons.insert(*x);
  148     }
  149     // remapped and transferred to scanner 0 format
  150     let mut corrected_scanner_data = vec![None; scanner_data.len()];
  151     corrected_scanner_data[0] = Some(scanner_data[0].clone());
  152     let mut match_queue = VecDeque::new();
  153     match_queue.push_back(0);
  154     while let Some(to_match) = match_queue.pop_front() {
  155         let ref_data = corrected_scanner_data[to_match].clone().unwrap();
  156         for matched in 0..scanner_data.len() {
  157             if corrected_scanner_data[matched].is_none() {
  158                 // see if we have more than 12 matching points
  159                 let mut matching_pairs = Vec::new();
  160                 for a in 0..ref_data.len() {
  161                     for b in 0..scanner_data[matched].len() {
  162                         let dist_a = ref_data
  163                             .iter()
  164                             .map(|x| ref_data[a].dist(x))
  165                             .collect::<HashSet<_>>();
  166                         let dist_b = scanner_data[matched]
  167                             .iter()
  168                             .map(|x| scanner_data[matched][b].dist(x))
  169                             .collect::<HashSet<_>>();
  170                         // measuring 12 points ensures unique identification (self + 11 others)
  171                         if dist_a.intersection(&dist_b).count() >= 12 {
  172                             matching_pairs.push((a, b));
  173                         }
  174                     }
  175                 }
  176                 // find right mapping by matching calculated scanner position
  177                 for mapping in all_mapping.iter() {
  178                     let possible_scanner_pos = matching_pairs
  179                         .iter()
  180                         .map(|&(a, b)| {
  181                             let a = ref_data[a];
  182                             let b = scanner_data[matched][b].remap(*mapping);
  183                             Pos([a.0[0] - b.0[0], a.0[1] - b.0[1], a.0[2] - b.0[2]])
  184                         })
  185                         .collect::<HashSet<_>>();
  186                     if possible_scanner_pos.len() == 1 {
  187                         scanner_coord[matched] = Some(*possible_scanner_pos.iter().next().unwrap());
  188                         match_queue.push_back(matched);
  189                         let mut corrected_data = Vec::new();
  190                         for x in scanner_data[matched].iter() {
  191                             let x = x.project(
  192                                 *mapping,
  193                                 scanner_coord[0].unwrap(),
  194                                 scanner_coord[matched].unwrap(),
  195                             );
  196                             all_beacons.insert(x);
  197                             corrected_data.push(x);
  198                         }
  199                         corrected_scanner_data[matched] = Some(corrected_data);
  200                         break;
  201                     }
  202                 }
  203             }
  204         }
  205     }
  206     (
  207         all_beacons.len(),
  208         scanner_coord.into_iter().map(|x| x.unwrap()).collect(),
  209     )
  210 }
  211 
  212 fn part_2(scanner_coord: &Vec<Pos>) -> i32 {
  213     let mut max_mdist = 0;
  214     for a in scanner_coord.iter() {
  215         for b in scanner_coord.iter() {
  216             max_mdist = max_mdist.max(a.dist(b).0);
  217         }
  218     }
  219     max_mdist
  220 }