Day 3 part 1
This commit is contained in:
182
day_03/src/main.rs
Normal file
182
day_03/src/main.rs
Normal file
@@ -0,0 +1,182 @@
|
||||
//https://adventofcode.com/2024/day/3
|
||||
//
|
||||
// Run command: cargo run ./input.txt
|
||||
|
||||
use core::ops::Mul;
|
||||
use core::panic;
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, prelude::*};
|
||||
use std::str::FromStr;
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
enum Token {
|
||||
Text(String),
|
||||
Number(String),
|
||||
Comma,
|
||||
OpenParenthesis,
|
||||
CloseParenthesis,
|
||||
SpecialChar(char),
|
||||
Whitespace,
|
||||
NewLine,
|
||||
}
|
||||
|
||||
// struct StringBuffer {
|
||||
// string: String,
|
||||
// seek_index: usize,
|
||||
// }
|
||||
|
||||
// impl StringBuffer {
|
||||
// pub fn new(string: String) -> StringBuffer{
|
||||
// StringBuffer {
|
||||
// string,
|
||||
// seek_index: 0,
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn take_char(&mut self) -> Option<char> {
|
||||
// if self.seek_index < self.string.len() {
|
||||
// self.seek_index += 1;
|
||||
// return self.string.char_indices()[self.seek_index - 1];
|
||||
// }
|
||||
// return None;
|
||||
// }
|
||||
// }
|
||||
|
||||
fn is_mul_text_token(text_token: &str) -> bool {
|
||||
if text_token.ends_with("mul") {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn tokenize(input_str: String) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = Vec::new();
|
||||
let mut chars = input_str.chars().peekable();
|
||||
while let Some(c) = chars.next() {
|
||||
let token = match c {
|
||||
// Text Numeric
|
||||
_ if char::is_alphabetic(c) => {
|
||||
let mut text = c.to_string();
|
||||
while let Some(alphabetic_char) = chars.next_if(|p| p.is_alphabetic()) {
|
||||
text.push(alphabetic_char)
|
||||
}
|
||||
Token::Text(text)
|
||||
}
|
||||
// Numbers
|
||||
_ if char::is_numeric(c) => {
|
||||
let mut number = c.to_string();
|
||||
while let Some(numeric_char) = chars.next_if(|p| p.is_numeric()) {
|
||||
number.push(numeric_char)
|
||||
}
|
||||
Token::Number(number)
|
||||
}
|
||||
// whitespace
|
||||
_ if char::is_whitespace(c) => {
|
||||
while chars.next_if(|p| p.is_whitespace()).is_some() {}
|
||||
Token::Whitespace
|
||||
}
|
||||
_ if c == ',' => Token::Comma,
|
||||
_ if c == '(' => Token::OpenParenthesis,
|
||||
_ if c == ')' => Token::CloseParenthesis,
|
||||
_ if c == '\n' => Token::NewLine,
|
||||
_ => Token::SpecialChar(c),
|
||||
};
|
||||
tokens.push(token);
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MulOp {
|
||||
lhs: String,
|
||||
rhs: String,
|
||||
}
|
||||
|
||||
impl MulOp {
|
||||
pub fn multiple<T>(&self) -> Result<<T as Mul>::Output, <T as FromStr>::Err>
|
||||
where
|
||||
T: FromStr + Mul,
|
||||
{
|
||||
let lhs: T = self.lhs.parse()?;
|
||||
let rhs: T = self.rhs.parse()?;
|
||||
Ok(lhs * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_tokens(tokens: &Vec<Token>) -> Vec<MulOp> {
|
||||
let mut tokens = tokens.iter().peekable();
|
||||
let mut muls: Vec<MulOp> = Vec::new();
|
||||
while let Some(token) = tokens.next() {
|
||||
match token {
|
||||
Token::Text(t) => {
|
||||
if is_mul_text_token(t) {
|
||||
// Take OpenParenthesis or continue
|
||||
if !tokens.next_if_eq(&&Token::OpenParenthesis).is_some() {
|
||||
continue;
|
||||
}
|
||||
// Take Number or continue
|
||||
let lhs = if let Some(Token::Number(lhs)) =
|
||||
tokens.next_if(|v| matches!(v, Token::Number(_)))
|
||||
{
|
||||
lhs.to_owned()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
// Take Comma or continue
|
||||
if !tokens.next_if_eq(&&Token::Comma).is_some() {
|
||||
continue;
|
||||
}
|
||||
// Take Number or continue
|
||||
let rhs = if let Some(Token::Number(rhs)) =
|
||||
tokens.next_if(|v: &&Token| matches!(v, Token::Number(_)))
|
||||
{
|
||||
rhs.to_owned()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
// Take CloseParenthesis or continue
|
||||
if !tokens.next_if_eq(&&Token::CloseParenthesis).is_some() {
|
||||
continue;
|
||||
}
|
||||
muls.push(MulOp { lhs, rhs });
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
muls
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Handle command input
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 2 {
|
||||
panic!(
|
||||
"{} must be run with a single argument of files name!",
|
||||
&args[0]
|
||||
)
|
||||
}
|
||||
let input_file_string = &args[1];
|
||||
|
||||
let input_buffer = BufReader::new(File::open(input_file_string)?);
|
||||
|
||||
let mut tokens: Vec<Token> = Vec::new();
|
||||
for line in input_buffer.lines() {
|
||||
tokens.append(&mut tokenize(line? + "\n"));
|
||||
}
|
||||
//println!("{:?}", tokens);
|
||||
|
||||
let muls = parse_tokens(&tokens);
|
||||
//println!("{:?}", muls);
|
||||
|
||||
let mut accumulator: i64 = 0;
|
||||
for mul in muls {
|
||||
accumulator += mul.multiple::<i64>()?;
|
||||
}
|
||||
|
||||
println!("Answer: {}", accumulator);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user