summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Kramkowski <tomasz@kramkow.ski>2024-12-03 10:21:48 +0000
committerTomasz Kramkowski <tomasz@kramkow.ski>2024-12-03 10:21:48 +0000
commit91c27347645fa5550bcc4dc40150c2c097ca7057 (patch)
tree85b5ceed751a829cebeb2b20fde3fde1f382e849
parentb4339b5f69909f10db14dc22e9413ba498b4f3d4 (diff)
downloadaoc2024-91c27347645fa5550bcc4dc40150c2c097ca7057.tar.gz
aoc2024-91c27347645fa5550bcc4dc40150c2c097ca7057.tar.xz
aoc2024-91c27347645fa5550bcc4dc40150c2c097ca7057.zip
Day 3
-rw-r--r--src/bin/3.rs144
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(())
+}