day3: problem 2 solution. this is ugly.
This commit is contained in:
		
							
								
								
									
										163
									
								
								3/src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								3/src/main.rs
									
									
									
									
									
								
							@@ -1,5 +1,7 @@
 | 
			
		||||
use num::traits;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::io::{BufRead, BufReader, Lines};
 | 
			
		||||
use std::ops::Range;
 | 
			
		||||
 | 
			
		||||
// --- Day 3: Gear Ratios ---
 | 
			
		||||
 | 
			
		||||
@@ -52,6 +54,7 @@ fn main() {
 | 
			
		||||
 | 
			
		||||
// We will store the schematic as a 2D Vector of char
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Pos(usize, usize);
 | 
			
		||||
 | 
			
		||||
// Outer Vec holds rows, so addressing is column then row
 | 
			
		||||
@@ -85,6 +88,19 @@ const ADJACENCY_OFFSETS: &[(i64, i64)] = &[
 | 
			
		||||
 | 
			
		||||
// We assume the schematic is composed of equal length lines
 | 
			
		||||
impl Schematic {
 | 
			
		||||
    fn in_bounds<T: PartialOrd + num::traits::Zero + TryFrom<usize>>(&self, x: T, y: T) -> bool {
 | 
			
		||||
        let x_bound: T = self.0[0]
 | 
			
		||||
            .0
 | 
			
		||||
            .len()
 | 
			
		||||
            .try_into()
 | 
			
		||||
            .unwrap_or_else(|_| panic!("bad bounds"));
 | 
			
		||||
        let y_bound: T = self
 | 
			
		||||
            .0
 | 
			
		||||
            .len()
 | 
			
		||||
            .try_into()
 | 
			
		||||
            .unwrap_or_else(|_| panic!("bad bounds"));
 | 
			
		||||
        x >= T::zero() && x < x_bound && y >= T::zero() && y < y_bound
 | 
			
		||||
    }
 | 
			
		||||
    fn at(&self, pos: &Pos) -> char {
 | 
			
		||||
        self.0[pos.1].0[pos.0]
 | 
			
		||||
    }
 | 
			
		||||
@@ -94,11 +110,7 @@ impl Schematic {
 | 
			
		||||
            let adj_x = (pos.0 as i64) + x_ofs;
 | 
			
		||||
            let adj_y = (pos.1 as i64) + y_ofs;
 | 
			
		||||
 | 
			
		||||
            if adj_x < 0
 | 
			
		||||
                || adj_x >= self.0[pos.1].0.len() as i64
 | 
			
		||||
                || adj_y < 0
 | 
			
		||||
                || adj_y >= self.0.len() as i64
 | 
			
		||||
            {
 | 
			
		||||
            if !self.in_bounds(adj_x, adj_y) {
 | 
			
		||||
                false
 | 
			
		||||
            } else {
 | 
			
		||||
                let adj_c = self.at(&Pos(adj_x as usize, adj_y as usize));
 | 
			
		||||
@@ -106,6 +118,95 @@ impl Schematic {
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_gear(&self, pos: &Pos) -> bool {
 | 
			
		||||
        if self.at(pos) != '*' {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ADJACENCY_OFFSETS
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter(|(x_ofs, y_ofs)| {
 | 
			
		||||
                let adj_x = (pos.0 as i64) + x_ofs;
 | 
			
		||||
                let adj_y = (pos.1 as i64) + y_ofs;
 | 
			
		||||
 | 
			
		||||
                if adj_x < 0
 | 
			
		||||
                    || adj_x >= self.0[pos.1].0.len() as i64
 | 
			
		||||
                    || adj_y < 0
 | 
			
		||||
                    || adj_y >= self.0.len() as i64
 | 
			
		||||
                {
 | 
			
		||||
                    false
 | 
			
		||||
                } else {
 | 
			
		||||
                    let adj_c = self.at(&Pos(adj_x as usize, adj_y as usize));
 | 
			
		||||
                    adj_c.is_digit(10)
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .count()
 | 
			
		||||
            >= 2
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn gear_ratio(&self, pos: &Pos) -> Option<u64> {
 | 
			
		||||
        if self.at(pos) != '*' {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut exclusions: Vec<(Range<usize>, i64)> = Vec::new();
 | 
			
		||||
        let mut nums = (0u64, 0u64);
 | 
			
		||||
 | 
			
		||||
        for (x_ofs, y_ofs) in ADJACENCY_OFFSETS {
 | 
			
		||||
            let adj_x = (pos.0 as i64) + x_ofs;
 | 
			
		||||
            let adj_y = (pos.1 as i64) + y_ofs;
 | 
			
		||||
            if !self.in_bounds(adj_x, adj_y)
 | 
			
		||||
                || exclusions
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .any(|(ex_x_range, ex_y)| *ex_y == adj_y && ex_x_range.contains(&(adj_x as usize)))
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            let adj_c = self.at(&Pos(adj_x as usize, adj_y as usize));
 | 
			
		||||
            if adj_c.is_digit(10) {
 | 
			
		||||
                let mut num_start_x = adj_x as usize;
 | 
			
		||||
                loop {
 | 
			
		||||
                    if num_start_x > 0
 | 
			
		||||
                        && self
 | 
			
		||||
                            .at(&Pos((num_start_x - 1) as usize, adj_y as usize))
 | 
			
		||||
                            .is_digit(10)
 | 
			
		||||
                    {
 | 
			
		||||
                        num_start_x -= 1;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                let mut num_end_x = adj_x as usize;
 | 
			
		||||
                loop {
 | 
			
		||||
                    if self.in_bounds(num_end_x + 1, adj_y as usize)
 | 
			
		||||
                        && self
 | 
			
		||||
                            .at(&Pos((num_end_x + 1) as usize, adj_y as usize))
 | 
			
		||||
                            .is_digit(10)
 | 
			
		||||
                    {
 | 
			
		||||
                        num_end_x += 1;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                // we have the bounds for the number, extract a slice
 | 
			
		||||
                let num_slice = &self.0[adj_y as usize].0[num_start_x..num_end_x + 1];
 | 
			
		||||
                let mut num = 0u64;
 | 
			
		||||
                for c in num_slice {
 | 
			
		||||
                    num = num * 10 + c.to_digit(10).unwrap() as u64;
 | 
			
		||||
                }
 | 
			
		||||
                if nums.0 == 0 {
 | 
			
		||||
                    nums.0 = num
 | 
			
		||||
                } else {
 | 
			
		||||
                    nums.1 = num;
 | 
			
		||||
                    return Some(nums.0 * nums.1);
 | 
			
		||||
                }
 | 
			
		||||
                exclusions.push((num_start_x..num_end_x + 1, adj_y));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PROBLEM 1 solution
 | 
			
		||||
@@ -156,6 +257,54 @@ fn problem1(input: InputIter) -> u64 {
 | 
			
		||||
 | 
			
		||||
// PROBLEM 2 solution
 | 
			
		||||
 | 
			
		||||
fn problem2(input: InputIter) -> u64 {
 | 
			
		||||
    0
 | 
			
		||||
// --- Part Two ---
 | 
			
		||||
 | 
			
		||||
// The engineer finds the missing part and installs it in the engine! As the engine
 | 
			
		||||
// springs to life, you jump in the closest gondola, finally ready to ascend to the
 | 
			
		||||
// water source.
 | 
			
		||||
 | 
			
		||||
// You don't seem to be going very fast, though. Maybe something is still wrong?
 | 
			
		||||
// Fortunately, the gondola has a phone labeled "help", so you pick it up and the
 | 
			
		||||
// engineer answers.
 | 
			
		||||
 | 
			
		||||
// Before you can explain the situation, she suggests that you look out the window.
 | 
			
		||||
// There stands the engineer, holding a phone in one hand and waving with the other.
 | 
			
		||||
// You're going so slowly that you haven't even left the station. You exit the gondola.
 | 
			
		||||
 | 
			
		||||
// The missing part wasn't the only issue - one of the gears in the engine is wrong. A
 | 
			
		||||
// gear is any * symbol that is adjacent to exactly two part numbers. Its gear ratio is
 | 
			
		||||
// the result of multiplying those two numbers together.
 | 
			
		||||
 | 
			
		||||
// This time, you need to find the gear ratio of every gear and add them all up so that
 | 
			
		||||
// the engineer can figure out which gear needs to be replaced.
 | 
			
		||||
 | 
			
		||||
// Consider the same engine schematic again:
 | 
			
		||||
 | 
			
		||||
// 467..114.. ...*...... ..35..633. ......#... 617*...... .....+.58. ..592.....
 | 
			
		||||
// ......755. ...$.*.... .664.598..
 | 
			
		||||
 | 
			
		||||
// In this schematic, there are two gears. The first is in the top left; it has part
 | 
			
		||||
// numbers 467 and 35, so its gear ratio is 16345. The second gear is in the lower
 | 
			
		||||
// right; its gear ratio is 451490. (The * adjacent to 617 is not a gear because it is
 | 
			
		||||
// only adjacent to one part number.) Adding up all of the gear ratios produces 467835.
 | 
			
		||||
 | 
			
		||||
// What is the sum of all of the gear ratios in your engine schematic?
 | 
			
		||||
 | 
			
		||||
fn problem2_all_gear_ratios(schematic: &Schematic) -> Vec<u64> {
 | 
			
		||||
    let mut gears = Vec::new();
 | 
			
		||||
    for y in 0..schematic.0.len() {
 | 
			
		||||
        for x in 0..schematic.0[0].0.len() {
 | 
			
		||||
            match schematic.gear_ratio(&Pos(x, y)) {
 | 
			
		||||
                Some(ratio) => gears.push(ratio),
 | 
			
		||||
                _ => ()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gears
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn problem2(input: InputIter) -> u64 {
 | 
			
		||||
    let schematic: Schematic = input.into();
 | 
			
		||||
    problem2_all_gear_ratios(&schematic).iter().sum()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user