use std::collections::HashSet; use std::io::{BufRead, BufReader}; use std::ops::Add; use std::path::Path; use std::fs::File; use std::rc::Rc; #[derive(Debug)] enum Tile { Empty, Sym, Num(Rc) } #[derive(Clone, Copy)] struct Point(i32, i32); impl Add for Point { type Output = Point; fn add(self, rhs: Self) -> Self::Output { Point(self.0 + rhs.0, self.1 + rhs.1) } } static DIRS: [Point; 8] = [Point(-1, -1), Point(0, -1), Point(1, -1), Point(-1, 0), Point(1, 0), Point(-1, 1), Point(0, 1), Point(1, 1)]; fn atoi(s: &str) -> i32 { let end = s.find(|c:char| !c.is_numeric()); match end { Some(end) => s[0..end].parse().unwrap(), None => s.parse().unwrap() } } fn is_inbounds(p: &Point, br: &Point) -> bool { p.0 >= 0 && p.1 >= 0 && p.0 < br.0 && p.1 < br.1 } fn main() { let path = Path::new("input"); let file = File::open(&path).unwrap(); let reader = BufReader::new(file); let mut map = vec![]; let mut syms = vec![]; for l in reader.lines() { let l = l.unwrap(); let mut row: Vec = vec![]; let mut c_it = l.char_indices(); loop { let Some((idx, c)) = c_it.next() else { break; }; match c { '.' => row.push(Tile::Empty), c if !c.is_ascii_alphanumeric() => { syms.push(Point(row.len().try_into().unwrap(), map.len().try_into().unwrap())); row.push(Tile::Sym); }, c if c.is_numeric() => { if let Some(Tile::Num(n)) = row.last() { row.push(Tile::Num(n.clone())); } else { let n = atoi(&l[idx..]); row.push(Tile::Num(Rc::new(n))); } } _ => unreachable!() } } map.push(row); } let br = Point(map[0].len().try_into().unwrap(), map.len().try_into().unwrap()); let mut nums: HashSet<*const i32> = HashSet::new(); for s in syms { for d in DIRS { let p = s + d; if !is_inbounds(&p, &br) { continue; } match &map[TryInto::::try_into(p.1).unwrap()][TryInto::::try_into(p.0).unwrap()] { Tile::Num(n) => { nums.insert(Rc::as_ptr(n)); }, _ => {} } } } let mut sum = 0; for n in nums { unsafe { sum += *n; } } println!("{}", sum); }