From 91c27347645fa5550bcc4dc40150c2c097ca7057 Mon Sep 17 00:00:00 2001
From: Tomasz Kramkowski <tomasz@kramkow.ski>
Date: Tue, 3 Dec 2024 10:21:48 +0000
Subject: Day 3

---
 src/bin/3.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)
 create mode 100644 src/bin/3.rs

(limited to 'src/bin')

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(())
+}
-- 
cgit v1.2.3-70-g09d2