Last active
December 3, 2023 08:02
-
-
Save koivunej/880d011674d20e613fc906aaa9f9f64a to your computer and use it in GitHub Desktop.
aoc 2023 day 03, buffering hashmappy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
fn main() { | |
const INPUT: &str = include_str!("../input"); | |
let (parts, ratios) = find_parts(INPUT); | |
let part1 = parts.iter().sum::<u64>(); | |
println!("{part1}"); | |
let part2 = ratios.iter().sum::<u64>(); | |
println!("{part2}"); | |
assert_eq!(part1, 537_832); | |
assert_eq!(part2, 81_939_900); | |
} | |
#[test] | |
fn example() { | |
let s = r#"467..114.. | |
...*...... | |
..35..633. | |
......#... | |
617*...... | |
.....+.58. | |
..592..... | |
......755. | |
...$.*.... | |
.664.598.."#; | |
let (part_numbers, gear_ratios) = find_parts(s); | |
assert_eq!(4361, part_numbers.iter().sum::<u64>()); | |
assert_eq!(467835, gear_ratios.iter().sum::<u64>()); | |
} | |
fn find_parts(s: &str) -> (Vec<u64>, Vec<u64>) { | |
// collect the symbol positions, unique parts and cells used by parts | |
// | |
// unique parts are defensive against same number appearing in different parts of the map. | |
// | |
// cells used by the part is to make up later scanning easier (only need to check 8 cells | |
// around a symbol). | |
let (symbols, mut parts_by_id, mut part_coordinates) = { | |
let mut parsing = String::with_capacity(8); | |
let mut parsing_from = None; | |
let mut part_id_counter = 1; | |
let mut parts_by_id = HashMap::new(); | |
let mut part_coordinates = HashMap::new(); | |
let mut symbols = Vec::new(); | |
let mut pos = (0u32, 0u32); | |
for ch in s.chars() { | |
pos.0 += 1; | |
let (flush_parsed, symbol) = match ch { | |
'\n' => (true, false), | |
'.' => (true, false), | |
'0'..='9' => { | |
if parsing_from.is_none() { | |
parsing_from = Some(pos); | |
} | |
parsing.push(ch); | |
(false, false) | |
} | |
_ => (true, true), | |
}; | |
if flush_parsed { | |
if let Some(origin) = parsing_from.take() { | |
let num = parsing.parse::<u64>().unwrap(); | |
let id = part_id_counter; | |
part_id_counter += 1; | |
// unique number which we'll only consume once | |
let old = parts_by_id.insert(id, num); | |
assert!(old.is_none()); | |
let y = pos.1; | |
for x in origin.0..pos.0 { | |
// record a link to this unique number for all cells it covered | |
let old = part_coordinates.insert((x, y), id); | |
assert!(old.is_none()); | |
} | |
parsing.clear(); | |
} | |
} | |
if symbol { | |
symbols.push((ch, pos)); | |
} | |
if ch == '\n' { | |
pos = (0, pos.1 + 1); | |
} | |
} | |
(symbols, parts_by_id, part_coordinates) | |
}; | |
let mut actual_parts = Vec::new(); | |
let mut gear_ratios = Vec::new(); | |
let mut scratch = Vec::new(); | |
// the input must be crafted so that there is no competition on which symbol "pulls" in which | |
// number, or perhaps this matters only that there is no competition with '*' for phase2. | |
for (ch, pos) in symbols { | |
scratch.clear(); | |
scratch.extend( | |
adjacent_of(pos) | |
.filter_map(|pos| part_coordinates.remove(&pos)) | |
.filter_map(|id| parts_by_id.remove(&id)) | |
.inspect(|num| println!("symbol {ch} at {pos:?} found {num}")), | |
); | |
if scratch.len() == 2 && ch == '*' { | |
gear_ratios.push(scratch.iter().product::<u64>()); | |
} | |
actual_parts.append(&mut scratch); | |
} | |
// println!("actual_parts: {:?}", actual_parts); | |
// println!("leftover: {:?}", parts_by_id.values()); | |
// println!("gear ratios: {:?}", gear_ratios); | |
(actual_parts, gear_ratios) | |
} | |
#[rustfmt::skip] | |
const fn adjacent_offsets() -> [(i32, i32); 8] { | |
[(-1, -1), ( 0, -1), ( 1, -1), | |
(-1, 0), ( 1, 0), | |
(-1, 1), ( 0, 1), ( 1, 1)] | |
} | |
fn adjacent_of(pos: (u32, u32)) -> impl Iterator<Item = (u32, u32)> { | |
adjacent_offsets().into_iter().filter_map(move |p| { | |
Some(( | |
pos.0.checked_add_signed(p.0)?, | |
pos.1.checked_add_signed(p.1)?, | |
)) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment