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