105 lines
2.3 KiB
Rust
105 lines
2.3 KiB
Rust
#[derive(Debug)]
|
|
pub enum Instruction {
|
|
Noop,
|
|
Addx(isize),
|
|
}
|
|
|
|
pub fn parse_instructions(input: &String) -> Vec<Instruction> {
|
|
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<Instruction>,
|
|
pc: usize,
|
|
inst_cycle: usize,
|
|
}
|
|
|
|
impl CPU {
|
|
pub fn new(instructions: Vec<Instruction>) -> 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");
|
|
}
|
|
}
|
|
}
|