nonogram_rs/
nonogram.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4#[cfg(feature = "serde")]
5use serde::de::Error;
6
7use std::ops::{Index, IndexMut};
8
9/// A cell of a [Nonogram].
10#[derive(Copy, Clone, PartialEq, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub enum Cell<T> {
13    /// A box with some color of type `T`.
14    Box { color: T },
15    /// A space ("x") between chains.
16    Space,
17}
18
19/// A nonogram with a fix size containing some [Cell]s.
20/// `T` is the type used to represent colors.
21/// ```rust
22/// use nonogram_rs::{Nonogram, Cell};
23///
24/// let mut n: Nonogram<u8> = Nonogram::new(5, 5);
25///
26/// n[(0, 3)] = Cell::Space;
27/// n[(1, 0)] = Cell::Box { color: 0 };
28/// n[(4, 2)] = Cell::Box { color: 1 };
29///
30/// let value = n[(0, 3)];
31/// ```
32#[derive(Clone, PartialEq)]
33pub struct Nonogram<T> {
34    cols: usize,
35    rows: usize,
36    data: Vec<Cell<T>>,
37}
38
39impl<T: Clone> Nonogram<T> {
40    /// Constructs a new nonogram.
41    pub fn new(cols: usize, rows: usize) -> Self {
42        Self {
43            cols,
44            rows,
45            data: vec![Cell::Space; cols * rows],
46        }
47    }
48}
49
50impl<T> Nonogram<T> {
51    /// Returns the column count.
52    pub fn cols(&self) -> usize {
53        self.cols
54    }
55
56    /// Returns the row count.
57    pub fn rows(&self) -> usize {
58        self.rows
59    }
60
61    /// Returns the index of a cell by column and row.
62    ///
63    /// # Panics
64    /// If the column or row is out of bounds.
65    fn index_of(&self, pos: (usize, usize)) -> usize {
66        assert!(pos.0 < self.cols);
67        assert!(pos.1 < self.rows);
68
69        pos.1 * self.cols + pos.0
70    }
71}
72
73impl<T: Copy> TryFrom<Vec<Vec<Cell<T>>>> for Nonogram<T> {
74    type Error = ();
75
76    fn try_from(value: Vec<Vec<Cell<T>>>) -> Result<Self, Self::Error> {
77        let row_len = value.len();
78        let col_len = value.iter().map(Vec::len).next().unwrap_or(0);
79
80        let mut nonogram = Nonogram::new(col_len, row_len);
81
82        for row in 0..row_len {
83            if value[row].len() != col_len {
84                return Err(());
85            }
86            for col in 0..col_len {
87                nonogram[(col, row)] = value[row][col];
88            }
89        }
90        Ok(nonogram)
91    }
92}
93
94impl<T: Copy> From<Nonogram<T>> for Vec<Vec<Cell<T>>> {
95    fn from(nonogram: Nonogram<T>) -> Self {
96        let mut rows: Vec<Vec<Cell<T>>> = Vec::new();
97
98        for row_i in 0..nonogram.rows() {
99            let mut row = Vec::new();
100
101            for col_i in 0..nonogram.cols() {
102                row.push(nonogram[(col_i, row_i)]);
103            }
104            rows.push(row);
105        }
106        rows
107    }
108}
109
110impl<T> Index<(usize, usize)> for Nonogram<T> {
111    type Output = Cell<T>;
112
113    fn index(&self, pos: (usize, usize)) -> &Self::Output {
114        let index = self.index_of(pos);
115
116        unsafe { self.data.get_unchecked(index) }
117    }
118}
119
120impl<T> IndexMut<(usize, usize)> for Nonogram<T> {
121    fn index_mut(&mut self, pos: (usize, usize)) -> &mut Self::Output {
122        let index = self.index_of(pos);
123
124        unsafe { self.data.get_unchecked_mut(index) }
125    }
126}
127
128#[cfg(feature = "serde")]
129impl<T: Copy + Serialize> Serialize for Nonogram<T> {
130    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131    where
132        S: Serializer,
133    {
134        let data: Vec<Vec<Cell<T>>> = self.clone().into();
135
136        data.serialize(serializer)
137    }
138}
139
140#[cfg(feature = "serde")]
141impl<'a, T: Copy + Deserialize<'a>> Deserialize<'a> for Nonogram<T> {
142    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
143    where
144        D: Deserializer<'a>,
145    {
146        let data: Vec<Vec<Cell<T>>> = Vec::deserialize(deserializer)?;
147
148        data.try_into()
149            .map_err(|_| Error::custom("Failed to construct a nonogram."))
150    }
151}
152
153#[cfg(test)]
154mod test {
155    use super::*;
156
157    #[test]
158    fn nonogram_cols() {
159        let n: Nonogram<()> = Nonogram::new(3, 7);
160
161        assert_eq!(3, n.cols());
162    }
163
164    #[test]
165    fn nonogram_rows() {
166        let n: Nonogram<()> = Nonogram::new(5, 2);
167
168        assert_eq!(2, n.rows());
169    }
170
171    #[test]
172    fn nonogram_index_mut() {
173        let mut n = Nonogram::new(5, 2);
174
175        n[(3, 1)] = Cell::Box { color: 5 };
176
177        assert!(matches!(n[(3, 1)], Cell::Box { color: 5 }));
178    }
179
180    #[test]
181    #[should_panic]
182    fn nonogram_index_mut_col_oob() {
183        let n: Nonogram<()> = Nonogram::new(4, 8);
184
185        n[(4, 0)];
186    }
187
188    #[test]
189    #[should_panic]
190    fn nonogram_index_mut_row_oob() {
191        let n: Nonogram<()> = Nonogram::new(9, 5);
192
193        n[(0, 5)];
194    }
195
196    #[test]
197    fn vec_from_nonogram() {
198        let mut nonogram = Nonogram::new(2, 3);
199        nonogram[(0, 0)] = Cell::Space;
200        nonogram[(0, 1)] = Cell::Box { color: 3 };
201        nonogram[(0, 2)] = Cell::Space;
202        nonogram[(1, 0)] = Cell::Box { color: 4 };
203        nonogram[(1, 1)] = Cell::Box { color: 4 };
204        nonogram[(1, 2)] = Cell::Space;
205
206        let vec: Vec<Vec<Cell<i32>>> = nonogram.into();
207
208        assert_eq!(3, vec.len());
209        assert_eq!(2, vec[0].len());
210        assert_eq!(2, vec[0].len());
211        assert_eq!(2, vec[0].len());
212        assert!(matches!(vec[0][0], Cell::Space));
213        assert!(matches!(vec[1][0], Cell::Box { color: 3 }));
214        assert!(matches!(vec[2][0], Cell::Space));
215        assert!(matches!(vec[0][1], Cell::Box { color: 4 }));
216        assert!(matches!(vec[1][1], Cell::Box { color: 4 }));
217        assert!(matches!(vec[2][1], Cell::Space));
218    }
219
220    #[test]
221    fn nonogram_from_vec() {
222        let vec = vec![
223            vec![Cell::Box { color: 3 }, Cell::Space, Cell::Space],
224            vec![Cell::Box { color: 2 }, Cell::Box { color: 5 }, Cell::Space],
225        ];
226
227        let nonogram: Nonogram<i32> = vec.try_into().unwrap();
228
229        assert_eq!(3, nonogram.cols());
230        assert_eq!(2, nonogram.rows());
231        assert!(matches!(nonogram[(0, 0)], Cell::Box { color: 3 }));
232        assert!(matches!(nonogram[(1, 0)], Cell::Space));
233        assert!(matches!(nonogram[(2, 0)], Cell::Space));
234        assert!(matches!(nonogram[(0, 1)], Cell::Box { color: 2 }));
235        assert!(matches!(nonogram[(1, 1)], Cell::Box { color: 5 }));
236        assert!(matches!(nonogram[(2, 1)], Cell::Space));
237    }
238
239    #[test]
240    #[cfg(feature = "serde")]
241    fn serialize_deserialize() {
242        let mut src = Nonogram::new(3, 5);
243        src[(2, 3)] = Cell::Space;
244        src[(1, 0)] = Cell::Box { color: 4 };
245        src[(0, 2)] = Cell::Box { color: 2 };
246
247        let json = serde_json::to_string(&src).unwrap();
248        let target: Nonogram<i32> = serde_json::from_str(&json).unwrap();
249
250        for col in 0..src.cols() {
251            for row in 0..src.rows() {
252                assert_eq!(src[(col, row)], target[(col, row)]);
253            }
254        }
255    }
256}