Advertisement
nairby

AOC 2023 Day 3

Dec 3rd, 2023
1,145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.07 KB | None | 0 0
  1. use std::env;
  2. use std::io::{self, prelude::*, BufReader};
  3. use std::fs::File;
  4. use std::collections::HashMap;
  5.  
  6. use point2d::point2d::Point2D;
  7.  
  8. fn neighbors(start: &Point2D, end: &Point2D) -> Vec<Point2D> {
  9.     let mut neighbors = Vec::new();
  10.     neighbors.push(Point2D {x: start.x - 1, y: start.y    }); // start:left
  11.     neighbors.push(Point2D {x: start.x - 1, y: start.y - 1}); // start:left-up
  12.     neighbors.push(Point2D {x: start.x - 1, y: start.y + 1}); // start:left-down
  13.     neighbors.push(Point2D {x: end.x   + 1, y: end.y      }); // end:right
  14.     neighbors.push(Point2D {x: end.x   + 1, y: end.y   - 1}); // end:right-up
  15.     neighbors.push(Point2D {x: end.x   + 1, y: end.y   + 1}); // end:right-down
  16.     for x in start.x..=end.x {
  17.         neighbors.push(Point2D {x: x      , y: start.y - 1}); // up
  18.         neighbors.push(Point2D {x: x      , y: start.y + 1}); // down
  19.     }
  20.     neighbors
  21. }
  22.  
  23. fn is_number(ch: char) -> bool {
  24.     match ch {
  25.         '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => true,
  26.         _ => false,
  27.     }
  28. }
  29.  
  30. fn is_symbol(ch: char) -> bool {
  31.     if is_number(ch) { return false }
  32.     if ch == '.'     { return false }
  33.     true
  34. }
  35.  
  36. fn is_gear_symbol(ch: char) -> bool {
  37.     if ch == '*' { return true }
  38.     false
  39. }
  40.  
  41. // Returns the actual number from a vec of numeric characters
  42. fn number_from_digits(digits: Vec<char>) -> i64 {
  43.     digits
  44.         .iter()
  45.         .rev()
  46.         .enumerate()
  47.         .map(|(i,digit)| digit.to_digit(10).unwrap() as i64 * i64::pow(10,i.try_into().unwrap()))
  48.         .sum()
  49. }
  50.  
  51. // Verifies that a given part number is valid based on adjacency to any symbol
  52. fn is_valid_part_number(start: &Point2D, end: &Point2D, map: &HashMap<Point2D,char>) -> bool {
  53.     for n in neighbors(&start, &end) {
  54.         match map.get(&n) {
  55.             Some(ch) => if is_symbol(*ch) { return true },
  56.             None => {},
  57.         }
  58.     }
  59.     false
  60. }
  61.  
  62. // Returns all gear symbol Point2D adjacent to a number
  63. fn adjacent_gears(start: &Point2D, end: &Point2D, map: &HashMap<Point2D,char>) -> Vec<Point2D> {
  64.     let mut gears: Vec<Point2D> = Vec::new();
  65.     for n in neighbors(&start, &end) {
  66.         match map.get(&n) {
  67.             Some(ch) => if is_gear_symbol(*ch) { gears.push(n) },
  68.             None => {},
  69.         }
  70.     }
  71.     gears
  72. }
  73.  
  74. // Extracts the current number and returns the end point thereof
  75. fn extract_number(start: &Point2D, map: &HashMap<Point2D,char>) -> (i64, Point2D) {
  76.     let mut digits: Vec<char> = Vec::new();
  77.     let mut end_pt = Point2D { x: start.x, y: start.y };
  78.     'find_lp: loop {
  79.        match map.get(&end_pt) {
  80.            Some(ch) => {
  81.                if is_number(*ch) { digits.push(*ch); }
  82.                else { break 'find_lp }
  83.             },
  84.             None => break 'find_lp,
  85.        }
  86.        end_pt.x += 1;
  87.    }
  88.    end_pt.x -= 1;
  89.    (number_from_digits(digits),end_pt)
  90. }
  91.  
  92. fn solve(input: &str) -> io::Result<()> {
  93.    let file = File::open(input).expect("Input file not found.");
  94.    let reader = BufReader::new(file);
  95.  
  96.    // Input
  97.    let input: Vec<String> = match reader.lines().collect() {
  98.        Err(err) => panic!("Unknown error reading input: {err}"),
  99.        Ok(result) => result,
  100.    };
  101.  
  102.    // Build map
  103.    let mut part_numbers: HashMap<Point2D,char> = HashMap::new();
  104.    for (y,line) in input.iter().enumerate() {
  105.        for (x,ch) in line.chars().enumerate() {
  106.            let pt = Point2D { x: x as i64, y: y as i64 };
  107.            part_numbers.insert(pt, ch);
  108.        }
  109.    }
  110.    let xmax = &part_numbers.keys().map(|&pt| pt.x).max().unwrap();
  111.    let ymax = &part_numbers.keys().map(|&pt| pt.y).max().unwrap();
  112.  
  113.    // Solve
  114.    let mut part1: i64 = 0;
  115.    let mut potential_gears: HashMap<Point2D,Vec<i64>> = HashMap::new();
  116.    for y in 0..=*ymax {
  117.        let mut pt = Point2D { x: 0, y: y };
  118.        loop {
  119.            let ch = part_numbers.get(&pt).unwrap();
  120.            if is_number(*ch) {
  121.                let (num,end) = extract_number(&pt, &part_numbers);
  122.                // Part 1
  123.                if is_valid_part_number(&pt, &end, &part_numbers) {
  124.                    part1 += num;
  125.                }
  126.                // Part 2
  127.                for gear in adjacent_gears(&pt, &end, &part_numbers) {
  128.                    if potential_gears.contains_key(&gear) {
  129.                        potential_gears.get_mut(&gear).unwrap().push(num);
  130.                    } else {
  131.                        potential_gears.insert(gear,vec![num]);
  132.                    }
  133.                }
  134.                pt.x = end.x + 1;
  135.            } else {
  136.                pt.x += 1;
  137.            }
  138.            if pt.x >= *xmax { break }
  139.        }
  140.    }
  141.    println!("Part 1: {part1}"); // 525119
  142.  
  143.    // Part 2
  144.    let part2: i64 = potential_gears
  145.        .iter()
  146.        .filter(|(_,v)| v.len() == 2)
  147.        .map(|(_,v)| v.iter().product::<i64>())
  148.        .sum();
  149.    println!("Part 2: {part2}"); // 76504829
  150.  
  151.    Ok(())
  152. }
  153.  
  154. fn main() {
  155.    let args: Vec<String> = env::args().collect();
  156.    let filename = &args[1];
  157.    solve(&filename).unwrap();
  158. }
  159.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement