mirror of
https://github.com/anthonyoteri/advent-of-code-2023.git
synced 2026-06-05 19:56:53 -04:00
+123
-2
@@ -1,8 +1,129 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::error::AocError;
|
use crate::error::AocError;
|
||||||
|
use nom::{
|
||||||
|
bytes::complete::{is_a, tag},
|
||||||
|
character::complete::{self, alpha1},
|
||||||
|
combinator::opt,
|
||||||
|
multi::separated_list1,
|
||||||
|
IResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Instruction<'a> {
|
||||||
|
hash: usize,
|
||||||
|
label: &'a str,
|
||||||
|
operation: Operation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Operation {
|
||||||
|
Insert(u8),
|
||||||
|
Remove,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Lens<'a> {
|
||||||
|
label: &'a str,
|
||||||
|
power: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct LightBox<'a> {
|
||||||
|
lenses: Vec<Lens<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_instruction(input: &str) -> IResult<&str, Instruction> {
|
||||||
|
let (input, label) = alpha1(input)?;
|
||||||
|
let (input, _) = is_a("=-")(input)?;
|
||||||
|
let (input, power) = opt(complete::u8)(input)?;
|
||||||
|
|
||||||
|
let operation = {
|
||||||
|
match power {
|
||||||
|
Some(p) => Operation::Insert(p),
|
||||||
|
None => Operation::Remove,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instruction = Instruction {
|
||||||
|
hash: hash_value(label),
|
||||||
|
label,
|
||||||
|
operation,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((input, instruction))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &str) -> IResult<&str, Vec<Instruction>> {
|
||||||
|
separated_list1(tag(","), parse_instruction)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument]
|
||||||
|
fn hash_value(input: &str) -> usize {
|
||||||
|
let ascii_codes = input.chars().map(|c| c as u8).collect_vec();
|
||||||
|
|
||||||
|
let mut sum: usize = 0;
|
||||||
|
|
||||||
|
for code in ascii_codes {
|
||||||
|
sum += code as usize;
|
||||||
|
sum *= 17;
|
||||||
|
sum %= 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn process(input: &str) -> miette::Result<u64, AocError> {
|
pub fn process(input: &str) -> miette::Result<u64, AocError> {
|
||||||
Ok(0)
|
let (input, instructions) = parse(input).unwrap();
|
||||||
|
debug_assert!(input.is_empty(), "Failed to completely parse input");
|
||||||
|
|
||||||
|
let boxes = (0..u8::MAX)
|
||||||
|
.map(|_| LightBox { lenses: Vec::new() })
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let boxes = instructions.iter().fold(boxes, |mut boxes, instruction| {
|
||||||
|
match instruction.operation {
|
||||||
|
Operation::Insert(power) => {
|
||||||
|
let idx = boxes[instruction.hash]
|
||||||
|
.lenses
|
||||||
|
.iter()
|
||||||
|
.position(|l| l.label == instruction.label);
|
||||||
|
match idx {
|
||||||
|
Some(idx) => {
|
||||||
|
boxes[instruction.hash].lenses[idx].power = power;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let lens = Lens {
|
||||||
|
label: instruction.label,
|
||||||
|
power,
|
||||||
|
};
|
||||||
|
boxes[instruction.hash].lenses.push(lens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Operation::Remove => boxes[instruction.hash]
|
||||||
|
.lenses
|
||||||
|
.retain(|l| l.label != instruction.label),
|
||||||
|
};
|
||||||
|
|
||||||
|
boxes
|
||||||
|
});
|
||||||
|
|
||||||
|
let power: u64 = boxes
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(box_index, b)| {
|
||||||
|
b.lenses.iter().enumerate().map(move |(lens_index, l)| {
|
||||||
|
let box_part = box_index + 1;
|
||||||
|
let slot_part = lens_index + 1;
|
||||||
|
let focal_length = l.power as usize;
|
||||||
|
|
||||||
|
box_part as u64 * slot_part as u64 * focal_length as u64
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
Ok(power)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -12,7 +133,7 @@ mod tests {
|
|||||||
#[test_log::test]
|
#[test_log::test]
|
||||||
fn test_process() -> miette::Result<()> {
|
fn test_process() -> miette::Result<()> {
|
||||||
let input = include_str!("../test-input.txt");
|
let input = include_str!("../test-input.txt");
|
||||||
assert_eq!(0, process(input)?);
|
assert_eq!(145, process(input)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user