2023 - Day 15
This commit is contained in:
parent
6416c98c73
commit
9004a8c891
1
2023/input/15/input
Normal file
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
1
2023/input/15/test-1
Normal 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
159
2023/src/bin/day15.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user