AdventOfCode/Rust/2022/10.rs

127 lines
2.8 KiB
Rust

#![feature(test)]
use aoc::parsing::parse_ascii;
type Input = Vec<Instruction>;
enum Instruction {
Noop,
Addx(i32),
}
struct Cpu<'a, I> {
instructions: I,
current: Option<&'a Instruction>,
cycle: usize,
x: i32,
}
impl<'a, I> Cpu<'a, I>
where
I: Iterator<Item = &'a Instruction>,
{
fn new(instructions: I) -> Self {
Self {
instructions,
current: None,
cycle: 0,
x: 1,
}
}
}
struct Cycle {
cycle: usize,
x: i32,
}
impl<'a, I> Iterator for Cpu<'a, I>
where
I: Iterator<Item = &'a Instruction>,
{
type Item = Cycle;
fn next(&mut self) -> Option<Self::Item> {
let current = Cycle {
cycle: self.cycle,
x: self.x,
};
self.cycle += 1;
if let Some(Instruction::Addx(x)) = self.current.take() {
self.x += x;
} else {
self.current = Some(self.instructions.next()?);
}
Some(current)
}
}
fn setup(input: &str) -> Input {
input
.trim()
.lines()
.map(|line| {
if line == "noop" {
Instruction::Noop
} else {
Instruction::Addx(line[5..].parse().unwrap())
}
})
.collect()
}
fn part1(input: &Input) -> i32 {
Cpu::new(input.iter())
.filter_map(|Cycle { cycle, x }| {
if cycle % 40 == 19 {
Some((cycle as i32 + 1) * x)
} else {
None
}
})
.sum()
}
fn part2(input: &Input) -> String {
let mut dots = [[false; 40]; 6];
for Cycle { cycle, x } in Cpu::new(input.iter()) {
if x.abs_diff(cycle as i32 % 40) <= 1 {
dots[cycle / 40][cycle % 40] = true;
}
}
parse_ascii(&dots.iter().map(|l| &l[..]).collect::<Vec<_>>())
}
#[cfg(test)]
mod test_cpu {
#[allow(unused_imports)]
use super::{Instruction::*, *};
macro_rules! test {
($name:ident, $instructions:expr, $expected:expr) => {
#[test]
fn $name() {
let cpu = Cpu::new($instructions.iter());
let cycles = cpu.map(|Cycle { cycle, x }| (cycle, x)).collect::<Vec<_>>();
let expected = $expected.into_iter().enumerate().collect::<Vec<_>>();
assert_eq!(cycles, expected);
}
};
}
test!(empty, [], []);
test!(noop, [Noop], [1]);
test!(noop3, [Noop, Noop, Noop], [1, 1, 1]);
test!(add, [Addx(2)], [1, 1]);
test!(add_noop, [Addx(2), Noop], [1, 1, 3]);
test!(noop_add_noop, [Noop, Addx(2), Noop], [1, 1, 1, 3]);
test!(
noop_add_add_noop,
[Noop, Addx(2), Addx(3), Noop],
[1, 1, 1, 3, 3, 6]
);
}
aoc::main!(2022, 10, ex: 1[a]);