takuzu/
grid.rs

1use std::{
2    fmt::{self, Display},
3    ops::{Index, IndexMut},
4    str::FromStr,
5};
6
7use cell::Cell;
8use error::{GridError, GridParseError, GridSizeError};
9use Cell::*;
10
11pub(crate) mod cell;
12pub(crate) mod error;
13
14/// An opaque container for manipulating takuzu grids.
15///
16/// It provides the internal logic and other convenience functions.
17/// To create a `Grid` you can:
18///
19/// * create an empty one yourself with [`Grid::new`].
20/// * use the [`FromStr`](#impl-FromStr) trait, e.g. by calling [`parse`](str::parse) on a string.
21///
22/// You can modify the cells as you like.
23/// Grids that break the rules will not be solved.
24#[derive(Clone, Debug, Eq, PartialEq, Hash)]
25pub struct Grid {
26    cells: Box<[Cell]>,
27    size: usize,
28}
29
30impl Display for Grid {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        use std::fmt::Write;
33
34        for row in self.cells.chunks(self.size) {
35            for cell in row {
36                let c = match cell {
37                    Zero => '0',
38                    One => '1',
39                    Empty => '.',
40                };
41                f.write_char(c)?;
42            }
43            writeln!(f)?;
44        }
45        Ok(())
46    }
47}
48
49impl Index<(usize, usize)> for Grid {
50    type Output = Cell;
51
52    fn index(&self, (i, j): (usize, usize)) -> &Self::Output {
53        &self.cells[i * self.size + j]
54    }
55}
56
57impl IndexMut<(usize, usize)> for Grid {
58    fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut Self::Output {
59        &mut self.cells[i * self.size + j]
60    }
61}
62
63impl FromStr for Grid {
64    type Err = GridParseError;
65
66    fn from_str(s: &str) -> Result<Self, Self::Err> {
67        use GridParseError::*;
68        use GridSizeError::*;
69
70        if s.is_empty() {
71            return Err(BadSize(EmptyGrid));
72        }
73        let lines: Vec<_> = s.lines().collect();
74        let size = lines.len();
75        if size % 2 == 1 {
76            return Err(BadSize(OddNumberSize(size)));
77        }
78        let mut cells = Vec::with_capacity(size * size);
79        for (i, line) in lines.iter().enumerate() {
80            let mut count: usize = 0;
81            for c in line.chars() {
82                cells.push(match c {
83                    '0' => Zero,
84                    '1' => One,
85                    '.' => Empty,
86                    _ => return Err(UnexpectedCharacter(c)),
87                });
88                count += 1;
89            }
90            if count != size {
91                return Err(BadSize(NotASquare { line: i + 1, found: count, expected: size }));
92            }
93        }
94        Ok(Self::from_parts(cells, size))
95    }
96}
97
98impl Grid {
99    /// Creates an new empty grid of a given size.
100    ///
101    /// # Errors
102    ///
103    /// Returns an error if the size is an odd number or 0.
104    pub fn new(size: usize) -> Result<Self, GridSizeError> {
105        use GridSizeError::*;
106
107        if size == 0 {
108            Err(EmptyGrid)
109        } else if size % 2 == 1 {
110            Err(OddNumberSize(size))
111        } else {
112            Ok(Self::from_parts(vec![Empty; size * size], size))
113        }
114    }
115
116    /// Returns the number of rows/columns of the array.
117    pub fn size(&self) -> usize {
118        self.size
119    }
120
121    /// Extracts a slice containing the entire underlying array.
122    pub fn as_slice(&self) -> &[Cell] {
123        &self.cells
124    }
125
126    /// Extracts a mutable slice of the entire underlying array.
127    pub fn as_mut_slice(&mut self) -> &mut [Cell] {
128        &mut self.cells
129    }
130
131    /// Returns `true` if the grid contains no `Empty` cell.
132    pub fn is_filled(&self) -> bool {
133        !self.cells.contains(&Empty)
134    }
135
136    /// Verifies that the grid does not currently violate any of the rules.
137    ///
138    /// Returns `true` if the grid is legal.
139    pub fn is_legal(&self) -> bool {
140        self.check_rule1() && self.check_rule2() && self.check_rule3()
141    }
142
143    /// Verifies that a certain cell does not violate any of the rules.
144    ///
145    /// Returns `true` if the value is legal.
146    pub fn is_cell_legal(&self, coord: (usize, usize)) -> bool {
147        self[coord].is_empty() || {
148            self.check_cell_rule1(coord)
149                && self.check_cell_rule2(coord)
150                && self.check_cell_rule3(coord)
151        }
152    }
153
154    /// Returns the coordinates of the first `Empty` cell
155    /// or `None` if the grid is filled.
156    pub fn next_empty(&self) -> Option<(usize, usize)> {
157        for (i, cell) in self.cells.iter().enumerate() {
158            if cell.is_empty() {
159                let row = i / self.size;
160                let col = i % self.size;
161                return Some((row, col));
162            }
163        }
164        None
165    }
166
167    /// Solves the grid using both rules logic and a backtracking algorithm.
168    ///
169    /// Returns an array containing the solution(s), or an empty array if there
170    /// are none.
171    ///
172    /// # Errors
173    ///
174    /// Returns an error before any attempt at solving if
175    /// the grid breaks any of the rules
176    /// (i.e. if [`is_legal`](Grid::is_legal) returns `false`).
177    pub fn solve(&self) -> Result<Vec<Self>, GridError> {
178        if !self.is_legal() {
179            return Err(GridError::Illegal);
180        }
181        let (mut stack, mut solutions) = (Vec::new(), Vec::new());
182        let mut grid = self.clone();
183        while grid.apply_rules() {}
184        stack.push(grid);
185        while !stack.is_empty() {
186            let mut grid = stack.pop().unwrap();
187            match grid.next_empty() {
188                Some(coord) => {
189                    grid[coord] = One;
190                    if grid.is_cell_legal(coord) {
191                        let mut grid = grid.clone();
192                        while grid.apply_rules() {}
193                        stack.push(grid);
194                    }
195                    grid[coord] = Zero;
196                    if grid.is_cell_legal(coord) {
197                        while grid.apply_rules() {}
198                        stack.push(grid);
199                    }
200                }
201                None => {
202                    if grid.is_legal() {
203                        solutions.push(grid);
204                    }
205                }
206            }
207        }
208        Ok(solutions)
209    }
210}
211
212impl Grid {
213    /// Creates a `Grid` from a `Vec` of `Cell`s
214    /// and the size of the grid.
215    ///
216    /// # Panics
217    ///
218    /// Panics if:
219    ///
220    /// * size is 0
221    /// * size is odd
222    /// * the number of cells is not size²
223    fn from_parts(cells: Vec<Cell>, size: usize) -> Self {
224        assert!(size != 0, "attempted to create an empty grid");
225        assert!(size % 2 == 0, "attempted to create an odd sized grid");
226        assert!(
227            cells.len() == size * size,
228            "putative grid size does not match the number of cells"
229        );
230        Self { cells: cells.into_boxed_slice(), size }
231    }
232
233    /// Verifies that the grid abides by rule 1.
234    ///
235    /// Rule 1: no more than two of either number adjacent to each other
236    /// (both vertically and horizontally).
237    fn check_rule1(&self) -> bool {
238        for row in self.cells.chunks(self.size) {
239            for triplet in row.windows(3) {
240                let cell = triplet[0];
241                if cell.is_filled() && cell == triplet[1] && cell == triplet[2] {
242                    return false;
243                }
244            }
245        }
246        for i in 0..self.size - 2 {
247            for j in 0..self.size {
248                let cell = self[(i, j)];
249                if cell.is_filled() && cell == self[(i + 1, j)] && cell == self[(i + 2, j)] {
250                    return false;
251                }
252            }
253        }
254        true
255    }
256
257    /// Verifies that the grid abides by rule 2.
258    ///
259    /// Rule 2: each row and each column should contain an equal number
260    /// of 0s and 1s.
261    fn check_rule2(&self) -> bool {
262        let nmax = self.size / 2;
263        for row in self.cells.chunks(self.size) {
264            let count = row.iter().fold((0, 0), |mut count, cell| {
265                match cell {
266                    Zero => count.0 += 1,
267                    One => count.1 += 1,
268                    Empty => {}
269                }
270                count
271            });
272            if count.0 > nmax || count.1 > nmax {
273                return false;
274            }
275        }
276        for i in 0..self.size {
277            let mut count = (0, 0);
278            for j in 0..self.size {
279                match self[(j, i)] {
280                    Zero => count.0 += 1,
281                    One => count.1 += 1,
282                    Empty => {}
283                }
284            }
285            if count.0 > nmax || count.1 > nmax {
286                return false;
287            }
288        }
289        true
290    }
291
292    /// Verifies that the grid abides by rule 3.
293    ///
294    /// Rule 3: no two rows and no two columns can be the same.
295    fn check_rule3(&self) -> bool {
296        for i in 0..self.size - 1 {
297            for j in i + 1..self.size {
298                if (0..self.size).all(|k| self[(i, k)].is_filled() && self[(i, k)] == self[(j, k)])
299                {
300                    return false;
301                }
302                if (0..self.size).all(|k| self[(k, i)].is_filled() && self[(k, i)] == self[(k, j)])
303                {
304                    return false;
305                }
306            }
307        }
308        true
309    }
310
311    /// Verifies that the cell with the given coordinates abides by rule 1.
312    ///
313    /// Rule 1: no more than two of either number adjacent to each other
314    /// (both vertically and horizontally).
315    fn check_cell_rule1(&self, (row, col): (usize, usize)) -> bool {
316        use std::cmp::min;
317
318        for i in row.saturating_sub(2)..min(row + 1, self.size - 2) {
319            let cell = self[(i, col)];
320            if cell.is_filled() && cell == self[(i + 1, col)] && cell == self[(i + 2, col)] {
321                return false;
322            }
323        }
324        for j in col.saturating_sub(2)..min(col + 1, self.size - 2) {
325            let cell = self[(row, j)];
326            if cell.is_filled() && cell == self[(row, j + 1)] && cell == self[(row, j + 2)] {
327                return false;
328            }
329        }
330        true
331    }
332
333    /// Verifies that the cell with the given coordinates abides by rule 2.
334    ///
335    /// Rule 2: each row and each column should contain an equal number
336    /// of 0s and 1s.
337    fn check_cell_rule2(&self, (row, col): (usize, usize)) -> bool {
338        let nmax = self.size / 2;
339        let mut count = (0, 0, 0, 0);
340        for k in 0..self.size {
341            match self[(row, k)] {
342                Zero => count.0 += 1,
343                One => count.1 += 1,
344                Empty => {}
345            }
346            match self[(k, col)] {
347                Zero => count.2 += 1,
348                One => count.3 += 1,
349                Empty => {}
350            }
351        }
352        count.0 <= nmax && count.1 <= nmax && count.2 <= nmax && count.3 <= nmax
353    }
354
355    /// Verifies that the cell with the given coordinates abides by rule 3.
356    ///
357    /// Rule 3: no two rows and no two columns can be the same.
358    fn check_cell_rule3(&self, (row, col): (usize, usize)) -> bool {
359        let rows_abide =
360            (0..self.size).filter(|&i| i != row && self[(i, col)] == self[(row, col)]).all(|i| !{
361                (0..self.size).all(|j| self[(row, j)].is_filled() && self[(row, j)] == self[(i, j)])
362            });
363        let cols_abide =
364            (0..self.size).filter(|&j| j != col && self[(row, j)] == self[(row, col)]).all(|j| !{
365                (0..self.size).all(|i| self[(i, col)].is_filled() && self[(i, col)] == self[(i, j)])
366            });
367        rows_abide && cols_abide
368    }
369}
370
371impl Grid {
372    /// Skims through the grid once, filling in the blanks
373    /// where the value is unambiguous according to one of the rules,
374    /// then returns if the grid was modified or repeats the operation
375    /// for the next rule. Each rule is applied once at the most.
376    ///
377    /// Returns `true` if the grid was modified.
378    ///
379    /// # Warning
380    ///
381    /// Does not guarantee the legality of the modifications.
382    /// For performance reasons, deductions made from a rule are not
383    /// checked for legality against the other rules. This can result in
384    /// grids with no legal solution being filled illegally.
385    /// Grids with one or more legal solution(s) are not affected.
386    fn apply_rules(&mut self) -> bool {
387        self.apply_rule1() || self.apply_rule2() || self.apply_rule3()
388    }
389
390    /// Disambiguates empty cells after rule 1.
391    ///
392    /// Rule 1: no more than two of either number adjacent to each other
393    /// (both vertically and horizontally).
394    #[rustfmt::skip]
395    fn apply_rule1(&mut self) -> bool {
396        let mut rule_applied = false;
397        for i in 0..self.size {
398            for j in 0..self.size - 2 {
399                let trio = (self[(i, j)], self[(i, j + 1)], self[(i, j + 2)]);
400                match trio {
401                    (Empty, Zero, Zero) => { self[(i, j  )] = One;  rule_applied = true; }
402                    (Zero, Empty, Zero) => { self[(i, j+1)] = One;  rule_applied = true; }
403                    (Zero, Zero, Empty) => { self[(i, j+2)] = One;  rule_applied = true; }
404                    (Empty, One, One)   => { self[(i, j  )] = Zero; rule_applied = true; }
405                    (One, Empty, One)   => { self[(i, j+1)] = Zero; rule_applied = true; }
406                    (One, One, Empty)   => { self[(i, j+2)] = Zero; rule_applied = true; }
407                    _ => {},
408                }
409                let trio = (self[(j, i)], self[(j + 1, i)], self[(j + 2, i)]);
410                match trio {
411                    (Empty, Zero, Zero) => { self[(j  , i)] = One;  rule_applied = true; }
412                    (Zero, Empty, Zero) => { self[(j+1, i)] = One;  rule_applied = true; }
413                    (Zero, Zero, Empty) => { self[(j+2, i)] = One;  rule_applied = true; }
414                    (Empty, One, One)   => { self[(j  , i)] = Zero; rule_applied = true; }
415                    (One, Empty, One)   => { self[(j+1, i)] = Zero; rule_applied = true; }
416                    (One, One, Empty)   => { self[(j+2, i)] = Zero; rule_applied = true; }
417                    _ => {},
418                }
419            }
420        }
421        rule_applied
422    }
423
424    /// Disambiguates empty cells after rule 2.
425    ///
426    /// Rule 2: each row and each column should contain an equal number
427    /// of 0s and 1s.
428    fn apply_rule2(&mut self) -> bool {
429        let mut rule_applied = false;
430        let nmax = self.size / 2;
431        for i in 0..self.size {
432            let mut count = (0, 0, 0, 0);
433            for j in 0..self.size {
434                match self[(i, j)] {
435                    Zero => count.0 += 1,
436                    One => count.1 += 1,
437                    Empty => {}
438                }
439                match self[(j, i)] {
440                    Zero => count.2 += 1,
441                    One => count.3 += 1,
442                    Empty => {}
443                }
444            }
445            if count.0 == nmax && count.1 != nmax {
446                rule_applied = true;
447                for j in 0..self.size {
448                    if self[(i, j)].is_empty() {
449                        self[(i, j)] = One;
450                    }
451                }
452            } else if count.1 == nmax && count.0 != nmax {
453                rule_applied = true;
454                for j in 0..self.size {
455                    if self[(i, j)].is_empty() {
456                        self[(i, j)] = Zero;
457                    }
458                }
459            }
460            if count.2 == nmax && count.3 != nmax {
461                rule_applied = true;
462                for j in 0..self.size {
463                    if self[(j, i)].is_empty() {
464                        self[(j, i)] = One;
465                    }
466                }
467            } else if count.3 == nmax && count.2 != nmax {
468                rule_applied = true;
469                for j in 0..self.size {
470                    if self[(j, i)].is_empty() {
471                        self[(j, i)] = Zero;
472                    }
473                }
474            }
475        }
476        rule_applied
477    }
478
479    /// Disambiguates empty cells after rule 3.
480    ///
481    /// Rule 3: no two rows and no two columns can be the same.
482    fn apply_rule3(&mut self) -> bool {
483        macro_rules! row {
484            ($i:expr) => {
485                self.cells[$i * self.size..($i + 1) * self.size]
486            };
487        }
488
489        let size = self.size;
490        let mut rule_applied = false;
491        for i in 0..size {
492            if row!(i).iter().filter(|value| value.is_empty()).count() == 2 {
493                for l in 0..size {
494                    if l != i
495                        && !row!(l).contains(&Empty)
496                        && row!(i)
497                            .iter()
498                            .zip(row!(l).iter())
499                            .filter(|&(value, _)| value.is_filled())
500                            .all(|(value, other)| value == other)
501                    {
502                        for j in 0..size {
503                            if self[(i, j)].is_empty() {
504                                self[(i, j)] = !self[(l, j)];
505                            }
506                        }
507                        rule_applied = true;
508                        break;
509                    }
510                }
511            }
512            let j = i;
513            if (0..size).filter(|&l| self[(l, j)].is_empty()).count() == 2 {
514                for m in 0..size {
515                    if m != j
516                        && (0..size).all(|i| self[(i, m)].is_filled())
517                        && (0..size)
518                            .filter(|&i| self[(i, j)].is_filled())
519                            .all(|i| self[(i, j)] == self[(i, m)])
520                    {
521                        for i in 0..size {
522                            if self[(i, j)].is_empty() {
523                                self[(i, j)] = !self[(i, m)];
524                            }
525                        }
526                        rule_applied = true;
527                        break;
528                    }
529                }
530            }
531        }
532        rule_applied
533    }
534}