Guest User

Untitled

a guest
Dec 9th, 2021
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 4.49 KB | None | 0 0
  1. use std::cmp::Reverse;
  2. use std::collections::BinaryHeap;
  3. use fixedbitset::FixedBitSet;
  4. use petgraph::Graph;
  5. use petgraph::graph::NodeIndex;
  6. use petgraph::visit::{Visitable, VisitMap};
  7.  
  8. /// Get basin related to a given node.
  9. ///
  10. /// # Arguments
  11. ///
  12. /// * `graph` - The whole graph.
  13. /// * `visited` - A visit lookahead...
  14. /// * `node` - The current node position in the graph.
  15. fn get_basin(graph: &Graph<i32, (), petgraph::Undirected>, visited: &mut FixedBitSet, node: &NodeIndex) -> Vec<NodeIndex> {
  16.     let mut visit_next = BinaryHeap::new();
  17.     let mut result = Vec::new();
  18.  
  19.     visit_next.push(*node);
  20.  
  21.     while let Some(walk) = visit_next.pop() {
  22.         if visited.is_visited(&walk) {
  23.             continue;
  24.         }
  25.  
  26.         // Mark as visited, register if wanted into the result...
  27.         visited.visit(walk);
  28.         if graph[walk] < 9 {
  29.             result.push(walk);
  30.         }
  31.  
  32.         let neighbors = graph.neighbors(walk);
  33.         for neighbor in neighbors {
  34.             if graph[neighbor] < 9 {
  35.                 visit_next.push(neighbor);
  36.             }
  37.         }
  38.     }
  39.  
  40.     result
  41. }
  42.  
  43. fn aoc_09_part02(graph: &Graph<i32, (), petgraph::Undirected>) -> usize {
  44.     let mut visited = graph.visit_map();
  45.     let mut basins: Vec<Vec<NodeIndex>> = Vec::new();
  46.  
  47.     // Walk the graph...
  48.     graph.node_indices().into_iter().for_each(|idx| {
  49.         // Its a basin we haven't seen yet... So we trace it...
  50.         if graph[idx] < 9 && !visited.is_visited(&idx) {
  51.             // we find the basin
  52.             let basin: Vec<NodeIndex> = get_basin(graph, &mut visited, &idx);
  53.  
  54.             if !basin.is_empty() {
  55.                 basins.push(basin);
  56.             }
  57.         }
  58.     });
  59.  
  60.     // Biggest first
  61.     basins.sort_unstable_by_key(|b| Reverse(b.len()));
  62.  
  63.     // Selecting top 3 only and multiply their length
  64.     basins[..=2].iter().fold(0, |acc, val| if acc == 0 { val.len() } else { acc * val.len() })
  65. }
  66.  
  67. fn aoc_09_part01(graph: &Graph<i32, (), petgraph::Undirected>) -> i32 {
  68.     let selected_nodes = graph.node_indices().into_iter().filter(|idx| {
  69.         let nodes = graph.neighbors(*idx);
  70.         let node = graph[*idx];
  71.         for sibling in nodes {
  72.             // The current node is not the minimum. We can stop here...
  73.             if graph[sibling] <= node {
  74.                 return false;
  75.             }
  76.         }
  77.  
  78.         true
  79.     }).collect::<Vec<_>>();
  80.  
  81.     // The result is 1 + its height for each point
  82.     selected_nodes.iter().map(|idx| graph.node_weight(*idx).unwrap_or(&0) + 1).sum()
  83. }
  84.  
  85. macro_rules! create_edge {
  86.     ($graph: ident, $nodes: ident, $node: ident, $i: expr, $j: expr) => {
  87.         if $i >= 0 && $j >= 0 {
  88.             let el = $nodes.get($i as usize).and_then(|row| row.get($j as usize));
  89.             if el.is_some() {
  90.                 $graph.add_edge($node, *el.unwrap(), ());
  91.             }
  92.         }
  93.     }
  94. }
  95.  
  96. /// Convert vec of vec into a graph.
  97. ///
  98. /// # Arguments
  99. ///
  100. /// * `input` - The input to convert as a graph (petgraph)
  101. fn convert_to_graph(input: &[Vec<i32>]) -> Graph<i32, (), petgraph::Undirected> {
  102.     let mut deps = Graph::<i32, (), petgraph::Undirected>::new_undirected();
  103.  
  104.     // Creating graph nodes
  105.     let nodes = input.iter().map(|line| {
  106.         line.iter().map(|el| deps.add_node(*el)).collect::<Vec<_>>()
  107.     }).collect::<Vec<Vec<_>>>();
  108.  
  109.     // Creating graph edges
  110.     for i in 0..nodes.len() as i32 {
  111.         for j in 0..nodes[i as usize].len() as i32 {
  112.             let node = nodes[i as usize][j as usize];
  113.             // Up
  114.             create_edge!(deps, nodes, node, i - 1, j);
  115.             // Left
  116.             create_edge!(deps, nodes, node, i, j - 1);
  117.             // Its not a directed graph so we dont need to create dual sided links...
  118.             // so up/left is enough to model the structure.
  119.             // Down
  120.             // create_edge!(deps, nodes, node, i + 1, j);
  121.             // Right
  122.             // create_edge!(deps, nodes, node, i, j + 1);
  123.         }
  124.     }
  125.  
  126.     deps
  127. }
  128.  
  129. fn main() {
  130.     let s = include_str!("../input.txt").lines().map(|line| {
  131.         line.chars().filter_map(|c| c.to_string().parse::<i32>().ok()).collect::<Vec<_>>()
  132.     }).collect::<Vec<Vec<_>>>();
  133.  
  134.     // We convert this to a graph...
  135.     let graph = convert_to_graph(&s);
  136.     // println!("{:#?}", petgraph::dot::Dot::new(&graph));
  137.  
  138.     let result = aoc_09_part01(&graph);
  139.     println!("Result part 1: {}", result);
  140.  
  141.     let result = aoc_09_part02(&graph);
  142.     println!("Result part 2: {}", result);
  143. }
  144.  
Advertisement
Add Comment
Please, Sign In to add comment