solution: day 3

This commit is contained in:
Matej Janezic 2024-12-03 07:22:09 +01:00
parent 0000004082
commit 0000005022
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
2 changed files with 94 additions and 0 deletions

1
data/examples/03.txt Normal file
View File

@ -0,0 +1 @@
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

93
src/bin/03.rs Normal file
View File

@ -0,0 +1,93 @@
use std::iter::once;
use regex::Regex;
fn get_mul_a_b_start(input: &str) -> Vec<(usize, usize, usize)> {
let r = Regex::new(r"mul\((\d+),(\d+)\)").unwrap();
r.captures_iter(input)
.map(|x| {
let a = x.get(1).unwrap().as_str().parse().unwrap();
let b = x.get(2).unwrap().as_str().parse().unwrap();
let start = x.get(0).unwrap().start();
(a, b, start)
})
.collect()
}
fn get_do_start(input: &str) -> Vec<usize> {
let d = Regex::new(r"do\(\)").unwrap();
// instructions are enabled at the beginning
once(0)
.chain(d.captures_iter(input).map(|x| x.get(0).unwrap().start()))
.collect()
}
fn get_dont_start(input: &str) -> Vec<usize> {
let n = Regex::new(r"don't\(\)").unwrap();
n.captures_iter(input)
.map(|x| x.get(0).unwrap().start())
.collect()
}
pub fn part_one(input: &str) -> Option<usize> {
get_mul_a_b_start(input)
.into_iter()
.map(|(a, b, _)| a * b)
.sum::<usize>()
.into()
}
pub fn part_two(input: &str) -> Option<usize> {
let ds = get_do_start(input);
let ns = get_dont_start(input);
let mut c = 0;
let mut d = None;
let mut n = None;
// increment pointer p while ps[p] < s, ps needs to be sorted
let mv_ptr = |ps: &[usize], p: Option<usize>, s| {
ps.iter()
.enumerate()
.skip(p.unwrap_or_default())
.take_while(|(_, &x)| x < s)
.last()
.map(|x| x.0)
};
for (a, b, s) in get_mul_a_b_start(input) {
d = mv_ptr(&ds, d, s);
n = mv_ptr(&ns, n, s);
// d is always some becaues we push a `0` to the start of array in `get_do_start` so we
// only need to check the (Some(_), Some(_)) case
if let (Some(dd), Some(nn)) = (d, n) {
if ds[dd] < ns[nn] {
continue;
}
}
c += a * b;
}
c.into()
}
aoc::solution!(3);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
assert_eq!(
part_one(&aoc::template::read_file("examples", 3)),
Some(161)
);
}
#[test]
fn test_part_two() {
assert_eq!(part_two(&aoc::template::read_file("examples", 3)), Some(48));
}
}