From b1e7d7ad356b67e68096544e62c407be900fc3ab Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Tue, 5 Dec 2023 18:49:36 -0800 Subject: [PATCH] day3: problem 2 solution. this is ugly. --- 3/Cargo.lock | 85 ++++++++++++++++++++++++++ 3/Cargo.toml | 1 + 3/src/main.rs | 163 +++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 242 insertions(+), 7 deletions(-) diff --git a/3/Cargo.lock b/3/Cargo.lock index 4104d70..b62acea 100644 --- a/3/Cargo.lock +++ b/3/Cargo.lock @@ -2,6 +2,91 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "day3" version = "0.1.0" +dependencies = [ + "num", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] diff --git a/3/Cargo.toml b/3/Cargo.toml index 898e70d..572ad51 100644 --- a/3/Cargo.toml +++ b/3/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +num = "0.4.1" diff --git a/3/src/main.rs b/3/src/main.rs index 90ee918..d832b1e 100644 --- a/3/src/main.rs +++ b/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>(&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 { + if self.at(pos) != '*' { + return None; + } + + let mut exclusions: Vec<(Range, 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 { + 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() }