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#[derive(Copy, Clone, PartialEq, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub enum Cell<T> {
13 Box { color: T },
15 Space,
17}
18
19#[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 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 pub fn cols(&self) -> usize {
53 self.cols
54 }
55
56 pub fn rows(&self) -> usize {
58 self.rows
59 }
60
61 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}