Advertisement
Guest User

Untitled

a guest
Dec 12th, 2024
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 4.17 KB | None | 0 0
  1. use std::collections::HashSet;
  2. use grid::*;
  3.  
  4. fn main() {
  5.     let mut input = include_str!("../input.txt").lines().peekable();
  6.     let width = input.peek().unwrap().len();
  7.     let mut grid = Grid::from_vec(input.flat_map(|l| l.chars()).collect(), width);
  8.  
  9.     let time = std::time::Instant::now();
  10.  
  11.     let mut sum = 0;
  12.  
  13.     let mut cells = HashSet::new();
  14.     let mut edges: Vec<EdgeDir> = Vec::new();
  15.     for i in 0..width * grid.rows() {
  16.         let x = (i % width) as i16;
  17.         let y = (i / width) as i16;
  18.  
  19.         let cell = grid[(y as usize, x as usize)];
  20.  
  21.         if cell == '#' {
  22.             continue;
  23.         }
  24.  
  25.         cells.clear();
  26.         edges.clear();
  27.         explore(x, y, cell, &mut grid, &mut cells, &mut edges);
  28.  
  29.         let mut sides: Vec<Vec<EdgeDir>> = Vec::new();
  30.         for edge in edges.iter() {
  31.  
  32.             // Check for adjacent sides
  33.             let (left, right) = match edge {
  34.                 EdgeDir::Horizontal(ed) => (
  35.                     find_edge_in_side(&sides, ed.0, ed.1, ed.2, ed.3, 0, -1),
  36.                     find_edge_in_side(&sides, ed.0, ed.1, ed.2, ed.3, 0,  1)
  37.                 ),
  38.                 EdgeDir::Vertical(ed) => (
  39.                     find_edge_in_side(&sides, ed.0, ed.1, ed.2, ed.3, -1, 0),
  40.                     find_edge_in_side(&sides, ed.0, ed.1, ed.2, ed.3,  1, 0)
  41.                 )
  42.             };
  43.  
  44.             if let (Some(left), Some(right)) = (left, right) {
  45.                 // Two adjacent sides discovered, link them up
  46.                 let mut combined = sides[left].clone();
  47.                 combined.extend(sides[right].clone());
  48.                 combined.push(*edge);
  49.                 sides[left] = combined;
  50.                 sides.remove(right);
  51.  
  52.             } else if let Some(left) = left {
  53.                 // Join with left side
  54.                 sides[left].push(*edge);
  55.  
  56.             } else if let Some(right) = right {
  57.                 // Join with right side
  58.                 sides[right].push(*edge);
  59.  
  60.             } else {
  61.                 // New side discovered
  62.                 sides.push(vec![*edge]);
  63.             }
  64.         }
  65.  
  66.         sum += cells.len() as u32 * sides.len() as u32;
  67.     }
  68.  
  69.     println!("Time: {:?}", time.elapsed());
  70.     println!("🪵 answer: {:#?}", sum);
  71. }
  72.  
  73. type Edge = (i16, i16, i16, i16);
  74. #[derive(Copy, Clone, PartialEq, Debug)]
  75. enum EdgeDir {
  76.     Horizontal(Edge),
  77.     Vertical(Edge)
  78. }
  79.  
  80. impl EdgeDir {
  81.     fn unwrap(self) -> Edge {
  82.         match self {
  83.             EdgeDir::Horizontal(edge) | EdgeDir::Vertical(edge) => edge
  84.         }
  85.     }
  86. }
  87.  
  88. fn explore(
  89.     x: i16,
  90.     y: i16,
  91.     cell: char,
  92.     grid: &mut Grid<char>,
  93.     cells: &mut HashSet<(i16, i16)>,
  94.     edges: &mut Vec<EdgeDir>
  95. ) -> bool {
  96.     if cells.contains(&(y, x)) {
  97.         return false; // Not an edge
  98.     }
  99.  
  100.     if let Some(other) = grid.get(y, x) {
  101.         if *other == cell {
  102.             // Same plant does not add perimeter, but does add area (cells)
  103.             cells.insert((y, x));
  104.             grid[(y as usize, x as usize)] = '#';
  105.  
  106.             if explore(x, y - 1, cell, grid, cells, edges) {
  107.                 edges.push(EdgeDir::Vertical((x, y, x, y - 1)));
  108.             }
  109.  
  110.             if explore(x + 1, y, cell, grid, cells, edges) {
  111.                 edges.push(EdgeDir::Horizontal((x, y, x + 1, y)));
  112.             }
  113.  
  114.             if explore(x, y + 1, cell, grid, cells, edges) {
  115.                 edges.push(EdgeDir::Vertical((x, y, x, y + 1)));
  116.             }
  117.  
  118.             if explore(x - 1, y, cell, grid, cells, edges) {
  119.                 edges.push(EdgeDir::Horizontal((x, y, x - 1, y)));
  120.             }
  121.  
  122.             return false; // Not an edge
  123.         }
  124.     }
  125.  
  126.     // Is an edge
  127.     true
  128. }
  129.  
  130. fn find_edge_in_side(
  131.     sides: &Vec<Vec<EdgeDir>>,
  132.     x: i16,
  133.     y: i16,
  134.     tx: i16,
  135.     ty: i16,
  136.     xd: i16,
  137.     yd: i16,
  138. ) -> Option<usize> {
  139.     for (index, edges) in sides.iter().enumerate() {
  140.         if edges.iter().any(|edge| {
  141.             let (x1, y1, x2, y2) = edge.unwrap();
  142.  
  143.             x1 == x  + xd && y1 == y  + yd &&
  144.             x2 == tx + xd && y2 == ty + yd
  145.         }) {
  146.             return Some(index);
  147.         }
  148.     }
  149.  
  150.     None
  151. }
  152.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement