Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::env;
- use std::io::{self, prelude::*, BufReader};
- use std::fs::File;
- use std::collections::HashMap;
- use point2d::point2d::Point2D;
- fn neighbors(start: &Point2D, end: &Point2D) -> Vec<Point2D> {
- let mut neighbors = Vec::new();
- neighbors.push(Point2D {x: start.x - 1, y: start.y }); // start:left
- neighbors.push(Point2D {x: start.x - 1, y: start.y - 1}); // start:left-up
- neighbors.push(Point2D {x: start.x - 1, y: start.y + 1}); // start:left-down
- neighbors.push(Point2D {x: end.x + 1, y: end.y }); // end:right
- neighbors.push(Point2D {x: end.x + 1, y: end.y - 1}); // end:right-up
- neighbors.push(Point2D {x: end.x + 1, y: end.y + 1}); // end:right-down
- for x in start.x..=end.x {
- neighbors.push(Point2D {x: x , y: start.y - 1}); // up
- neighbors.push(Point2D {x: x , y: start.y + 1}); // down
- }
- neighbors
- }
- fn is_number(ch: char) -> bool {
- match ch {
- '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => true,
- _ => false,
- }
- }
- fn is_symbol(ch: char) -> bool {
- if is_number(ch) { return false }
- if ch == '.' { return false }
- true
- }
- fn is_gear_symbol(ch: char) -> bool {
- if ch == '*' { return true }
- false
- }
- // Returns the actual number from a vec of numeric characters
- fn number_from_digits(digits: Vec<char>) -> i64 {
- digits
- .iter()
- .rev()
- .enumerate()
- .map(|(i,digit)| digit.to_digit(10).unwrap() as i64 * i64::pow(10,i.try_into().unwrap()))
- .sum()
- }
- // Verifies that a given part number is valid based on adjacency to any symbol
- fn is_valid_part_number(start: &Point2D, end: &Point2D, map: &HashMap<Point2D,char>) -> bool {
- for n in neighbors(&start, &end) {
- match map.get(&n) {
- Some(ch) => if is_symbol(*ch) { return true },
- None => {},
- }
- }
- false
- }
- // Returns all gear symbol Point2D adjacent to a number
- fn adjacent_gears(start: &Point2D, end: &Point2D, map: &HashMap<Point2D,char>) -> Vec<Point2D> {
- let mut gears: Vec<Point2D> = Vec::new();
- for n in neighbors(&start, &end) {
- match map.get(&n) {
- Some(ch) => if is_gear_symbol(*ch) { gears.push(n) },
- None => {},
- }
- }
- gears
- }
- // Extracts the current number and returns the end point thereof
- fn extract_number(start: &Point2D, map: &HashMap<Point2D,char>) -> (i64, Point2D) {
- let mut digits: Vec<char> = Vec::new();
- let mut end_pt = Point2D { x: start.x, y: start.y };
- 'find_lp: loop {
- match map.get(&end_pt) {
- Some(ch) => {
- if is_number(*ch) { digits.push(*ch); }
- else { break 'find_lp }
- },
- None => break 'find_lp,
- }
- end_pt.x += 1;
- }
- end_pt.x -= 1;
- (number_from_digits(digits),end_pt)
- }
- fn solve(input: &str) -> io::Result<()> {
- let file = File::open(input).expect("Input file not found.");
- let reader = BufReader::new(file);
- // Input
- let input: Vec<String> = match reader.lines().collect() {
- Err(err) => panic!("Unknown error reading input: {err}"),
- Ok(result) => result,
- };
- // Build map
- let mut part_numbers: HashMap<Point2D,char> = HashMap::new();
- for (y,line) in input.iter().enumerate() {
- for (x,ch) in line.chars().enumerate() {
- let pt = Point2D { x: x as i64, y: y as i64 };
- part_numbers.insert(pt, ch);
- }
- }
- let xmax = &part_numbers.keys().map(|&pt| pt.x).max().unwrap();
- let ymax = &part_numbers.keys().map(|&pt| pt.y).max().unwrap();
- // Solve
- let mut part1: i64 = 0;
- let mut potential_gears: HashMap<Point2D,Vec<i64>> = HashMap::new();
- for y in 0..=*ymax {
- let mut pt = Point2D { x: 0, y: y };
- loop {
- let ch = part_numbers.get(&pt).unwrap();
- if is_number(*ch) {
- let (num,end) = extract_number(&pt, &part_numbers);
- // Part 1
- if is_valid_part_number(&pt, &end, &part_numbers) {
- part1 += num;
- }
- // Part 2
- for gear in adjacent_gears(&pt, &end, &part_numbers) {
- if potential_gears.contains_key(&gear) {
- potential_gears.get_mut(&gear).unwrap().push(num);
- } else {
- potential_gears.insert(gear,vec![num]);
- }
- }
- pt.x = end.x + 1;
- } else {
- pt.x += 1;
- }
- if pt.x >= *xmax { break }
- }
- }
- println!("Part 1: {part1}"); // 525119
- // Part 2
- let part2: i64 = potential_gears
- .iter()
- .filter(|(_,v)| v.len() == 2)
- .map(|(_,v)| v.iter().product::<i64>())
- .sum();
- println!("Part 2: {part2}"); // 76504829
- Ok(())
- }
- fn main() {
- let args: Vec<String> = env::args().collect();
- let filename = &args[1];
- solve(&filename).unwrap();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement