summaryrefslogtreecommitdiff
path: root/2023/src/bin/day_15.rs
diff options
context:
space:
mode:
Diffstat (limited to '2023/src/bin/day_15.rs')
-rw-r--r--2023/src/bin/day_15.rs153
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);
+}