use std::fs; use nom::{ branch::alt, bytes::complete::tag, character::complete::{alpha1, u32}, combinator::{consumed, map, value}, multi::separated_list1, sequence::{pair, preceded}, IResult, }; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_15.txt")?; let parsed = InitializationInstructions::parser(&input).unwrap().1; dbg!(&parsed.hash_sum()); dbg!(&parsed.final_focusing_power()); Ok(()) } #[derive(Debug)] struct InitializationInstructions(Vec); #[derive(Debug)] struct Instruction { instruction: String, label: String, action: Action, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Action { Remove, Insert(u32), } #[derive(Default, Debug, Clone)] struct LensBox { lenses: Vec, } #[derive(Debug, Clone)] struct Lens { label: String, power: u32, } impl InitializationInstructions { fn parser(input: &str) -> IResult<&str, Self> { map( separated_list1(tag(","), Instruction::parser), InitializationInstructions, )(input) } fn hash_sum(&self) -> usize { self.0.iter().map(|i| hash(&i.instruction)).sum() } fn final_focusing_power(&self) -> u32 { let mut boxes = vec![LensBox::default(); 256]; for instruction in &self.0 { let box_index = hash(&instruction.label); let lens_box = &mut boxes[box_index]; match instruction.action { Action::Remove => { lens_box .lenses .retain(|lens| lens.label != instruction.label); } Action::Insert(power) => { let existing_position = lens_box .lenses .iter() .position(|lens| lens.label == instruction.label); match existing_position { Some(position) => { lens_box.lenses[position].power = power; } None => { lens_box.lenses.push(Lens { label: instruction.label.clone(), power, }); } } } } } boxes .into_iter() .enumerate() .flat_map(|(box_index, lens_box)| { lens_box .lenses .into_iter() .enumerate() .map(move |(lens_index, lens)| { (box_index as u32 + 1) * (lens_index as u32 + 1) * lens.power }) }) .sum() } } impl Instruction { fn parser(input: &str) -> IResult<&str, Self> { map( consumed(pair(alpha1, Action::parser)), |(instruction, (label, action))| Instruction { instruction: instruction.to_owned(), label: label.to_owned(), action, }, )(input) } } impl Action { fn parser(input: &str) -> IResult<&str, Self> { alt(( value(Action::Remove, tag("-")), map(preceded(tag("="), u32), Action::Insert), ))(input) } } fn hash(input: &str) -> usize { let mut result: usize = 0; for c in input.bytes() { result += Into::::into(c); result *= 17; result %= 256; } result } #[test] fn examples() { assert_eq!(hash("rn=1"), 30); assert_eq!(hash("cm-"), 253); assert_eq!(hash("qp=3"), 97); assert_eq!(hash("cm=2"), 47); assert_eq!(hash("qp-"), 14); assert_eq!(hash("pc=4"), 180); assert_eq!(hash("ot=9"), 9); assert_eq!(hash("ab=5"), 197); assert_eq!(hash("pc-"), 48); assert_eq!(hash("pc=6"), 214); assert_eq!(hash("ot=7"), 231); }