tis_100/
image.rs

1//! Constructs for generating images using the TIS-100.
2
3/// The colors that the TIS-100 can generate.
4#[derive(Debug, PartialEq, Eq, Copy, Clone)]
5pub enum Color {
6    Black,
7    DarkGrey,
8    BrightGrey,
9    White,
10    Red,
11}
12
13impl Color {
14    /// Get the color for the given integer representation.
15    fn from_isize(value: isize) -> Color {
16        match value {
17            1 => DarkGrey,
18            2 => BrightGrey,
19            3 => White,
20            4 => Red,
21            _ => Black,
22        }
23    }
24}
25
26use self::Color::*;
27
28/// The operational modes of the image.
29#[derive(Debug, PartialEq, Eq, Copy, Clone)]
30enum ImageMode {
31    Move,
32    Paint,
33}
34
35use self::ImageMode::*;
36
37/// An image that can receive values from the TIS-100. When in the `Move` mode, the image receives
38/// coordinates that tell it where to draw. When in the `Paint` mode, the image will draw values.
39/// Sending a negative value at any time will reset the image to `Move` mode.
40#[derive(Debug)]
41pub struct Image {
42    width: usize,
43    height: usize,
44    data: Vec<Color>,
45    mode: ImageMode,
46    position: Vec<isize>,
47    offset: usize,
48}
49
50impl Image {
51    /// Construct a new, empty `Image` with the given width and height.
52    pub fn new(width: usize, height: usize) -> Image {
53        let mut data = Vec::with_capacity(width * height);
54        for _ in 0..width * height {
55            data.push(Black);
56        }
57
58        Image {
59            width: width,
60            height: height,
61            data: data,
62            mode: Move,
63            position: Vec::new(),
64            offset: 0,
65        }
66    }
67
68    /// Construct a new `Image` with the given width, height, and initial values.
69    pub fn with_data(data: &Vec<isize>, width: usize, height: usize) -> Image {
70        assert_eq!(data.len(), width * height);
71
72        let data = data.iter().map(|&i| Color::from_isize(i)).collect::<Vec<_>>();
73
74        Image {
75            width: width,
76            height: height,
77            data: data,
78            mode: Move,
79            position: Vec::new(),
80            offset: 0,
81        }
82    }
83
84    /// Retrieve the image's data.
85    pub fn data(&self) -> &Vec<Color> {
86        &self.data
87    }
88
89    /// Write a value to the image. If the image is in `Move` mode, then the value will be
90    /// interpreted as a coordinate. If the image is in `Paint` mode, then the value will be
91    /// interpreted as a color unless the value is negative.
92    pub fn write(&mut self, value: isize) {
93        if value < 0 {
94            self.position.clear();
95            self.mode = Move;
96            self.offset = 0;
97            return;
98        }
99
100        if self.mode == Move {
101            self.position.push(value);
102
103            if self.position.len() == 2 {
104                self.mode = Paint;
105            }
106
107            return;
108        }
109
110        let row_off = self.position[0] as usize * self.width;
111
112        if row_off < self.width * self.height {
113            let col = self.position[1] as usize + self.offset;
114
115            if col < self.width {
116                self.data[row_off + col] = Color::from_isize(value);
117            }
118        }
119
120        self.offset += 1;
121    }
122}
123
124impl PartialEq for Image {
125    fn eq(&self, other: &Self) -> bool {
126        self.data == other.data
127    }
128}
129
130impl Eq for Image {}
131
132#[test]
133fn test_color_from_isize() {
134    assert_eq!(Color::from_isize(0), Black);
135    assert_eq!(Color::from_isize(1), DarkGrey);
136    assert_eq!(Color::from_isize(2), BrightGrey);
137    assert_eq!(Color::from_isize(3), White);
138    assert_eq!(Color::from_isize(4), Red);
139    assert_eq!(Color::from_isize(5), Black);
140}
141
142#[test]
143fn test_image_with_data() {
144    let expected = vec![DarkGrey, BrightGrey, White, Red];
145    let data = vec![1, 2, 3, 4];
146    let image = Image::with_data(&data, 2, 2);
147
148    assert_eq!(expected, image.data().clone());
149}
150
151#[test]
152fn test_image_write() {
153    let expected = vec![DarkGrey, BrightGrey, White, Red];
154    let mut image = Image::new(2, 2);
155
156    image.write(0);
157    image.write(0);
158    image.write(1);
159    image.write(2);
160    image.write(-1);
161    image.write(1);
162    image.write(0);
163    image.write(3);
164    image.write(4);
165    image.write(-1);
166
167    assert_eq!(expected, image.data().clone());
168}