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}