203 lines
4.8 KiB
Rust
203 lines
4.8 KiB
Rust
use itertools::Itertools;
|
|
|
|
pub fn run() {
|
|
let input = include_str!("../input/day15.txt");
|
|
dbg!(sum_hashes(input));
|
|
let ops = parse_ops(input);
|
|
let mut boxes: Vec<Vec<Lens>> = vec![vec![]; 256];
|
|
run_ops(ops, &mut boxes);
|
|
dbg!(focusing_power(&boxes));
|
|
}
|
|
|
|
fn sum_hashes(s: &str) -> usize {
|
|
s.trim().split(",").map(hash).sum()
|
|
}
|
|
|
|
fn hash(s: &str) -> usize {
|
|
assert!(s.is_ascii());
|
|
let mut res = 0;
|
|
for c in s.chars() {
|
|
let cur = c as usize;
|
|
res += cur;
|
|
res *= 17;
|
|
res %= 256;
|
|
}
|
|
res
|
|
}
|
|
|
|
fn parse_ops(s: &str) -> Vec<Op> {
|
|
let mut v = vec![];
|
|
let mut cs = s.trim().chars().peekable();
|
|
while cs.peek().is_some() {
|
|
let label = cs
|
|
.take_while_ref(|&c| c != '-' && c != '=')
|
|
.collect::<String>();
|
|
let ty = match cs.next() {
|
|
Some('-') => OpType::Dash,
|
|
Some('=') => {
|
|
let focal_length = cs
|
|
.take_while_ref(|c| c.is_ascii_digit())
|
|
.collect::<String>()
|
|
.parse::<u8>()
|
|
.unwrap();
|
|
OpType::Equals(focal_length)
|
|
}
|
|
x => panic!("unexpected char {:?}", x),
|
|
};
|
|
v.push(Op { label, ty });
|
|
if cs.peek().is_some() {
|
|
assert_eq!(cs.next(), Some(','));
|
|
}
|
|
}
|
|
v
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
struct Op {
|
|
label: String,
|
|
ty: OpType,
|
|
}
|
|
|
|
impl Op {
|
|
fn hash(&self) -> usize {
|
|
hash(&self.label)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
enum OpType {
|
|
Dash,
|
|
Equals(u8),
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
struct Lens {
|
|
label: String,
|
|
focal_length: u8,
|
|
}
|
|
|
|
fn run_ops(ops: Vec<Op>, boxes: &mut Vec<Vec<Lens>>) {
|
|
for op in ops.into_iter() {
|
|
let hash = op.hash();
|
|
let existing = boxes[hash]
|
|
.iter()
|
|
.find_position(|lens| lens.label == op.label);
|
|
match op.ty {
|
|
OpType::Dash => {
|
|
if let Some((idx, _)) = existing {
|
|
boxes[hash].remove(idx);
|
|
}
|
|
}
|
|
OpType::Equals(focal_length) => {
|
|
let new_lens = Lens {
|
|
label: op.label,
|
|
focal_length,
|
|
};
|
|
if let Some((idx, _)) = existing {
|
|
boxes[hash][idx] = new_lens;
|
|
} else {
|
|
boxes[hash].push(new_lens);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn focusing_power(boxes: &[Vec<Lens>]) -> usize {
|
|
let mut res = 0;
|
|
for (i, lenses) in boxes.iter().enumerate() {
|
|
for (j, lens) in lenses.iter().enumerate() {
|
|
res += (i + 1) * (j + 1) * lens.focal_length as usize;
|
|
}
|
|
}
|
|
res
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::io::BufRead;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_hash() {
|
|
assert_eq!(hash("HASH"), 52);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sum_hashes() {
|
|
assert_eq!(
|
|
sum_hashes("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7"),
|
|
1320
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_ops() {
|
|
assert_eq!(
|
|
parse_ops("rn=1,cm-"),
|
|
vec![
|
|
Op {
|
|
label: "rn".into(),
|
|
ty: OpType::Equals(1)
|
|
},
|
|
Op {
|
|
label: "cm".into(),
|
|
ty: OpType::Dash
|
|
},
|
|
]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_run_ops() {
|
|
let ops = parse_ops("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7");
|
|
let mut boxes: Vec<Vec<Lens>> = vec![vec![]; 256];
|
|
run_ops(ops, &mut boxes);
|
|
assert_eq!(
|
|
boxes[0],
|
|
vec![
|
|
Lens {
|
|
label: "rn".into(),
|
|
focal_length: 1
|
|
},
|
|
Lens {
|
|
label: "cm".into(),
|
|
focal_length: 2
|
|
},
|
|
]
|
|
);
|
|
assert_eq!(
|
|
boxes[3],
|
|
vec![
|
|
Lens {
|
|
label: "ot".into(),
|
|
focal_length: 7
|
|
},
|
|
Lens {
|
|
label: "ab".into(),
|
|
focal_length: 5
|
|
},
|
|
Lens {
|
|
label: "pc".into(),
|
|
focal_length: 6
|
|
},
|
|
]
|
|
);
|
|
for i in 0..256 {
|
|
if i == 0 || i == 3 {
|
|
continue;
|
|
}
|
|
assert!(boxes[i].is_empty());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_focusing_power() {
|
|
let ops = parse_ops("rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7");
|
|
let mut boxes: Vec<Vec<Lens>> = vec![vec![]; 256];
|
|
run_ops(ops, &mut boxes);
|
|
assert_eq!(focusing_power(&boxes), 145);
|
|
}
|
|
}
|