use std::convert::TryFrom; use std::env::args; use std::fs::File; use std::io::BufRead; use std::io::BufReader; mod package; use package::Package; use package::PackageReader; impl std::fmt::Display for Package { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self._type == 4 { write!(f, "{}", self.value)?; assert_eq!(self.children.len(), 0); } else { let op = match self._type { 0 => "sum", 1 => "prod", 2 => "min", 3 => "max", 5 => "gt", 6 => "lt", 7 => "eq", _ => unreachable!(), }; write!(f, "{}(", op)?; let mut first = true; for child in self.children.iter() { if first { first = false; } else { write!(f, ", ")?; } write!(f, "{}", child)?; } write!(f, ")")?; } return Ok(()); } } fn evaluate(package: &Package) -> u64 { let mut values = package.children.iter().map(|p| evaluate(p)); return match package._type { 0 => values.sum(), 1 => values.product(), 2 => values.min().unwrap(), 3 => values.max().unwrap(), 4 => package.value, 5 => { assert_eq!(package.children.len(), 2); if values.next() > values.next() {1} else {0} }, 6 => { assert_eq!(package.children.len(), 2); if values.next() < values.next() {1} else {0} }, 7 => { assert_eq!(package.children.len(), 2); if values.next() == values.next() {1} else {0} }, _ => unreachable!(), }; } fn main() { let path = args().nth(1).unwrap(); let file = File::open(path).unwrap(); for line in BufReader::new(file).lines() { let buffer: Vec = line .unwrap() .chars() .map(|c| u8::try_from(c.to_digit(16).unwrap()).unwrap()) .collect(); let package = PackageReader::read(buffer).unwrap(); // println!("{}", package); println!("{}", evaluate(&package)); } }