palmer/
display.rs

1pub const SCREEN_WIDTH: usize = 64;
2pub const SCREEN_HEIGHT: usize = 32;
3
4pub type Pixels = [bool; SCREEN_WIDTH * SCREEN_HEIGHT];
5
6#[derive(Debug, Clone)]
7pub struct Display {
8  pub pixels: Pixels,
9}
10
11impl Display {
12  pub fn new() -> Display {
13    Display {
14      pixels: [false; SCREEN_WIDTH * SCREEN_HEIGHT],
15    }
16  }
17
18  pub fn clear(&mut self) {
19    self.pixels = [false; SCREEN_WIDTH * SCREEN_HEIGHT];
20  }
21
22  fn set_pixel(&mut self, x: usize, y: usize, value: bool) {
23    self.pixels[x + y * SCREEN_WIDTH] = value;
24  }
25
26  fn get_pixel(&self, x: usize, y: usize) -> bool {
27    self.pixels[x + y * SCREEN_WIDTH]
28  }
29
30  fn xor_pixel(&mut self, x: usize, y: usize, new_value: bool) -> bool {
31    let current = self.get_pixel(x, y);
32    let new_pixel = current ^ new_value;
33    self.set_pixel(x, y, new_pixel);
34    current && !new_pixel
35  }
36
37  pub fn draw(&mut self, x: usize, y: usize, sprite: &[u8]) -> u8 {
38    let mut new_vf = 0;
39
40    sprite.iter().enumerate().for_each(|(line_number, line)| {
41      if line_number + y < SCREEN_HEIGHT {
42        format!("{:08b}", line)
43          .chars()
44          .map(|char| char == '1')
45          .enumerate()
46          .for_each(|(column_number, pixel)| {
47            if column_number + x < SCREEN_WIDTH {
48              if self.xor_pixel(x + column_number, y + line_number, pixel) {
49                new_vf = 1;
50              }
51            }
52          });
53      }
54    });
55
56    new_vf
57  }
58}
59
60#[cfg(test)]
61mod tests {
62  use super::*;
63
64  #[test]
65  fn get_pixel() {
66    let mut display = Display::new();
67    display.pixels[1] = true;
68    assert_eq!(display.get_pixel(1, 0), true);
69    assert_eq!(display.get_pixel(0, 0), false);
70  }
71
72  #[test]
73  fn set_pixel() {
74    let mut display = Display::new();
75    display.set_pixel(1, 1, true);
76    assert_eq!(display.get_pixel(1, 1), true);
77    display.set_pixel(1, 1, false);
78    assert_eq!(display.get_pixel(1, 1), false);
79  }
80
81  #[test]
82  fn clear_screen() {
83    let mut display = Display::new();
84    display.set_pixel(1, 3, true);
85    display.set_pixel(5, 15, true);
86    display.clear();
87    assert!(display.pixels.iter().all(|pixel| { !*pixel }));
88  }
89
90  #[test]
91  fn draw() {
92    let lines: [u8; 4] = [0b01101100, 0b00011000, 0b00011000, 0b00111100];
93    let mut display = Display::new();
94    display.draw(0, 0, &lines);
95    for i in 0..4 {
96      for j in 0..8 {
97        if i == 0 {
98          assert_eq!(display.get_pixel(j, i), [1, 2, 4, 5].contains(&j));
99        } else if i < 3 {
100          assert_eq!(display.get_pixel(j, i), [3, 4].contains(&j));
101        } else {
102          assert_eq!(display.get_pixel(j, i), [2, 3, 4, 5].contains(&j));
103        }
104      }
105    }
106  }
107
108  #[test]
109  fn draw_erases() {
110    let lines: [u8; 4] = [0b01101100, 0b00011000, 0b00011000, 0b00111100];
111    let mut display = Display::new();
112    display.draw(0, 0, &lines);
113    display.draw(0, 0, &lines);
114    assert!(display.pixels.iter().all(|pixel| { !*pixel }));
115  }
116}