/// Sometimes I wake up in the morning and pretend to be a regex engine use std::{error::Error, fs::File, io::Read}; #[derive(PartialEq, Eq, Copy, Clone, Debug)] enum State { Outside, D, O, DoLParen, N, Apos, T, DontLParen, M, U, L, Num1, Num2, End, } struct Scanner { state: State, mul_enable: bool, num1: i64, num2: i64, total1: i64, total2: i64, } impl Scanner { fn new() -> Self { Self { state: State::Outside, mul_enable: true, num1: 0, num2: 0, total1: 0, total2: 0, } } fn feed(&mut self, s: &[u8]) { // Technically I should be feeding an "EOF" character but it's fine // since we don't terminate on repetition for c in s.iter().copied() { let next_state = match self.state { State::Outside | State::End => match c { b'm' => State::M, b'd' => State::D, _ => State::Outside, }, State::D => match c { b'o' => State::O, _ => State::Outside, }, State::O => match c { b'(' => State::DoLParen, b'n' => State::N, _ => State::Outside, }, State::N => match c { b'\'' => State::Apos, _ => State::Outside, }, State::Apos => match c { b't' => State::T, _ => State::Outside, }, State::T => match c { b'(' => State::DontLParen, _ => State::Outside, }, State::DoLParen | State::DontLParen => match c { b')' => State::End, _ => State::Outside, }, State::M => match c { b'u' => State::U, _ => State::Outside, }, State::U => match c { b'l' => State::L, _ => State::Outside, }, State::L => match c { b'(' => State::Num1, _ => State::Outside, }, State::Num1 => match c { b',' => State::Num2, _ if c.is_ascii_digit() => State::Num1, _ => State::Outside, }, State::Num2 => match c { b')' => State::End, _ if c.is_ascii_digit() => State::Num2, _ => State::Outside, }, }; match (self.state, next_state) { (State::L, State::Num1) => self.num1 = 0, (State::Num1, State::Num2) => self.num2 = 0, (State::DoLParen, State::End) => self.mul_enable = true, (State::DontLParen, State::End) => self.mul_enable = false, (State::Num2, State::End) => { let m = self.num1 * self.num2; self.total1 += m; if self.mul_enable { self.total2 += m; } } (State::Num1, State::Num1) => { self.num1 *= 10; self.num1 += char::from(c).to_digit(10).unwrap() as i64; } (State::Num2, State::Num2) => { self.num2 *= 10; self.num2 += char::from(c).to_digit(10).unwrap() as i64; } _ => (), } self.state = next_state; } } fn totals(&self) -> (i64, i64) { (self.total1, self.total2) } } fn main() -> Result<(), Box> { let mut f = File::open("input/3")?; let mut buf = [0; 8 * 1024]; let mut scanner = Scanner::new(); loop { let n = f.read(&mut buf)?; if n == 0 { break; }; scanner.feed(&buf[..n]); } let (p1, p2) = scanner.totals(); println!("{p1}\n{p2}"); Ok(()) }