diff options
Diffstat (limited to '2023/src/bin/day_15.rs')
-rw-r--r-- | 2023/src/bin/day_15.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/2023/src/bin/day_15.rs b/2023/src/bin/day_15.rs new file mode 100644 index 0000000..429e7f4 --- /dev/null +++ b/2023/src/bin/day_15.rs @@ -0,0 +1,153 @@ +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<dyn std::error::Error>> { + 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<Instruction>); + +#[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<Lens>, +} + +#[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::<usize>::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); +} |