#[derive(Debug)] pub enum Instruction { Noop, Addx(isize), } pub fn parse_instructions(input: &String) -> Vec { let mut result = Vec::new(); for line in input.lines() { if line == "noop" { result.push(Instruction::Noop); } else { let (inst, v) = line.split_once(' ').unwrap(); assert_eq!(inst, "addx"); let v = v.parse().unwrap(); result.push(Instruction::Addx(v)); } } result } #[derive(Debug)] pub struct CPU { pub x: isize, pub cycle: isize, instructions: Vec, pc: usize, inst_cycle: usize, } impl CPU { pub fn new(instructions: Vec) -> CPU { CPU { x: 1, cycle: 0, instructions, pc: 0, inst_cycle: 0, } } pub fn do_cycle(&mut self) -> Option<()> { if let Some(inst) = self.instructions.get(self.pc) { match inst { Instruction::Noop => { self.pc += 1; } Instruction::Addx(v) => { self.inst_cycle += 1; if self.inst_cycle == 2 { self.pc += 1; self.inst_cycle = 0; self.x += v; } } } self.cycle += 1; Some(()) } else { None } } pub fn signal_strength(&self) -> isize { return self.x * (self.cycle + 1); } } pub struct CRT { pub pixels: [[char; 40]; 6], } impl CRT { pub fn new() -> CRT { CRT { pixels: [['.'; 40]; 6], } } pub fn render(&mut self, cpu: &CPU) { let c = cpu.cycle; assert!(c >= 0 && c < 240); let x = c % 40; let y = c / 40; let sprite_pos = cpu.x - 1; let px = &mut self.pixels[y as usize][x as usize]; if x >= sprite_pos && x < sprite_pos + 3 { *px = '#'; } else { *px = '.'; } } pub fn draw(&self) { for y in 0..6 { for x in 0..40 { print!("{}", self.pixels[y][x]); } print!("\n"); } } }