diff --git a/README.md b/README.md index 519008c..68711ee 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,15 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | Day | Part 1 | Part 2 | | :---: | :---: | :---: | -| [Day 1](./src/bin/01.rs) | `33.9µs` | `36.0µs` | -| [Day 2](./src/bin/02.rs) | `41.5µs` | `40.8µs` | -| [Day 3](./src/bin/03.rs) | `116.5µs` | `115.9µs` | -| [Day 4](./src/bin/04.rs) | `49.4µs` | `49.7µs` | -| [Day 5](./src/bin/05.rs) | `20.9µs` | `24.1µs` | -| [Day 6](./src/bin/06.rs) | `202.0ns` | `100.0ns` | -| [Day 7](./src/bin/07.rs) | `93.6µs` | `92.6µs` | - -**Total: 0.72ms** +| [Day 1](./src/bin/01.rs) | `28.7µs` | `34.6µs` | +| [Day 2](./src/bin/02.rs) | `41.7µs` | `40.8µs` | +| [Day 3](./src/bin/03.rs) | `84.3µs` | `99.7µs` | +| [Day 4](./src/bin/04.rs) | `49.0µs` | `50.7µs` | +| [Day 5](./src/bin/05.rs) | `20.7µs` | `24.3µs` | +| [Day 6](./src/bin/06.rs) | `203.0ns` | `102.0ns` | +| [Day 7](./src/bin/07.rs) | `97.6µs` | `92.8µs` | + +**Total: 0.67ms** --- diff --git a/src/bin/03.rs b/src/bin/03.rs index a2febe9..ca90fe3 100644 --- a/src/bin/03.rs +++ b/src/bin/03.rs @@ -1,109 +1,105 @@ -use std::{collections::HashMap, str::FromStr}; +use std::collections::HashMap; advent_of_code::solution!(3); pub fn part_one(input: &str) -> Option { - Some( - input - .parse::() - .ok()? - .parts - .into_iter() - .map(|p| p.number) - .sum(), - ) + let mut part_sum = 0; + let mut cur_num: Option = None; + let mut cur_start: Option = None; + let chars: Vec> = input + .lines() + .map(|line| line.trim().chars().collect()) + .collect(); + // TODO: scan for gears instead, and only parse numbers when gears are found? + for (row, line) in chars.iter().enumerate() { + for (col, ch) in line.iter().copied().enumerate() { + let mut numeric = false; + if let Some(digit) = ch.to_digit(10) { + numeric = true; + cur_num = Some(cur_num.unwrap_or(0) * 10 + digit); + if cur_start.is_none() { + cur_start = Some(col); + } + } + if !numeric || col == line.len() - 1 { + if let Some((start, number)) = cur_start.zip(cur_num) { + let end = if numeric { col } else { col - 1 }; + let mut symbol: Option = None; + for i in row.saturating_sub(1)..=row.saturating_add(1) { + for j in start.saturating_sub(1)..=end.saturating_add(1) { + if let Some(&adj_ch) = chars.get(i).and_then(|l| l.get(j)) { + if !adj_ch.is_numeric() && adj_ch != '.' { + symbol = Some(adj_ch); + } + } + } + } + if symbol.is_some() { + part_sum += number; + } + } + cur_start = None; + cur_num = None; + } + } + } + Some(part_sum) } pub fn part_two(input: &str) -> Option { - Some( - input - .parse::() - .ok()? - .gears - .into_iter() - .map(|gear| gear.ratio) - .sum(), - ) -} - -struct Part { - number: u32, -} - -struct Gear { - ratio: u32, - adjacent_parts: usize, -} - -struct Engine { - parts: Vec, - gears: Vec, -} - -struct ParseEngineErr; - -impl FromStr for Engine { - type Err = ParseEngineErr; - - fn from_str(s: &str) -> Result { - let mut parts: Vec = Vec::new(); - let mut gears: HashMap<(usize, usize), Gear> = HashMap::new(); - let mut cur_num: Option = None; - let mut cur_start: Option = None; - let chars: Vec> = s - .lines() - .map(|line| line.trim().chars().collect()) - .collect(); - for (row, line) in chars.iter().enumerate() { - for (col, ch) in line.iter().copied().enumerate() { - let mut numeric = false; - if let Some(digit) = ch.to_digit(10) { - numeric = true; - cur_num = Some(cur_num.unwrap_or(0) * 10 + digit); - if cur_start.is_none() { - cur_start = Some(col); - } + let mut gears: HashMap<(usize, usize), Gear> = HashMap::new(); + let mut cur_num: Option = None; + let mut cur_start: Option = None; + let chars: Vec> = input + .lines() + .map(|line| line.trim().chars().collect()) + .collect(); + for (row, line) in chars.iter().enumerate() { + for (col, ch) in line.iter().copied().enumerate() { + let mut numeric = false; + if let Some(digit) = ch.to_digit(10) { + numeric = true; + cur_num = Some(cur_num.unwrap_or(0) * 10 + digit); + if cur_start.is_none() { + cur_start = Some(col); } - if !numeric || col == line.len() - 1 { - if let Some((start, number)) = cur_start.zip(cur_num) { - let end = if numeric { col } else { col - 1 }; - let mut symbol: Option = None; - let mut counted_gear_part = false; - for i in row.saturating_sub(1)..=row.saturating_add(1) { - for j in start.saturating_sub(1)..=end.saturating_add(1) { - if let Some(&adj_ch) = chars.get(i).and_then(|l| l.get(j)) { - if !adj_ch.is_numeric() && adj_ch != '.' { - symbol = Some(adj_ch); - } - if adj_ch == '*' && !counted_gear_part { - let gear = gears.entry((i, j)).or_insert(Gear { - ratio: 1, - adjacent_parts: 0, - }); - gear.ratio *= number; - gear.adjacent_parts += 1; - counted_gear_part = true; - } + } + if !numeric || col == line.len() - 1 { + if let Some((start, number)) = cur_start.zip(cur_num) { + let end = if numeric { col } else { col - 1 }; + let mut counted_gear_part = false; + for i in row.saturating_sub(1)..=row.saturating_add(1) { + for j in start.saturating_sub(1)..=end.saturating_add(1) { + if let Some(&adj_ch) = chars.get(i).and_then(|l| l.get(j)) { + if adj_ch == '*' && !counted_gear_part { + let gear = gears.entry((i, j)).or_insert(Gear { + ratio: 1, + adjacent_parts: 0, + }); + gear.ratio *= number; + gear.adjacent_parts += 1; + counted_gear_part = true; } } } - if symbol.is_some() { - parts.push(Part { number }); - } } - cur_start = None; - cur_num = None; } + cur_start = None; + cur_num = None; } } - Ok(Engine { - parts, - gears: gears - .into_values() - .filter(|gear| gear.adjacent_parts >= 2) - .collect(), - }) } + Some( + gears + .into_values() + .filter_map(|gear| (gear.adjacent_parts == 2).then_some(gear.ratio)) + .sum(), + ) +} + +struct Gear { + ratio: u32, + adjacent_parts: usize, } #[cfg(test)]