Advertisement
Guest User

DAY 19 FXHASH

a guest
Dec 20th, 2021
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 11.71 KB | None | 0 0
  1. use std::collections::{HashMap, HashSet};
  2. use itertools::Itertools;
  3. use pathfinding::num_traits::{abs, pow};
  4. use pathfinding::prelude::absdiff;
  5. use std::borrow::Borrow;
  6. use fxhash::{FxBuildHasher, FxHasher, FxHashMap, FxHashSet};
  7.  
  8.  
  9. fn euclid_dist(first: &(i64, i64, i64), second: &(i64, i64, i64)) -> i64 {
  10.     pow(first.0 - second.0, 2) + pow(first.1 - second.1, 2) + pow(first.2 - second.2, 2)
  11. }
  12.  
  13. fn rotation_matrix(a: &(i64, i64, i64)) -> Vec<((i64, i64, i64))> {
  14.     let &(x,y,z) = a;
  15.     vec![
  16.         (x, y, z),
  17.         (x, z, -y),
  18.         (x, -y, -z),
  19.         (x, -z, y),
  20.         (y, x, -z),
  21.         (y, z, x),
  22.         (y, -x, z),
  23.         (y, -z, -x),
  24.         (z, x, y),
  25.         (z, y, -x),
  26.         (z, -x, -y),
  27.         (z, -y, x),
  28.         (-x, y, -z),
  29.         (-x, z, y),
  30.         (-x, -y, z),
  31.         (-x, -z, -y),
  32.         (-y, x, z),
  33.         (-y, z, -x),
  34.         (-y, -x, -z),
  35.         (-y, -z, x),
  36.         (-z, x, -y),
  37.         (-z, y, x),
  38.         (-z, -x, y),
  39.         (-z, -y, -x),
  40.     ]
  41. }
  42.  
  43. fn rotate_and_translate_single(a: &(i64, i64, i64), rot: usize, b: &(i64, i64, i64)) -> (i64, i64, i64) {
  44.    let &(x,y, z) = a;
  45.    match rot {
  46.         0 => (x + b.0, y + b.1, z + b.2),
  47.         1 => (x + b.0, z + b.1, -y + b.2),
  48.         2 => (x + b.0, -y + b.1, -z + b.2),
  49.         3 => (x + b.0, -z + b.1, y + b.2),
  50.         4 => (y + b.0, x + b.1, -z + b.2),
  51.         5 => (y + b.0, z + b.1, x + b.2),
  52.         6 => (y + b.0, -x + b.1, z + b.2),
  53.         7 => (y + b.0, -z + b.1, -x + b.2),
  54.         8 => (z + b.0, x + b.1, y + b.2),
  55.         9 => (z + b.0, y + b.1, -x + b.2),
  56.         10 => (z + b.0, -x + b.1, -y + b.2),
  57.         11 => (z + b.0, -y + b.1, x + b.2),
  58.         12 => (-x + b.0, y + b.1, -z + b.2),
  59.         13 => (-x + b.0, z + b.1, y + b.2),
  60.         14 => (-x + b.0, -y + b.1, z + b.2),
  61.         15 => (-x + b.0, -z + b.1, -y + b.2),
  62.         16 => (-y + b.0, x + b.1, z + b.2),
  63.         17 => (-y + b.0, z + b.1, -x + b.2),
  64.         18 => (-y + b.0, -x + b.1, -z + b.2),
  65.         19 => (-y + b.0, -z + b.1, x + b.2),
  66.         20 => (-z + b.0, x + b.1, -y + b.2),
  67.         21 => (-z + b.0, y + b.1, x + b.2),
  68.         22 => (-z + b.0, -x + b.1, y + b.2),
  69.         23 => (-z + b.0, -y + b.1, -x + b.2),
  70.         _ => unreachable!(),
  71.     }
  72. }
  73.  
  74. pub fn day19_2UNSTABLE(){
  75.     let mut inputs: Vec<HashSet<(i64, i64, i64), FxBuildHasher>> = Vec::new();
  76.     include_str!("../temp19").split("\r\n\r\n").for_each(|x| {
  77.         let mut inner: HashSet<(i64, i64, i64), FxBuildHasher> = FxHashSet::default();
  78.         x.lines().skip(1).for_each(|x| {
  79.             inner.insert(x.split(',').map(|x| x.parse().unwrap()).collect_tuple().unwrap());
  80.         });
  81.         inputs.push(inner);
  82.     });
  83.     let mut all_distances = Vec::new();
  84.     let mut all_distances_dict = Vec::new();
  85.  
  86.     for input in &inputs {
  87.         let mut distances = FxHashSet::default();
  88.         let mut distances_dict = FxHashMap::default();
  89.         for (&first, &second) in input.iter().tuple_combinations() {
  90.             let euclid_dist : i64 = euclid_dist(&first, &second);
  91.             //let man_dist : i64 = absdiff(first.0, second.0) + absdiff(first.1, second.1) + absdiff(first.2, second.2); //euclid might be sufficient?
  92.             distances.insert(euclid_dist);
  93.             distances_dict.insert(euclid_dist, (first, second));
  94.         }
  95.         all_distances.push(distances);
  96.         all_distances_dict.push(distances_dict);
  97.     }
  98.     let mut rel_dists = vec![(0i64, 0i64, 0i64)];
  99.     loop {
  100.         let mut to_stich = ((0), (Vec::new()));
  101.         let first = &all_distances[0];
  102.         for (i2, second) in all_distances.iter().enumerate().skip(1) {
  103.             let intersection = first.intersection(second).collect_vec();
  104.             if intersection.len() >= 66 { //66 not 12 since 12 * 11 / 2 = 66 and thats the amount of intersections that they would have
  105.                 //stitch the first matching thing to the first one
  106.                 to_stich = (i2, intersection);
  107.                 break;
  108.             }
  109.         }
  110.         let first1 = &all_distances_dict[0];
  111.         let mut translation = FxHashMap::default();
  112.         for dists in to_stich.1 {
  113.             //find out if these two lines (formed by two points) are translations of each other (this doesnt work right now cause I'm not accounting for rotations)
  114.             let (p1_1, p1_2) = first1.get(dists).unwrap();
  115.             let (p2_1, p2_2) = all_distances_dict[to_stich.0].get(dists).unwrap();
  116.             //do another loop for rotations
  117.             rotation_matrix(&p2_1).iter().zip(rotation_matrix(&p2_2)).enumerate().for_each(|(i, (rp2_1, rp2_2))|
  118.                 {
  119.                     let dist_11 = euclid_dist(&rp2_1, p1_1);
  120.                     let dist_22 = euclid_dist(&rp2_2, p1_2);
  121.                     let dist_12 = euclid_dist(p1_1, &rp2_2);
  122.                     let dist_21 = euclid_dist(p1_2, &rp2_1);
  123.                     if absdiff(dist_11, dist_22) == 0 {
  124.                         //p1_1 is the same point as p2_1
  125.                         let counter = translation.entry(((p1_1.0 - rp2_1.0, p1_1.1 - rp2_1.1, p1_1.2 - rp2_1.2), i)).or_insert(0);
  126.                         *counter += 1;
  127.                     } else if absdiff(dist_12, dist_21) == 0 {
  128.                         //other match
  129.                         let counter = translation.entry(((p1_1.0 - rp2_2.0, p1_1.1 - rp2_2.1, p1_1.2 - rp2_2.2), i)).or_insert(0);
  130.                         *counter += 1;
  131.                     }
  132.                 });
  133.         };
  134.         let x = translation.iter().filter(|(x, &y)| y >= 66).next().unwrap(); //this assumes something to stitch
  135.         let insert = inputs[to_stich.0].iter().map(|y| {
  136.             rotate_and_translate_single(y, x.0.1, &x.0.0)
  137.         }).collect_vec();
  138.         rel_dists.push(x.0.0);
  139.         inputs[0].extend(&mut insert.iter());
  140.         //if that was the only element left break out of the loop.
  141.         if inputs.len() == 2 {
  142.             break;
  143.         }
  144.         //remove from everywhere it needs to be
  145.         inputs.remove(to_stich.0);
  146.         all_distances_dict.remove(to_stich.0);
  147.         all_distances.remove(to_stich.0);
  148.         //recalculate the thing
  149.         let mut distances = FxHashSet::default();
  150.         let mut distances_dict = FxHashMap::default();
  151.         for (&first, &second) in inputs[0].iter().tuple_combinations() {
  152.             let euclid_dist: i64 = euclid_dist(&first, &second);
  153.             //let man_dist: i64 = absdiff(first.0, second.0) + absdiff(first.1, second.1) + absdiff(first.2, second.2); //euclid might be sufficient?
  154.             distances.insert(euclid_dist);
  155.             distances_dict.insert(euclid_dist, (first, second));
  156.         }
  157.         all_distances[0] = distances;
  158.         all_distances_dict[0] = distances_dict;
  159.     }
  160.     println!("ANSWER {}", inputs[0].len());
  161.     println!("ANSWER PART 2 {}", rel_dists.iter().tuple_combinations().map(|((x1, y1, z1), (x2, y2, z2))| abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2)).max().unwrap());
  162.     return;
  163. }
  164.  
  165.  
  166. pub fn day19_2stable() {
  167.     let mut inputs = Vec::new();
  168.     include_str!("../temp19").split("\r\n\r\n").for_each(|x| {
  169.         let mut inner = FxHashSet::default();
  170.         x.lines().skip(1).for_each(|x| {
  171.             inner.insert(x.split(',').map(|x| x.parse().unwrap()).collect_tuple().unwrap());
  172.         });
  173.         inputs.push(inner);
  174.     });
  175.     let mut all_distances = Vec::new();
  176.     let mut all_distances_dict = Vec::new();
  177.  
  178.     for input in &inputs {
  179.         let mut distances = FxHashSet::default();
  180.         let mut distances_dict = FxHashMap::default();
  181.         for (&first, &second) in input.iter().tuple_combinations() {
  182.             let euclid_dist : i64 = euclid_dist(&first, &second);
  183.             let man_dist : i64 = absdiff(first.0, second.0) + absdiff(first.1, second.1) + absdiff(first.2, second.2); //euclid might be sufficient?
  184.             distances.insert((euclid_dist, man_dist));
  185.             distances_dict.insert((euclid_dist, man_dist), (first, second));
  186.         }
  187.         all_distances.push(distances);
  188.         all_distances_dict.push(distances_dict);
  189.     }
  190.     let mut rel_dists = vec![(0i64, 0i64, 0i64)];
  191.     loop {
  192.         let mut to_stich = ((0), (Vec::new()));
  193.         let first = &all_distances[0];
  194.         for (i2, second) in all_distances.iter().enumerate().skip(1) {
  195.             let intersection = first.intersection(second).collect_vec();
  196.             if intersection.len() >= 66 { //66 not 12 since 12 * 11 / 2 = 66 and thats the amount of intersections that they would have
  197.                 //stitch the first matching thing to the first one
  198.                 to_stich = (i2, intersection);
  199.                 break;
  200.             }
  201.         }
  202.         let mut translation = FxHashMap::default();
  203.         let thing = &all_distances_dict[0];
  204.         for dists in to_stich.1 {
  205.             //find out if these two lines (formed by two points) are translations of each other (this doesnt work right now cause I'm not accounting for rotations)
  206.             let (p1_1, p1_2) = thing.get(dists).unwrap();
  207.             let (p2_1, p2_2) = all_distances_dict[to_stich.0].get(dists).unwrap();
  208.             //do another loop for rotations
  209.             rotation_matrix(&p2_1).iter().zip(rotation_matrix(&p2_2)).enumerate().for_each(|(i, (rp2_1, rp2_2))|
  210.                 {
  211.                     let dist_11 = euclid_dist(&rp2_1, p1_1);
  212.                     let dist_22 = euclid_dist(&rp2_2, p1_2);
  213.                     let dist_12 = euclid_dist(p1_1, &rp2_2);
  214.                     let dist_21 = euclid_dist(p1_2, &rp2_1);
  215.                     if absdiff(dist_11, dist_22) == 0 {
  216.                         //p1_1 is the same point as p2_1
  217.                         let counter = translation.entry(((p1_1.0 - rp2_1.0, p1_1.1 - rp2_1.1, p1_1.2 - rp2_1.2), i)).or_insert(0);
  218.                         *counter += 1;
  219.                     } else if absdiff(dist_12, dist_21) == 0 {
  220.                         //other match
  221.                         let counter = translation.entry(((p1_1.0 - rp2_2.0, p1_1.1 - rp2_2.1, p1_1.2 - rp2_2.2), i)).or_insert(0);
  222.                         *counter += 1;
  223.                     }
  224.                 });
  225.         };
  226.  
  227.         let x = translation.iter().filter(|(x, &y)| y >= 66).next().unwrap(); //this assumes something to stitch
  228.         rel_dists.push(x.0.0);
  229.         //if that was the only element left break out of the loop. in part 2 we can leave earlier because we don't have to stitch.
  230.         //if inputs.len() == 2 {
  231.         //    break;
  232.         //}
  233.         let insert = inputs[to_stich.0].iter().map(|y| {
  234.             rotate_and_translate_single(y, x.0.1, &x.0.0)
  235.         }).collect_vec();
  236.  
  237.         inputs[0].extend(&mut insert.iter());
  238.  
  239.         if inputs.len() == 2 {
  240.             break;
  241.         }
  242.         //remove from everywhere it needs to be
  243.         inputs.remove(to_stich.0);
  244.         all_distances_dict.remove(to_stich.0);
  245.         all_distances.remove(to_stich.0);
  246.         //recalculate the thing
  247.         let mut distances = FxHashSet::default();
  248.         let mut distances_dict = FxHashMap::default();
  249.         for (&first, &second) in inputs[0].iter().tuple_combinations() {
  250.             let euclid_dist: i64 = euclid_dist(&first, &second);
  251.             let man_dist: i64 = absdiff(first.0, second.0) + absdiff(first.1, second.1) + absdiff(first.2, second.2); //euclid might be sufficient?
  252.             distances.insert((euclid_dist, man_dist));
  253.             distances_dict.insert((euclid_dist, man_dist), (first, second));
  254.         }
  255.         all_distances[0] = distances;
  256.         all_distances_dict[0] = distances_dict;
  257.     }
  258.     println!("ANSWER PART 1 {}", inputs[0].len());
  259.     println!("ANSWER PART 2 {}", rel_dists.iter().tuple_combinations().map(|((x1, y1, z1), (x2, y2, z2))| abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2)).max().unwrap());
  260.  
  261.     return;
  262. }
  263.  
  264.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement