Advertisement
nairby

Day 19 Code

Dec 29th, 2021
593
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 8.21 KB | None | 0 0
  1. use std::env;
  2. use std::io::{self};
  3. use std::collections::{HashSet,HashMap};
  4.  
  5. extern crate regex;
  6. use regex::Regex;
  7.  
  8. use point3d::point3d::Point3D;
  9.  
  10. type Tuple3D = ((i64,i64,i64),(i64,i64,i64),(i64,i64,i64));
  11.  
  12. // https://www.euclideanspace.com/maths/algebra/matrix/transforms/examples/index.htm
  13. const ROT01: Tuple3D =
  14.     ((  1,  0,  0),
  15.      (  0,  1,  0),
  16.      (  0,  0,  1));
  17.  
  18. const ROT02: Tuple3D =
  19.     ((  1,  0,  0),
  20.      (  0,  0, -1),
  21.      (  0,  1,  0));
  22.  
  23. const ROT03: Tuple3D =
  24.     ((  1,  0,  0),
  25.      (  0, -1,  0),
  26.      (  0,  0, -1));
  27.  
  28. const ROT04: Tuple3D =
  29.     ((  1,  0,  0),
  30.      (  0,  0,  1),
  31.      (  0, -1,  0));
  32.  
  33. const ROT05: Tuple3D =
  34.     ((  0, -1,  0),
  35.      (  1,  0,  0),
  36.      (  0,  0,  1));
  37.  
  38. const ROT06: Tuple3D =
  39.     ((  0,  0,  1),
  40.      (  1,  0,  0),
  41.      (  0,  1,  0));
  42.  
  43. const ROT07: Tuple3D =
  44.     ((  0,  1,  0),
  45.      (  1,  0,  0),
  46.      (  0,  0, -1));
  47.  
  48. const ROT08: Tuple3D =
  49.     ((  0,  0, -1),
  50.      (  1,  0,  0),
  51.      (  0, -1,  0));
  52.  
  53. const ROT09: Tuple3D =
  54.     (( -1,  0,  0),
  55.      (  0, -1,  0),
  56.      (  0,  0,  1));
  57.  
  58. const ROT10: Tuple3D =
  59.     (( -1,  0,  0),
  60.      (  0,  0, -1),
  61.      (  0, -1,  0));
  62.  
  63. const ROT11: Tuple3D =
  64.     (( -1,  0,  0),
  65.      (  0,  1,  0),
  66.      (  0,  0, -1));
  67.  
  68. const ROT12: Tuple3D =
  69.     (( -1,  0,  0),
  70.      (  0,  0,  1),
  71.      (  0,  1,  0));
  72.  
  73. const ROT13: Tuple3D =
  74.     ((  0,  1,  0),
  75.      ( -1,  0,  0),
  76.      ( 0,   0,  1));
  77.  
  78. const ROT14: Tuple3D =
  79.     ((  0,  0,  1),
  80.      ( -1,  0,  0),
  81.      (  0, -1,  0));
  82.  
  83. const ROT15: Tuple3D =
  84.     ((  0, -1,  0),
  85.      ( -1,  0,  0),
  86.      (  0,  0, -1));
  87.  
  88. const ROT16: Tuple3D =
  89.     ((  0,  0, -1),
  90.      ( -1,  0,  0),
  91.      (  0,  1,  0));
  92.  
  93. const ROT17: Tuple3D =
  94.     ((  0,  0, -1),
  95.      (  0,  1,  0),
  96.      (  1,  0,  0));
  97.  
  98. const ROT18: Tuple3D =
  99.     ((  0,  1,  0),
  100.      (  0,  0,  1),
  101.      (  1,  0,  0));
  102.  
  103. const ROT19: Tuple3D =
  104.     ((  0,  0,  1),
  105.      (  0, -1,  0),
  106.      (  1,  0,  0));
  107.  
  108. const ROT20: Tuple3D =
  109.     ((  0, -1,  0),
  110.      (  0,  0, -1),
  111.      (  1,  0,  0));
  112.  
  113. const ROT21: Tuple3D =
  114.     ((  0,  0, -1),
  115.      (  0, -1,  0),
  116.      ( -1,  0,  0));
  117.  
  118. const ROT22: Tuple3D =
  119.     ((  0, -1,  0),
  120.      (  0,  0,  1),
  121.      ( -1,  0,  0));
  122.  
  123. const ROT23: Tuple3D =
  124.     ((  0,  0,  1),
  125.      (  0,  1,  0),
  126.      ( -1,  0,  0));
  127.  
  128. const ROT24: Tuple3D =
  129.     ((  0,  1,  0),
  130.      (  0,  0, -1),
  131.      ( -1,  0,  0));
  132.  
  133. const ALL_ROTATIONS: [Tuple3D; 24] =
  134.         [ROT01, ROT02, ROT03, ROT04, ROT05, ROT06,
  135.          ROT07, ROT08, ROT09, ROT10, ROT11, ROT12,
  136.          ROT13, ROT14, ROT15, ROT16, ROT17, ROT18,
  137.          ROT19, ROT20, ROT21, ROT22, ROT23, ROT24];
  138. // https://www.euclideanspace.com/maths/algebra/matrix/transforms/examples/index.htm
  139.  
  140. #[derive(Clone)]
  141. struct Scanner {
  142.     id: u8,
  143.     beacons: Vec<Point3D>,
  144.     fixed: bool,
  145.     origin: Point3D,
  146. }
  147. impl From<&str> for Scanner {
  148.     fn from(s: &str) -> Self {
  149.         let s: Vec<_> = s.split("\n").collect();
  150.  
  151.         // Get id
  152.         let re = Regex::new(r"scanner (\d+)").unwrap();
  153.         let matches = re.captures(s[0]).unwrap();
  154.         let id = matches[1].parse().unwrap();
  155.  
  156.         // Get beacons
  157.         let mut beacons: Vec<Point3D> = Vec::new();
  158.         let re = Regex::new(r"(\-*\d+),(\-*\d+),(\-*\d+)").unwrap();
  159.         for line in s[1..].into_iter() {
  160.             let matches = re.captures(line).unwrap();
  161.             let (x,y,z) = (matches[1].parse().unwrap(),matches[2].parse().unwrap(),matches[3].parse().unwrap());
  162.             beacons.push(Point3D { x: x, y: y, z: z });
  163.         }
  164.         Self { id: id, beacons: beacons, fixed: false, origin: Point3D::zeros() }
  165.     }
  166. }
  167.  
  168. fn rotate_by(pt: &mut Point3D, rotation: Tuple3D) {
  169.     let pt0 = pt.clone();
  170.     pt.x = rotation.0.0*pt0.x + rotation.0.1*pt0.y+rotation.0.2*pt0.z;
  171.     pt.y = rotation.1.0*pt0.x + rotation.1.1*pt0.y+rotation.1.2*pt0.z;
  172.     pt.z = rotation.2.0*pt0.x + rotation.2.1*pt0.y+rotation.2.2*pt0.z;
  173. }
  174. fn rotate_all_by(pts: &mut Vec<Point3D>, rotation: Tuple3D) {
  175.     pts.iter_mut().for_each(|mut x| rotate_by(&mut x,rotation))
  176. }
  177.  
  178. fn translate_xyz(pt: &mut Point3D, delx: i64, dely: i64, delz: i64) {
  179.     pt.x += delx;
  180.     pt.y += dely;
  181.     pt.z += delz;
  182. }
  183. fn translate_all_xyz(pts: &mut Vec<Point3D>, delx: i64, dely: i64, delz: i64) {
  184.     pts.iter_mut().for_each(|mut x| translate_xyz(&mut x,delx,dely,delz))
  185. }
  186.  
  187. fn manhattan_distance(pt1: &Point3D, pt2: &Point3D) -> i64 {
  188.     (pt1.x-pt2.x).abs() + (pt1.y-pt2.y).abs() + (pt1.z-pt2.z).abs()
  189. }
  190.  
  191. fn solve(input: &str) -> io::Result<()> {
  192.     // Input
  193.     let input_str = std::fs::read_to_string(input).unwrap();
  194.     let input_str = input_str.trim();
  195.     let input: Vec<_> = input_str.split("\n\n").collect();
  196.    
  197.     // Get scanner and beacon data
  198.     let mut scanners: Vec<_> = input
  199.         .iter()
  200.         .map(|x| Scanner::from(*x))
  201.         .collect();
  202.    
  203.     // Assume orientation of first scanner
  204.     scanners[0].fixed = true;
  205.  
  206.     // Generate initial composites from scanner 0
  207.     let mut composite: HashSet<Point3D> = HashSet::new();
  208.     for b in &scanners[0].beacons {
  209.         composite.insert(*b);
  210.     }
  211.  
  212.     'main: loop {
  213.        // Try to match unfixed scanners against fixed scanners
  214.        'scanner: for scanner in &mut scanners {
  215.             if scanner.fixed { continue; }
  216.  
  217.             for rot in ALL_ROTATIONS {
  218.                 let mut beacons = scanner.beacons.clone();
  219.                 rotate_all_by(&mut beacons, rot);
  220.  
  221.                 // Count x-, y-, z-offsets between these and known points
  222.                 let mut xcounts: HashMap<i64,i64> = HashMap::new();
  223.                 let mut ycounts: HashMap<i64,i64> = HashMap::new();
  224.                 let mut zcounts: HashMap<i64,i64> = HashMap::new();
  225.                 for beacon in &beacons {
  226.                     for comp in composite.iter() {
  227.                         *xcounts.entry(comp.x - beacon.x).or_insert(0) += 1;
  228.                         *ycounts.entry(comp.y - beacon.y).or_insert(0) += 1;
  229.                         *zcounts.entry(comp.z - beacon.z).or_insert(0) += 1;
  230.                     }
  231.                 }
  232.  
  233.                 // Generate x-, y-, z-offsets from counts and align scanner (if applicable)
  234.                 let xoffset = xcounts.iter().find(|&(_,v)| *v >= 12).map(|(k,_)| k);
  235.                 let yoffset = ycounts.iter().find(|&(_,v)| *v >= 12).map(|(k,_)| k);
  236.                 let zoffset = zcounts.iter().find(|&(_,v)| *v >= 12).map(|(k,_)| k);
  237.                
  238.                 // Sort offset results to avoid non-deterministic solution
  239.                 let mut xcounts2: Vec<_> = xcounts.iter().collect(); xcounts2.sort_by(|a,b| b.1.cmp(a.1));
  240.                 let mut ycounts2: Vec<_> = ycounts.iter().collect(); ycounts2.sort_by(|a,b| b.1.cmp(a.1));
  241.                 let mut zcounts2: Vec<_> = zcounts.iter().collect(); zcounts2.sort_by(|a,b| b.1.cmp(a.1));
  242.                 if xoffset.is_some() && yoffset.is_some() && zoffset.is_some() {
  243.                    
  244.                     let (newx,_) = *xcounts2.iter().next().unwrap();
  245.                     let (newy,_) = *ycounts2.iter().next().unwrap();
  246.                     let (newz,_) = *zcounts2.iter().next().unwrap();
  247.  
  248.                     scanner.beacons = beacons.clone();
  249.                     scanner.origin = Point3D::new(*newx,*newy,*newz);
  250.                     scanner.fixed = true;
  251.  
  252.                     // Add to composite
  253.                     translate_all_xyz(&mut beacons,*newx,*newy,*newz);
  254.                     for beacon in &beacons {
  255.                         composite.insert(*beacon);
  256.                     }
  257.                     continue 'scanner;
  258.                }
  259.            }
  260.        }
  261.  
  262.        // Check all scanners have been fixed
  263.        if scanners.iter().all(|s| s.fixed) { break 'main; }
  264.     }
  265.     println!("Part 1: {}", composite.len()); // 318
  266.  
  267.     // Part 2
  268.     let mut part2 = 0;
  269.     for scanner1 in &scanners {
  270.         for scanner2 in &scanners {
  271.             part2 = std::cmp::max(part2,
  272.                 manhattan_distance(&scanner1.origin,&scanner2.origin));
  273.         }
  274.     }
  275.     println!("Part 2: {}",part2); // 12166
  276.  
  277.  
  278.     Ok(())
  279. }
  280.  
  281. fn main() {
  282.     let args: Vec<String> = env::args().collect();
  283.     let filename = &args[1];
  284.     solve(&filename).unwrap();
  285. }
  286.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement