refactor for yearly

This commit is contained in:
RingOfStorms (Josh) 2024-09-28 21:52:31 -05:00
parent da00eb3606
commit dddda24957
57 changed files with 3 additions and 0 deletions

190
2023/src/bin/day15.rs Normal file
View file

@ -0,0 +1,190 @@
use aoc23::prelude::*;
use derive_builder::Builder;
use itertools::Itertools;
use rayon::prelude::*;
use std::{str::FromStr, time::Instant};
static DAY: u8 = 15;
#[derive(Debug, Clone, Default, Eq, PartialEq)]
struct Seq {
chars: Vec<char>,
}
impl Seq {
fn new(s: &str) -> Result<Self> {
Ok(Self {
chars: s.trim().chars().filter(|c| !c.is_whitespace()).collect(),
})
}
fn hash(&self) -> usize {
self.chars.iter().fold(0, |acc, char| {
let mut value = acc;
value += *char as usize;
value *= 17;
value = value % 256;
value
})
}
}
#[derive(Debug, Clone)]
enum Operation {
Remove,
// focal length
Insert(usize),
}
#[derive(Debug, Clone)]
struct LensOp {
label: Seq,
box_index: usize,
operation: Operation,
}
impl LensOp {
fn new(value: &Seq) -> Self {
let label = Seq {
chars: value
.chars
.iter()
.take_while(|c| c != &&'=' && c != &&'-')
.map(|c| *c)
.collect(),
};
let box_index = label.hash();
let mut op = value.chars.iter().skip(label.chars.len());
Self {
label,
box_index,
operation: match op.next().unwrap() {
'-' => Operation::Remove,
'=' => Operation::Insert(op.next().unwrap().to_digit(10).unwrap() as usize),
o => panic!("Unknown op {o}"),
},
}
}
}
#[derive(Debug, Clone, Default)]
struct LensBox {
lenses: Vec<LensOp>,
}
fn part1(input: String) -> Result<usize> {
// parse
let start = Instant::now();
let sequences: Vec<Seq> = input.split(',').map(|seq| Seq::new(seq)).try_collect()?;
let parsed_time = start.elapsed();
// algo
let a_start = Instant::now();
let answer = sequences.par_iter().map(Seq::hash).sum();
let algo_time = a_start.elapsed();
// output
println!("part 1: {answer}\t[total: {:?}]", start.elapsed());
println!("\tparse: {parsed_time:?}");
println!("\talgo: {algo_time:?}");
Ok(answer)
}
fn part2(input: String) -> Result<usize> {
// parse
let start = Instant::now();
let lens_ops: Vec<LensOp> = input
.split(',')
.map(|seq| Seq::new(seq).unwrap())
.map(|s| LensOp::new(&s))
.collect();
let mut lens_boxes: Vec<LensBox> = std::iter::repeat_with(|| LensBox::default())
.take(256)
.collect();
let parsed_time = start.elapsed();
// algo
let a_start = Instant::now();
for lens_op in lens_ops {
if let Some(lens_box) = lens_boxes.get_mut(lens_op.box_index) {
match lens_op.operation {
Operation::Remove => lens_box.lenses.retain(|lop| lop.label != lens_op.label),
Operation::Insert(_) => {
if let Some(existing) = lens_box
.lenses
.iter_mut()
.find(|lop| lop.label == lens_op.label)
{
*existing = lens_op;
} else {
lens_box.lenses.push(lens_op);
}
}
}
}
}
let answer = lens_boxes
.iter()
.enumerate()
.map(|(box_idx, lens_box)| {
lens_box
.lenses
.iter()
.enumerate()
.map(|(lens_idx, lens)| {
if let Operation::Insert(focal_length) = lens.operation {
(box_idx + 1) * (lens_idx + 1) * focal_length
} else {
panic!("How did a removal lens get in there?");
}
})
.sum::<usize>()
})
.sum();
let algo_time = a_start.elapsed();
// output
println!("part 2: {answer}\t[total: {:?}]", start.elapsed());
println!("\tparse: {parsed_time:?}");
println!("\talgo: {algo_time:?}");
Ok(answer)
}
#[tokio::main]
async fn main() -> Result<()> {
println!("Day {DAY}");
println!("=====");
let input = utils::aoc::get_puzzle_input(DAY).await?;
part1(input.clone())?;
part2(input.clone())?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_1_a() -> Result<()> {
assert_eq!(part1("HASH".to_owned())?, 52);
Ok(())
}
#[test]
fn test_part_1_b() -> Result<()> {
assert_eq!(
part1("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7".to_owned())?,
1320
);
Ok(())
}
#[test]
fn test_part_2() -> Result<()> {
assert_eq!(
part2("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7".to_owned())?,
145
);
Ok(())
}
}