use std::collections::{HashMap, HashSet}; use std::error::Error; use std::fs::File; use std::io::{self, BufRead}; use std::vec::Vec; #[derive(PartialEq, Copy, Clone, Debug)] enum CubeState { Active, Inactive, } fn enumerate_adjacent(x: i32, y: i32, z: i32, w: i32) -> Vec<(i32, i32, i32, i32)> { let mut res: Vec<(i32, i32, i32, i32)> = Vec::new(); for dx in -1..2 { for dy in -1..2 { for dz in -1..2 { for dw in -1..2 { if dx != 0 || dy != 0 || dz != 0 || dw != 0 { res.push((x + dx, y + dy, z + dz, w + dw)); } } } } } res } fn count_adjacent_active( x: i32, y: i32, z: i32, w: i32, world: &HashMap<(i32, i32, i32, i32), CubeState>, ) -> u32 { enumerate_adjacent(x, y, z, w) .iter() .map(|coords| match world.get(&coords) { Some(CubeState::Active) => 1, _ => 0, }) .fold(0u32, |x, acc| x + acc) } fn main() -> Result<(), Box> { let file = File::open("inputs/day17.txt")?; let lines = io::BufReader::new(file).lines().map(|l| l.unwrap()); let mut world: HashMap<(i32, i32, i32, i32), CubeState> = HashMap::new(); let initial_slice: Vec<(i32, i32, i32, i32, CubeState)> = lines .enumerate() .map(|(y, l)| { l.chars() .enumerate() .map(|(x, c)| match c { '#' => (x as i32, y as i32, 0, 0, CubeState::Active), '.' => (x as i32, y as i32, 0, 0, CubeState::Inactive), _ => panic!("Unknown State: {}", c), }) .collect::>() }) .fold(Vec::new(), |mut acc, mut x| { acc.append(&mut x); acc }); for (x, y, z, w, s) in initial_slice { world.insert((x, y, z, w), s); } for _ in 0..6 { let mut used_positions: HashSet<(i32, i32, i32, i32)> = HashSet::new(); for (x, y, z, w) in world.keys() { for coords in enumerate_adjacent(*x, *y, *z, *w) { used_positions.insert(coords); } } let mut new_world: HashMap<(i32, i32, i32, i32), CubeState> = HashMap::new(); for (x, y, z, w) in used_positions { let cur_state = if let Some(state) = world.get(&(x, y, z, w)) { *state } else { CubeState::Inactive }; let active_adjacent = count_adjacent_active(x, y, z, w, &world); if cur_state == CubeState::Active && (active_adjacent == 2 || active_adjacent == 3) { new_world.insert((x, y, z, w), CubeState::Active); } else if cur_state == CubeState::Inactive && active_adjacent == 3 { new_world.insert((x, y, z, w), CubeState::Active); } else { new_world.insert((x, y, z, w), CubeState::Inactive); }; } world = new_world; } let active_count = world .values() .map(|s| match s { CubeState::Active => 1, _ => 0, }) .fold(0, |acc, x| x + acc); println!("Active Cells: {}", active_count); Ok(()) }