109 lines
2.3 KiB
Rust
109 lines
2.3 KiB
Rust
#![feature(generators)]
|
|
#![feature(generator_clone)]
|
|
#![feature(iter_from_generator)]
|
|
#![warn(clippy::pedantic)]
|
|
|
|
use std::{
|
|
io::{stdin, Read},
|
|
iter,
|
|
str::FromStr,
|
|
};
|
|
|
|
type Word = i64;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
struct MachineState {
|
|
x: Word,
|
|
}
|
|
|
|
impl MachineState {
|
|
const fn new() -> Self {
|
|
Self { x: 1 }
|
|
}
|
|
|
|
fn execute(&mut self, op: MicroOp) {
|
|
match op {
|
|
MicroOp::Noop => {}
|
|
MicroOp::Addx(i) => self.x += i,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
enum MicroOp {
|
|
Noop,
|
|
Addx(Word),
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
enum Instruction {
|
|
Noop,
|
|
Addx(Word),
|
|
}
|
|
|
|
impl Instruction {
|
|
pub fn expand(self) -> impl Iterator<Item = MicroOp> {
|
|
iter::from_generator(move || match self {
|
|
Self::Noop => yield MicroOp::Noop,
|
|
Self::Addx(x) => {
|
|
yield MicroOp::Noop;
|
|
yield MicroOp::Addx(x);
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
impl FromStr for Instruction {
|
|
type Err = ();
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let mut args = s.split_whitespace();
|
|
match args.next().ok_or(())? {
|
|
"noop" => Ok(Self::Noop),
|
|
"addx" => {
|
|
let i = args.next().ok_or(())?.parse().map_err(|_| ())?;
|
|
Ok(Self::Addx(i))
|
|
}
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
const START: MachineState = MachineState::new();
|
|
|
|
let mut data = String::new();
|
|
stdin().read_to_string(&mut data).unwrap();
|
|
|
|
let states: Vec<_> = data
|
|
.lines()
|
|
.map(|l| l.parse().unwrap())
|
|
.flat_map(Instruction::expand)
|
|
.scan(START, |state, op| {
|
|
let prev = state.clone();
|
|
state.execute(op);
|
|
Some(prev)
|
|
})
|
|
.enumerate()
|
|
.map(|(i, state)| (Word::try_from(i).unwrap() + 1, state))
|
|
.collect();
|
|
|
|
let sum: Word = states
|
|
.iter()
|
|
.skip(20 - 1)
|
|
.step_by(40)
|
|
.map(|(i, state)| i * state.x)
|
|
.sum();
|
|
println!("{:?}", sum);
|
|
|
|
let crt: Vec<_> = states
|
|
.iter()
|
|
.map(|(i, state)| ((i - 1) % 40).abs_diff(state.x) < 2)
|
|
.map(|x| if x { '#' } else { '.' })
|
|
.collect();
|
|
|
|
for line in crt.chunks_exact(40) {
|
|
println!("{}", line.iter().collect::<String>());
|
|
}
|
|
}
|