use nom::{ bytes::complete::tag, character::complete::u32 as nom_u32, combinator::{map, map_res}, multi::separated_list1, IResult, ToUsize, }; use std::{collections::VecDeque, fs}; use thiserror::Error; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_6.txt")?; let mut swarm = parse_swarm(&input).unwrap().1; for _ in 0..80 { swarm.grow(); } dbg!(swarm.fish_sum()); for _ in 80..256 { swarm.grow(); } dbg!(swarm.fish_sum()); Ok(()) } #[derive( Default, Debug, Clone, Copy, derive_more::Add, derive_more::AddAssign, derive_more::Sum, )] struct FishCount(u64); const FISH_INITIAL_SPAWN_COUNTDOWN: usize = 9; const FISH_REPEAT_SPAWN_COUNTDOWN: usize = 7; #[derive(Debug)] struct Swarm { fish: VecDeque, } #[derive(Debug, Error)] enum SwarmParseError { #[error("input was out of range")] OutOfRange, } impl Swarm { fn new(fish_counters: Vec) -> Result { let mut fish = VecDeque::with_capacity(FISH_INITIAL_SPAWN_COUNTDOWN); for _ in 0..FISH_INITIAL_SPAWN_COUNTDOWN { fish.push_back(FishCount::default()); } for fish_counter in fish_counters { if fish_counter > fish.len() { return Err(SwarmParseError::OutOfRange); } fish[fish_counter] += FishCount(1); } Ok(Swarm { fish }) } fn grow(&mut self) { let spawning = self .fish .pop_front() .expect("Fish buffer should maintain exactly 9 entries"); self.fish[FISH_REPEAT_SPAWN_COUNTDOWN - 1] += spawning; self.fish.push_back(spawning); } fn fish_sum(&self) -> FishCount { self.fish.iter().copied().sum() } } fn parse_swarm(input: &str) -> IResult<&str, Swarm> { map_res( separated_list1(tag(","), map(nom_u32, |n| n.to_usize())), Swarm::new, )(input) }