diff options
author | Tomasz Kramkowski <tomasz@kramkow.ski> | 2024-12-03 10:21:48 +0000 |
---|---|---|
committer | Tomasz Kramkowski <tomasz@kramkow.ski> | 2024-12-03 10:21:48 +0000 |
commit | 91c27347645fa5550bcc4dc40150c2c097ca7057 (patch) | |
tree | 85b5ceed751a829cebeb2b20fde3fde1f382e849 | |
parent | b4339b5f69909f10db14dc22e9413ba498b4f3d4 (diff) | |
download | aoc2024-91c27347645fa5550bcc4dc40150c2c097ca7057.tar.gz aoc2024-91c27347645fa5550bcc4dc40150c2c097ca7057.tar.xz aoc2024-91c27347645fa5550bcc4dc40150c2c097ca7057.zip |
Day 3
-rw-r--r-- | src/bin/3.rs | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/bin/3.rs b/src/bin/3.rs new file mode 100644 index 0000000..b0d5d6c --- /dev/null +++ b/src/bin/3.rs @@ -0,0 +1,144 @@ +/// 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<dyn Error>> { + 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(()) +} |