Skip to content

Instantly share code, notes, and snippets.

@oskardotglobal
Created December 10, 2024 15:03
Show Gist options
  • Save oskardotglobal/22af033645bcd44a5659e3071abe47e5 to your computer and use it in GitHub Desktop.
Save oskardotglobal/22af033645bcd44a5659e3071abe47e5 to your computer and use it in GitHub Desktop.
use itertools::Itertools;
use std::str::Chars;
use super::INPUT;
#[derive(Debug)]
enum Tokens {
Do,
Dont,
Mul(i64, i64),
}
struct Scanner<'a> {
buffer: &'a mut Chars<'a>,
result: Vec<Tokens>,
eof: bool,
}
macro expect($self:expr, $char:expr) {
if !$self.is_expected($char) {
return;
}
}
macro expect_many($self:expr, $chars:expr) {
if !$self.are_expected($chars) {
return;
}
}
impl<'a> Scanner<'a> {
pub fn new(buffer: &'a mut Chars<'a>) -> Self {
Self {
buffer,
result: Vec::new(),
eof: false,
}
}
fn read(&mut self) -> Option<char> {
let char = self.buffer.next();
if char.is_none() {
self.eof = true;
}
char
}
fn read_many(&mut self, n: usize) -> Vec<char> {
let chars: Vec<char> = self.buffer.take(n).collect();
if chars.len() != n {
self.eof = true;
}
chars
}
fn is_expected(&mut self, expected: char) -> bool {
match self.read() {
Some(char) if char == expected => true,
_ => false,
}
}
fn are_expected(&mut self, expected: Vec<char>) -> bool {
let chars = self.read_many(expected.len());
chars == expected
}
fn scan_digits(&mut self) -> Option<i64> {
let chars = self
.buffer
.take_while_ref(|c| c.is_ascii_digit())
.collect::<String>();
if self.buffer.clone().next().is_none() {
self.eof = true
}
match chars.is_empty() {
true => None,
false => Some(chars.parse::<i64>().unwrap()),
}
}
fn scan_mul(&mut self) {
expect_many!(self, vec!['u', 'l', '(']);
let first = self.scan_digits();
expect!(self, ',');
let second = self.scan_digits();
expect!(self, ')');
if let (Some(first), Some(second)) = (first, second) {
self.result.push(Tokens::Mul(first, second))
}
}
fn scan_mode(&mut self) {
expect!(self, 'o');
match self.read() {
Some('(') => {
expect!(self, ')');
self.result.push(Tokens::Do)
}
Some('n') => {
expect_many!(self, vec!['\'', 't', '(', ')']);
self.result.push(Tokens::Dont)
}
_ => (),
}
}
pub fn scan(&mut self) -> &Vec<Tokens> {
while !self.eof {
match self.read() {
Some('m') => self.scan_mul(),
Some('d') => self.scan_mode(),
_ => (),
};
}
&self.result
}
}
pub fn part2() -> i64 {
let mut chars = INPUT.chars();
let mut scanner = Scanner::new(&mut chars);
let tokens = scanner.scan();
let mut enabled = true;
tokens
.iter()
.filter_map(|token| match (token, enabled) {
(Tokens::Mul(a, b), true) => Some(a * b),
(Tokens::Do, false) => {
enabled = true;
None
}
(Tokens::Dont, true) => {
enabled = false;
None
}
_ => None,
})
.sum()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment