Skip to content

Instantly share code, notes, and snippets.

@typester
Created December 3, 2023 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save typester/29ff2ce835f14f89503456af0677997c to your computer and use it in GitHub Desktop.
Save typester/29ff2ce835f14f89503456af0677997c to your computer and use it in GitHub Desktop.
2023 Advent of Code Day 3
use std::collections::HashMap;
const INPUT: &str = "..snip..";
#[derive(Debug)]
struct Info {
symbol_map: Vec<Vec<bool>>,
numbers: Vec<Number>,
}
enum SymbolType {
Any,
Gear,
}
#[derive(Debug)]
struct Number {
num: u32,
x: usize,
y: usize,
len: usize,
}
fn main() {
let info = parse_input(INPUT, SymbolType::Any);
let sum: u32 = info.numbers.iter().fold(0, |mut acc, n| {
if n.has_symbol(&info.symbol_map) {
acc += n.num;
}
acc
});
println!("part1: {}", sum);
let info = parse_input(INPUT, SymbolType::Gear);
let gear_map: HashMap<String, Vec<u32>> = info.numbers.iter().fold(HashMap::new(), |mut acc, n| {
for gear_addr in n.symbol_addrs(&info.symbol_map).iter() {
acc.entry(gear_addr.into()).or_insert(vec![]).push(n.num);
}
acc
});
let sum = gear_map.iter().fold(0, |mut acc, (_addr, nums)| {
if nums.len() == 2 {
acc += nums[0] * nums[1];
}
acc
});
println!("part2: {}", sum);
}
fn parse_input(input: &str, symbol_type: SymbolType) -> Info {
#[derive(Debug, Default)]
struct ParseInfo {
symbol_map: Vec<Vec<bool>>,
numbers: Vec<Number>,
x: usize,
y: usize,
number_buf: String,
number_x: usize,
number_y: usize,
}
let parse_info = input.lines().fold(ParseInfo::default(), |mut acc, line| {
acc.symbol_map.push(vec![]);
acc.x = 0;
for c in line.chars() {
if c.is_numeric() {
if acc.number_buf == "" {
acc.number_x = acc.x;
acc.number_y = acc.symbol_map.len() - 1;
}
acc.number_buf.push(c);
acc.symbol_map[acc.y].push(false);
} else {
if acc.number_buf != "" {
let n = Number {
num: acc.number_buf.parse::<u32>().unwrap(),
x: acc.number_x,
y: acc.number_y,
len: acc.number_buf.len(),
};
acc.numbers.push(n);
acc.number_buf.clear()
}
match symbol_type {
SymbolType::Any =>
acc.symbol_map[acc.y].push(c != '.'),
SymbolType::Gear =>
acc.symbol_map[acc.y].push(c == '*'),
}
}
acc.x += 1;
}
acc.y += 1;
acc
});
Info {
symbol_map: parse_info.symbol_map,
numbers: parse_info.numbers,
}
}
impl Number {
fn has_symbol(&self, symbol_map: &Vec<Vec<bool>>) -> bool {
let start_y = if self.y > 0 { self.y - 1 } else { self.y };
let start_x = if self.x > 0 { self.x - 1 } else { self.x };
for y in start_y ..= self.y + 1 {
if symbol_map.len() <= y { continue }
for x in start_x ..= self.x + self.len {
if symbol_map[y].len() <= x { continue }
if symbol_map[y][x] {
return true
}
}
}
false
}
fn symbol_addrs(&self, symbol_map: &Vec<Vec<bool>>) -> Vec<String> {
let mut addrs: Vec<String> = vec![];
let start_y = if self.y > 0 { self.y - 1 } else { self.y };
let start_x = if self.x > 0 { self.x - 1 } else { self.x };
for y in start_y ..= self.y + 1 {
if symbol_map.len() <= y { continue }
for x in start_x ..= self.x + self.len {
if symbol_map[y].len() <= x { continue }
if symbol_map[y][x] {
addrs.push(format!("{}-{}", y, x));
}
}
}
addrs
}
}
#[cfg(test)]
mod tests {
use crate::parse_input;
#[test]
fn test_parser() {
let input = "467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..";
let info = parse_input(&input, crate::SymbolType::Any);
println!("info: {:?}", info);
for n in info.numbers.iter() {
println!("n={}, {}", n.num, n.has_symbol(&info.symbol_map));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment