Advertisement
Guest User

Untitled

a guest
Dec 11th, 2023
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 4.53 KB | None | 0 0
  1. use itertools::Itertools;
  2. use std::collections::BTreeMap;
  3.  
  4. fn main() {
  5.     let input = include_str!("../../input.txt");
  6.     let result = part2(input, 1_000_000);
  7.  
  8.     println!("{result}");
  9. }
  10.  
  11. fn part2(input: &str, n: usize) -> usize {
  12.     let universe = Universe::create(input, n - 1);
  13.     let pairs = universe.galaxy_pairs();
  14.     pairs.into_iter().map(|(src, dst)| src.manhattan(dst)).sum()
  15. }
  16.  
  17. #[derive(Debug)]
  18. enum Space {
  19.     Empty,
  20.     Galaxy,
  21. }
  22.  
  23. impl From<char> for Space {
  24.     fn from(value: char) -> Self {
  25.         match value {
  26.             '.' => Self::Empty,
  27.             '#' => Self::Galaxy,
  28.             val => panic!("invalid space: {val}"),
  29.         }
  30.     }
  31. }
  32.  
  33. #[derive(Debug)]
  34. struct Universe {
  35.     universe: BTreeMap<Point, Space>,
  36. }
  37.  
  38. #[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord)]
  39. struct Point(usize, usize);
  40. impl Point {
  41.     /// X is the row number
  42.     #[inline]
  43.     fn x(&self) -> usize {
  44.         self.0
  45.     }
  46.     /// Y is the column number
  47.     #[inline]
  48.     fn y(&self) -> usize {
  49.         self.1
  50.     }
  51.  
  52.     fn manhattan(&self, p: Point) -> usize {
  53.         let (x1, y1) = (self.x(), self.y());
  54.         let (x2, y2) = (p.x(), p.y());
  55.         x1.abs_diff(x2) + y1.abs_diff(y2)
  56.     }
  57. }
  58.  
  59. impl Universe {
  60.     fn create(input: &str, n: usize) -> Self {
  61.         let universe = Expander::new(input).expand_universe(input, n);
  62.         Self { universe }
  63.     }
  64.  
  65.     fn galaxies(&self) -> Vec<Point> {
  66.         self.universe
  67.             .iter()
  68.             .filter_map(|(&point, space)| match space {
  69.                 Space::Galaxy => Some(point),
  70.                 _ => None,
  71.             })
  72.             .collect()
  73.     }
  74.  
  75.     fn galaxy_pairs(&self) -> Vec<(Point, Point)> {
  76.         self.galaxies()
  77.             .into_iter()
  78.             .tuple_combinations()
  79.             .collect_vec()
  80.     }
  81. }
  82.  
  83. #[derive(Debug)]
  84. struct Expander {
  85.     rows: Vec<usize>,
  86.     cols: Vec<usize>,
  87. }
  88.  
  89. impl Expander {
  90.     fn new(input: &str) -> Self {
  91.         // count rows
  92.         let rows = input
  93.             .lines()
  94.             .enumerate()
  95.             .filter_map(|(i, line)| if !line.contains('#') { Some(i) } else { None })
  96.             .collect_vec();
  97.  
  98.         // count cols
  99.         let col_count = input.lines().next().unwrap().chars().count();
  100.         let cols = (0..col_count)
  101.             .filter(|&c| {
  102.                 input
  103.                     .lines()
  104.                     .all(|line| line.chars().nth(c).unwrap() != '#')
  105.             })
  106.             .collect_vec();
  107.  
  108.         Self { rows, cols }
  109.     }
  110.  
  111.     /// Expands universe, with empty row/cols expanded by factor n
  112.     fn expand_universe(&self, input: &str, n: usize) -> BTreeMap<Point, Space> {
  113.         let mut expanded_uni = BTreeMap::new();
  114.  
  115.         let (mut x_offset, mut y_offset) = (0, 0);
  116.         for (i, line) in input.lines().enumerate() {
  117.             if self.rows.contains(&i) {
  118.                 x_offset += n;
  119.                 continue;
  120.             }
  121.             for (j, space) in line.char_indices() {
  122.                 if self.cols.contains(&j) {
  123.                     y_offset += n;
  124.                     continue;
  125.                 }
  126.                 expanded_uni.insert(Point(i + x_offset, j + y_offset), space.into());
  127.             }
  128.             y_offset = 0;
  129.         }
  130.  
  131.         expanded_uni
  132.     }
  133. }
  134.  
  135. #[cfg(test)]
  136. mod tests {
  137.     use super::*;
  138.     use indoc::indoc;
  139.  
  140.     #[test]
  141.     fn test_part2() {
  142.         let input = indoc! {"
  143.        ...#......
  144.        .......#..
  145.        #.........
  146.        ..........
  147.        ......#...
  148.        .#........
  149.        .........#
  150.        ..........
  151.        .......#..
  152.        #...#....."};
  153.         let result = part2(input, 10);
  154.         assert_eq!(result, 1030);
  155.     }
  156.  
  157.     #[test]
  158.     fn test_universe_pairs() {
  159.         let input = indoc! {"
  160.        ...#......
  161.        .......#..
  162.        #.........
  163.        ..........
  164.        ......#...
  165.        .#........
  166.        .........#
  167.        ..........
  168.        .......#..
  169.        #...#....."};
  170.         let universe = Universe::create(input, 1);
  171.         assert_eq!(universe.galaxy_pairs().len(), 36);
  172.     }
  173.  
  174.     #[test]
  175.     fn test_expander() {
  176.         let input = indoc! {"
  177.        ...#......
  178.        .......#..
  179.        #.........
  180.        ..........
  181.        ......#...
  182.        .#........
  183.        .........#
  184.        ..........
  185.        .......#..
  186.        #...#....."};
  187.         let result = Expander::new(input);
  188.  
  189.         assert_eq!(result.rows, vec![3, 7]);
  190.         assert_eq!(result.cols, vec![2, 5, 8]);
  191.     }
  192. }
  193.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement