use crate::solvers::Solver; use grid::Grid; use std::io::BufRead; pub struct TrashCompactor {} impl TrashCompactor { const NUMBER_SPLIT_CHAR: char = ' '; const SUM_SIGN: &'static str = "+"; const PRODUCT_SIGN: &'static str = "*"; fn add_row_layout_line(line: &str, numbers: &mut Grid) { let v: Vec = line .split(Self::NUMBER_SPLIT_CHAR) .filter_map(|s| { if s.is_empty() { None } else { Some(s.parse().unwrap()) } }) .collect(); numbers.push_row(v); } fn row_layout_calculation(numbers: &Grid, signs: &Vec<&str>) -> u64 { let mut result = 0; for (i, sign) in signs.iter().enumerate() { match *sign { Self::SUM_SIGN => result += numbers.iter_col(i).sum::(), Self::PRODUCT_SIGN => result += numbers.iter_col(i).product::(), _ => {} } } result } fn add_column_layout_line(line: &str, numbers: &mut Vec) { let add = line .bytes() .map(|c| if c.is_ascii_digit() { c - b'0' } else { 0 }) .collect::>(); if numbers.len() < 1 { *numbers = vec![0; add.len()]; } for (i, n) in numbers.iter_mut().enumerate() { if add[i] > 0 { *n = *n * 10 + add[i] as u64; } } } fn column_layout_calculation(numbers: &Vec, signs: &Vec<&str>) -> u64 { let mut result = 0; let mut it = numbers.iter(); for sign in signs { let block_it = it.by_ref().take_while(|&&n| n > 0); match *sign { Self::SUM_SIGN => result += block_it.sum::(), Self::PRODUCT_SIGN => result += block_it.product::(), _ => {} } } result } fn signs(line: &str) -> Vec<&str> { line.split(Self::NUMBER_SPLIT_CHAR) .filter(|s| !s.is_empty()) .collect() } } impl Solver for TrashCompactor { const PUZZLE_INDEX: u8 = 6; const PUZZLE_NAME: &'static str = "Trash Compactor"; fn process_data(&self, reader: R) -> (u64, u64) { let mut row_layout_result = 0; let mut column_layout_result = 0; let mut row_layout_numbers = Grid::new(0, 0); let mut column_layout_numbers = Vec::new(); for line in reader.lines().map_while(Result::ok) { if line.as_bytes()[0].is_ascii_digit() || line.as_bytes()[0].is_ascii_whitespace() { Self::add_row_layout_line(&line, &mut row_layout_numbers); Self::add_column_layout_line(&line, &mut column_layout_numbers); } else { let signs = Self::signs(&line); row_layout_result = Self::row_layout_calculation(&row_layout_numbers, &signs); column_layout_result = Self::column_layout_calculation(&column_layout_numbers, &signs); } } (row_layout_result, column_layout_result) } }