use std::time::Instant; use rustc_hash::FxHashMap; const INPUT: &str = include_str!("inputs/day08.txt"); enum Modifier { Increment(isize), Decrement(isize), } impl Modifier { fn new(what: &str, quantity: &str) -> Self { match what { "inc" => Self::Increment(quantity.parse::().unwrap()), _ => Self::Decrement(quantity.parse::().unwrap()), } } fn apply(&self, to: &mut isize) { match self { Self::Increment(q) => *to += q, Self::Decrement(q) => *to -= q, } } } enum Comparator { Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual, } impl Comparator { fn eval(&self, lhs: isize, rhs: isize) -> bool { match self { Comparator::Equal => lhs == rhs, Comparator::NotEqual => lhs != rhs, Comparator::Less => lhs < rhs, Comparator::LessEqual => lhs <= rhs, Comparator::Greater => lhs > rhs, Comparator::GreaterEqual => lhs >= rhs, } } } impl From<&str> for Comparator { fn from(value: &str) -> Self { match value { "==" => Comparator::Equal, "!=" => Comparator::NotEqual, "<" => Comparator::Less, "<=" => Comparator::LessEqual, ">" => Comparator::Greater, ">=" => Comparator::GreaterEqual, _ => panic!("bug"), } } } struct Condition<'a> { register: &'a str, comp: Comparator, value: isize, } impl<'a> Condition<'a> { fn eval(&self, registers: &FxHashMap<&str, isize>) -> bool { self.comp .eval(*registers.get(self.register).unwrap_or(&0), self.value) } fn new(register: &'a str, comp: &str, value: &str) -> Self { Self { register, comp: comp.into(), value: value.parse::().unwrap(), } } } struct Instruction<'a> { register: &'a str, modifier: Modifier, condition: Condition<'a>, } impl<'a> Instruction<'a> { fn parse(input: &'a str) -> Self { let mut parts = input.split_whitespace().filter(|&v| v != "if"); Instruction { register: parts.next().unwrap(), modifier: Modifier::new(parts.next().unwrap(), parts.next().unwrap()), condition: Condition::new( parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap(), ), } } } fn parse<'a>(input: &'a str) -> Vec> { input.lines().map(Instruction::parse).collect() } fn p1(input: &str) -> isize { let instructions = parse(input); let mut registers = FxHashMap::default(); for instruction in instructions { if instruction.condition.eval(®isters) { instruction .modifier .apply(registers.entry(instruction.register).or_default()); } } *registers.values().max().unwrap() } fn p2(input: &str) -> isize { let instructions = parse(input); let mut registers = FxHashMap::default(); let mut max = isize::MIN; for instruction in instructions { if instruction.condition.eval(®isters) { let reg = registers.entry(instruction.register).or_default(); instruction.modifier.apply(reg); max = max.max(*reg); } } max } fn main() { let now = Instant::now(); let solution = p1(INPUT); println!("p1 {:?} {}", now.elapsed(), solution); let now = Instant::now(); let solution = p2(INPUT); println!("p2 {:?} {}", now.elapsed(), solution); } #[cfg(test)] mod tests { use super::*; #[test] fn test_p1() { let input = "b inc 5 if a > 1\na inc 1 if b < 5\nc dec -10 if a >= 1\nc inc -20 if c == 10"; assert_eq!(p1(input), 1); } #[test] fn test_p2() { let input = "b inc 5 if a > 1\na inc 1 if b < 5\nc dec -10 if a >= 1\nc inc -20 if c == 10"; assert_eq!(p2(input), 10); } }