2023 - Day 15

This commit is contained in:
Dreaded_X 2023-12-15 11:34:00 +01:00
parent 6416c98c73
commit 9004a8c891
Signed by: Dreaded_X
GPG Key ID: 5A0CBFE3C3377FAA
3 changed files with 161 additions and 0 deletions

1
2023/input/15/input Normal file

File diff suppressed because one or more lines are too long

1
2023/input/15/test-1 Normal file
View File

@ -0,0 +1 @@
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7

159
2023/src/bin/day15.rs Normal file
View File

@ -0,0 +1,159 @@
#![feature(test)]
use std::cmp::Ordering;
use anyhow::Result;
use aoc::Solver;
// -- Runners --
fn main() -> Result<()> {
Day::solve()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_test1() -> Result<()> {
Day::test(Day::part1, "test-1", 1320)
}
#[test]
fn part1_solution() -> Result<()> {
Day::test(Day::part1, "input", 511416)
}
#[test]
fn part2_test1() -> Result<()> {
Day::test(Day::part2, "test-1", 145)
}
#[test]
fn part2_solution() -> Result<()> {
Day::test(Day::part2, "input", 290779)
}
// Benchmarks
extern crate test;
#[bench]
#[ignore]
fn part1_bench(b: &mut test::Bencher) {
Day::benchmark(Day::part1, b)
}
#[bench]
#[ignore]
fn part2_bench(b: &mut test::Bencher) {
Day::benchmark(Day::part2, b)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Action<'a> {
Add { label: &'a str, focal_length: usize },
Remove { label: &'a str },
}
impl<'a> Action<'a> {
fn index(&self) -> usize {
match self {
Action::Add { label, .. } | Action::Remove { label } => label
.chars()
.map(|c| c as usize)
.fold(0, |acc, num| ((acc + num) * 17) % 256),
}
}
}
// -- Solution --
pub struct Day;
impl aoc::Solver for Day {
type Output1 = usize;
type Output2 = usize;
fn day() -> u8 {
15
}
fn part1(input: &str) -> Self::Output1 {
input
.trim()
.split(',')
.map(|sequence| {
sequence
.chars()
.map(|c| c as usize)
.fold(0, |acc, num| ((acc + num) * 17) % 256)
})
.sum()
}
fn part2(input: &str) -> Self::Output2 {
let actions: Vec<_> = input
.trim()
.split(',')
.map(|sequence| {
if sequence.ends_with('-') {
let label = sequence.split_once('-').unwrap().0;
Action::Remove { label }
} else {
let (label, focal_length) = sequence.split_once('=').unwrap();
let focal_length = focal_length.parse().unwrap();
Action::Add {
label,
focal_length,
}
}
})
.collect();
let mut boxes: [Vec<(&str, usize)>; 256] = std::array::from_fn(|_| Vec::new());
for action in &actions {
let index = action.index();
match action {
Action::Add {
label,
focal_length,
} => {
// NOTE: Using a library like OrderedMap would make this trivially easy
if let Some(position) = boxes[index]
.iter()
.position(|lens| lens.0.cmp(label) == Ordering::Equal)
{
// If a lens with this label is already in the box, replace it
boxes[index][position].1 = *focal_length;
} else {
// Otherwise add it to the end of the box
boxes[index].push((label, *focal_length));
}
}
Action::Remove { label } => {
if let Some(position) = boxes[index]
.iter()
.position(|lens| lens.0.cmp(label) == Ordering::Equal)
{
// A lens with the label exists, remove it
boxes[index].remove(position);
}
}
}
}
boxes
.iter()
.enumerate()
.map(|(index, b)| {
b.iter()
.enumerate()
.map(|(position, (_, focal_length))| {
(1 + index) * (1 + position) * focal_length
})
.sum::<usize>()
})
.sum()
}
}