diff --git a/samples/day15.txt b/samples/day15.txt new file mode 100644 index 0000000..4f58f74 --- /dev/null +++ b/samples/day15.txt @@ -0,0 +1 @@ +rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7 diff --git a/src/bin/day15.rs b/src/bin/day15.rs new file mode 100644 index 0000000..84a4382 --- /dev/null +++ b/src/bin/day15.rs @@ -0,0 +1,118 @@ +use std::str::FromStr; + +use aoc_2023::*; + +type Output1 = i32; +type Output2 = Output1; + +fn hash_algorithm(s: &str) -> i32 { + s.chars().fold(0, |mut h, c| { + let mut b = [0]; + + c.encode_utf8(&mut b); + + h += b[0] as i32; + h *= 17; + h %= 256; + + h + }) +} + +enum Step { + Del(String), + Ins(String, i32), +} + +impl FromStr for Step { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + let (label, focal_length) = s.split_once(['=', '-']).unwrap(); + + Ok(match focal_length { + "" => Step::Del(label.to_owned()), + _ => Step::Ins(label.to_owned(), focal_length.parse().unwrap()), + }) + } +} + +impl Step { + fn hash_step(&self) -> i32 { + let original = match self { + Step::Del(label) => format!("{}-", label), + Step::Ins(label, length) => format!("{}={}", label, length), + }; + + hash_algorithm(&original) + } + + fn label(&self) -> &str { + match self { + Step::Del(l) | Step::Ins(l, _) => l, + } + } + + fn hash_label(&self) -> i32 { + hash_algorithm(self.label()) + } +} + +struct Day15 { + steps: Vec, +} +impl Solution for Day15 { + fn new>(pathname: P) -> Self { + Self { + steps: file_to_string(pathname) + .trim_end() + .split(',') + .map(|s| s.parse().unwrap()) + .collect_vec(), + } + } + + fn part_1(&mut self) -> Output1 { + self.steps.iter().map(|s| s.hash_step()).sum() + } + + fn part_2(&mut self) -> Output2 { + let mut boxes: Vec> = vec![]; + boxes.resize_with(256, Vec::new); + + for step in &self.steps { + let h = step.hash_label(); + + let b: &mut Vec<(&str, i32)> = &mut boxes[h as usize]; + + match step { + Step::Del(_) => { + if let Some(idx) = b.iter().position(|&(l, _)| l == step.label()) { + b.remove(idx); + } + } + Step::Ins(label, l) => match b.iter().position(|&(l, _)| l == step.label()) { + Some(idx) => b[idx] = (label, *l), + None => b.push((label, *l)), + }, + } + } + + boxes + .iter() + .enumerate() + .map(|(i, b)| { + b.iter() + .enumerate() + .map(|(j, (_, l))| (i as i32 + 1) * (j as i32 + 1) * l) + .sum::() + }) + .sum() + } +} + +fn main() -> Result<()> { + Day15::main() +} + +test_sample!(day_15, Day15, 1320, 145);