Skip to content

Instantly share code, notes, and snippets.

@tomaspavlic
Created December 10, 2024 16:08
Show Gist options
  • Save tomaspavlic/741fde3a86b4feb7be87efe1178901dc to your computer and use it in GitHub Desktop.
Save tomaspavlic/741fde3a86b4feb7be87efe1178901dc to your computer and use it in GitHub Desktop.
#![feature(let_chains)]
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{char, i32},
sequence::{delimited, separated_pair, tuple},
IResult,
};
fn parse_mul(s: &str) -> IResult<&str, (i32, i32)> {
let numbers_parser = delimited(char('('), separated_pair(i32, char(','), i32), char(')'));
let (s, (_, numbers)) = tuple((tag("mul"), numbers_parser))(s)?;
Ok((s, numbers))
}
fn parse_conditional_statement(s: &str) -> IResult<&str, bool> {
let (s, parsed) = alt((tag("do()"), tag("don't()")))(s)?;
Ok((s, parsed == "do()"))
}
fn find_muls(s: &str, use_conditional_statements: bool) -> Vec<(i32, i32)> {
let mut remainder = s;
let mut v = vec![];
let mut include = true;
loop {
if remainder.is_empty() {
break;
}
if use_conditional_statements && let Ok((s, i)) = parse_conditional_statement(remainder) {
remainder = s;
include = i;
}
remainder = if let Ok((s, numbers)) = parse_mul(remainder) {
if include {
v.push(numbers)
}
s
} else {
&remainder[1..]
}
}
v
}
fn sum_multiples(v: &[(i32, i32)]) -> i32 {
v.iter().map(|(a, b)| a * b).sum()
}
fn main() -> anyhow::Result<()> {
let input = include_str!("../input/day3.txt");
let muls = find_muls(input, false);
let part1 = sum_multiples(&muls);
dbg!(part1);
let muls = find_muls(input, true);
let part2 = sum_multiples(&muls);
dbg!(part2);
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parse_mul_works() {
let a = "mul(1,2)";
let actual = parse_mul(a);
let expected = IResult::Ok(("", (1, 2)));
assert_eq!(actual, expected);
}
#[test]
fn find_all_mul_works() {
let actual = find_muls(
"xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))",
false,
);
assert_eq!(actual, vec![(2, 4), (5, 5), (11, 8), (8, 5)]);
}
#[test]
fn find_all_mul_works_with_includes_and_exludes() {
let actual = find_muls(
"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))",
true,
);
assert_eq!(actual, vec![(2, 4), (8, 5)]);
}
#[test]
fn sum_multiples_works() {
let actual = sum_multiples(&[(2, 4), (5, 5), (11, 8), (8, 5)]);
assert_eq!(161, actual);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment