diff --git a/day10/src/main.rs b/day10/src/main.rs index f9a374b..fdfeb9f 100644 --- a/day10/src/main.rs +++ b/day10/src/main.rs @@ -1,13 +1,172 @@ +use std::collections::HashSet; + fn main() { - println!("Hello, world!"); + let input = std::fs::read_to_string("input").unwrap(); + let grid = Grid::new(&input); + println!("{}", pt1(&grid)); } +fn pt1(grid: &Grid) -> usize { + dfs(grid) +} + +fn dfs(grid: &Grid) -> usize { + let mut total = 0; + + for head in grid.heads.iter() { + let mut processed = HashSet::new(); + let mut q = Vec::new(); + + q.push(*head); + while let Some(current) = q.pop() { + if !processed.contains(¤t) { + q.push(current); + } + + let mut do_top = true; + let nexts = grid.next_step(¤t); + for next in nexts.iter() { + if !processed.contains(next) { + q.push(*next); + do_top = false; + } + } + + if do_top { + let _ = q.pop(); + processed.insert(current); + if grid.get(¤t).unwrap() == 9 { + total += 1; + } + } + } + } + + total +} + +#[derive(Debug, Clone)] struct Grid { rows: Vec<Vec<usize>>, + heads: Vec<Loc>, } impl Grid { fn new(input: &str) -> Self { - todo!() + let mut rows = Vec::new(); + let mut heads = Vec::new(); + for (row, line) in input.lines().enumerate() { + let row = line + .chars() + .enumerate() + .map(|(col, c)| { + let n = c.to_digit(10).unwrap() as usize; + if n == 0 { + heads.push(Loc { row, col }); + } + n + }) + .collect(); + rows.push(row); + } + Self { rows, heads } + } + + fn get(&self, loc: &Loc) -> Option<usize> { + self.rows + .get(loc.row) + .and_then(|row| row.get(loc.col).copied()) + } + + fn next(&self, loc: &Loc) -> Vec<Tile> { + let Loc { row, col } = *loc; + let mut out = Vec::new(); + + // north + { + let row = row.wrapping_sub(1); + if let Some(&alt) = self.rows.get(row).and_then(|r| r.get(col)) { + out.push(Tile { + alt, + loc: Loc { row, col }, + }); + } + } + + // south + { + let row = row + 1; + if let Some(&alt) = self.rows.get(row).and_then(|r| r.get(col)) { + out.push(Tile { + alt, + loc: Loc { row, col }, + }); + } + } + + // east + { + let col = col + 1; + if let Some(&alt) = self.rows.get(row).and_then(|r| r.get(col)) { + out.push(Tile { + alt, + loc: Loc { row, col }, + }); + } + } + + // west + { + let col = col.wrapping_sub(1); + if let Some(&alt) = self.rows.get(row).and_then(|r| r.get(col)) { + out.push(Tile { + alt, + loc: Loc { row, col }, + }); + } + } + out + } + + fn next_step(&self, loc: &Loc) -> Vec<Loc> { + let alt = self.rows[loc.row][loc.col]; + let target = alt + 1; + self.next(loc) + .iter() + .filter_map(|t| if t.alt == target { Some(t.loc) } else { None }) + .collect() + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +struct Loc { + row: usize, + col: usize, +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +struct Tile { + loc: Loc, + alt: usize, +} + +#[cfg(test)] +mod test { + + use super::*; + + static INPUT: &str = "89010123 +78121874 +87430965 +96549874 +45678903 +32019012 +01329801 +10456732"; + + #[test] + fn p1() { + let g = Grid::new(INPUT); + assert_eq!(36, pt1(&g)); } }