sudoku_variants/
constraint.rs

1//! This module defines constraints which can be applied tu Sudoku grids, thus
2//! specifying the rules of the puzzle.
3//!
4//! Besides the definition of the [Constraint] trait, this crate contains some
5//! predefined constraint for default Sudoku rules and some variants. We will
6//! cover them first and afterwards show how to implement a custom constraint.
7//!
8//! # Default Sudoku rules
9//!
10//! To get the default Sudoku rules, [DefaultConstraint] can be used.
11//! Conceptually, it is a conjunction of [RowConstraint], [ColumnConstraint],
12//! and [BlockConstraint].
13//!
14//! # Variants
15//!
16//! Besides the default rules, `sudoku-variants` also offers some pre-defined
17//! variantions. As an example, we will use the [DiagonalsConstraint], which
18//! requires that the two diagonals, top-left to bottom-right and top-right to
19//! bottom-left, do not contain duplicate digits, just like each row, column,
20//! and block in standard Sudoku.
21//!
22//! Normally, one wants to apply a `DiagonalsConstraint` *and* a
23//! `DefaultConstraint`. This can be done in two ways: using a
24//! [CompositeConstraint] and using a [DynamicConstraint]. The first is
25//! type-checked over two parameter types, which both need to be constraints.
26//! It is provided one instance of each type, and is defined to be fulfilled
27//! if both instances are fulfilled. In contrast, the `DynamicConstraint` uses
28//! a vector of trait objects and is fulfilled if all entries are fulfilled.
29//! This enables a more flexible design and is less cumbersome, especially when
30//! combining more than two constraints, but comes at a runtime cost due to
31//! dynamic dispatch.
32//!
33//! To define our combination of default- and diagonals-constraints, we can
34//! write the following code:
35//!
36//! ```
37//! use sudoku_variants::constraint::{
38//!     CompositeConstraint,
39//!     DefaultConstraint,
40//!     DiagonalsConstraint,
41//!     DynamicConstraint
42//! };
43//!
44//! // Option 1: CompositeConstraint
45//! let c1 = CompositeConstraint::new(DefaultConstraint, DiagonalsConstraint);
46//!
47//! // Option 2: DynamicConstraint
48//! let c2 = DynamicConstraint::with_children(vec![
49//!     Box::new(DefaultConstraint),
50//!     Box::new(DiagonalsConstraint)
51//! ]);
52//! ```
53//!
54//! # Custom constraints
55//!
56//! When implementing a constraint, it is usually sufficient to implement
57//! [Constraint::check_number] and [Constraint::get_groups]. All other methods
58//! are default-implemented. However, the performance of [Constraint::check]
59//! could be improved by a specialized implementation, since by default it
60//! calls `check_number` for every cell.
61//!
62//! As an example of an implementation of a custom constraint, we will look at
63//! the source code of a subset of the `DiagonalsConstraint`, which we call
64//! `MainDiagonalConstraint`. It only checks the diagonal from the top-left to
65//! the bottom-right corner of the Sudoku.
66//!
67//! ```
68//! use sudoku_variants::SudokuGrid;
69//! use sudoku_variants::constraint::{Constraint, Group};
70//!
71//! #[derive(Clone)]
72//! struct MainDiagonalConstraint;
73//!
74//! impl Constraint for MainDiagonalConstraint {
75//!     fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
76//!             number: usize) -> bool {
77//!         // For all cells on the diagonal, the column index is equal to the
78//!         // row index. All other cells don't interact with this constraint,
79//!         // so we return true, indicating that they don't violate it.
80//!         if column == row {
81//!             let size = grid.size();
82//!
83//!             for i in 0..size {
84//!                 // Since column == row, if i == column we are looking at
85//!                 // the checked cell itself, which may contain the number.
86//!                 if i != column &&
87//!                         grid.has_number(i, i, number).unwrap() {
88//!                     return false;
89//!                 }
90//!             }
91//!         }
92//!
93//!         true
94//!     }
95//!
96//!     fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
97//!         // There is one group in this case: the main diagonal.
98//!         let size = grid.size();
99//!         let mut group = Group::new();
100//!
101//!         for i in 0..size {
102//!             group.push((i, i));
103//!         }
104//!
105//!         vec![ group ]
106//!     }
107//! }
108//! ```
109//!
110//! Deriving `Clone` is important, since occasionally Sudoku need to be cloned.
111//! Sudoku therefore implements `Clone`, which requires its constraint to be
112//! cloneable aswell. Note that `Clone` is not required by the `Constraint`
113//! trait, since that would make it impossible to create `Constraint`-trait
114//! objects, which are used in the `DynamicConstraint`. Instead,
115//! [CloneConstraint], which clones a trait object, is required for elements of
116//! a `DynamicConstraint`. However, if you derive `Clone`, you do not need to
117//! worry about `CloneConstraint`, since it is implemented for every constraint
118//! that implements `Clone` by default.
119
120use crate::SudokuGrid;
121use crate::util::USizeSet;
122
123use std::iter::Cloned;
124use std::slice::Iter;
125
126/// A group of cells, represented by a vector of their coordinates in the form
127/// `(column, row)`.
128pub type Group = Vec<(usize, usize)>;
129
130/// A constraint defines some property on a Sudoku grid. These are essentially
131/// the rules of the Sudoku. In standard Sudoku these are "No duplicates in a
132/// row" (`RowConstraint`), "No duplicates in a column" (`ColumnConstraint`),
133/// and "No duplicates in a block" (`BlockConstraint`). Here, however, the
134/// design is more flexible to allow for custom constraints.
135///
136/// By default, implementors of this trait only need to implement the
137/// `check_number` associated function, which verifies a proposed number for a
138/// specified cell. `check_cell` and `check` are implemented by default based
139/// on it, however `check` in particular may be very inefficient compared to a
140/// specialized implementation (it checks every cell using `check_number`).
141///
142/// Note regarding cloning: To enable wrapping constraints in a trait object,
143/// the `Clone` trait must not be required here. However, it is necessary later
144/// to create a Sudoku with this constraint. Implementing the `Clone` trait
145/// also automatically gives the `CloneConstraint` trait via a blanket
146/// implementation, so it is recommended to derive `Clone` and not worry about
147/// `CloneConstraint`.
148pub trait Constraint {
149
150    /// Checks whether the given [SudokuGrid] matches this constraint, that is,
151    /// every cell matches this constraint.  By default, this runs `check_cell`
152    /// on every cell of the grid, which may be inefficient, so custom
153    /// implementations may be advantageous.
154    fn check(&self, grid: &SudokuGrid) -> bool {
155        let size = grid.size();
156
157        for row in 0..size {
158            for column in 0..size {
159                if !self.check_cell(grid, column, row) {
160                    return false;
161                }
162            }
163        }
164
165        true
166    }
167
168    /// Checks whether the cell at the given position in the [SudokuGrid]
169    /// fulfills the constraint. This is the same as calling `check_number`
170    /// with the same coordinates and the number which is actually filled in
171    /// that cell. If the cell is empty, this function always returns `true`.
172    fn check_cell(&self, grid: &SudokuGrid, column: usize, row: usize)
173            -> bool {
174        if let Some(number) = grid.get_cell(column, row).unwrap() {
175            self.check_number(grid, column, row, number)
176        }
177        else {
178            true
179        }
180    }
181
182    /// Checks whether the given `number` would fit into the cell specified by
183    /// `column` and `row` into the `grid` without violating this constraint.
184    /// This function does *not* have to check whether `number` is actually a
185    /// valid number for this grid (i.e. in the interval [1, size]). If you
186    /// require this guarantee, use
187    /// [Sudoku::is_valid_number](crate::Sudoku::is_valid_number) instead.
188    ///
189    /// For some constraints, it may be difficult to decide whether a number
190    /// could actually fill the cell without making the puzzle impossible. It
191    /// is therefore explicitly *not* required for this function to check
192    /// whether the actual solution could contain that number, however it must
193    /// guarantee that an error in a full grid (where all numbers are filled
194    /// in) is detected. Still, it should detect errors way before that to
195    /// improve the performance of solvers.
196    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
197        number: usize) -> bool;
198
199    /// Gets a vector of all groups that are defined by this constraint. A
200    /// group is a set of cells which may not contain repeated numbers. As an
201    /// example, the [BlockConstraint] defines each block as a group. Some
202    /// constraints, such as the [KingsMoveConstraint], do not have groups. In
203    /// this particular case, a cell removed by a kings-move to the top-left
204    /// may be the same as one to the bottom-right, so the cells removed by a
205    /// kings-move from any particular cell cannot form a group. Such
206    /// constraints should return an empty vector here.
207    ///
208    /// Arguing about groups is necessary for some strategies. While it is
209    /// possible to solve Sudoku with constraints which do not implement this
210    /// method, getting this implementation will enable some strategies as well
211    /// as improve the performance of strategic backtracking.
212    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group>;
213}
214
215/// A [Constraint] that there are no duplicates in each row.
216#[derive(Clone)]
217pub struct RowConstraint;
218
219impl Constraint for RowConstraint {
220    fn check(&self, grid: &SudokuGrid) -> bool {
221        let size = grid.size();
222        let mut set = USizeSet::new(1, size).unwrap();
223
224        for row in 0..size {
225            set.clear();
226
227            for column in 0..size {
228                if let Some(number) = grid.get_cell(column, row).unwrap() {
229                    if !set.insert(number).unwrap() {
230                        return false;
231                    }
232                }
233            }
234        }
235
236        true
237    }
238
239    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
240            number: usize) -> bool {
241        let size = grid.size();
242
243        for other_column in 0..size {
244            if other_column != column &&
245                    grid.has_number(other_column, row, number).unwrap()  {
246                return false;
247            }
248        }
249
250        true
251    }
252
253    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
254        let size = grid.size();
255        let mut groups = Vec::new();
256
257        for row in 0..size {
258            let mut group = Group::new();
259
260            for column in 0..size {
261                group.push((column, row));
262            }
263
264            groups.push(group);
265        }
266
267        groups
268    }
269}
270
271/// A [Constraint] that there are no duplicates in each column.
272#[derive(Clone)]
273pub struct ColumnConstraint;
274
275impl Constraint for ColumnConstraint {
276
277    // TODO investigate whether code duplication between this and RowConstraint
278    // can be avoided.
279
280    fn check(&self, grid: &SudokuGrid) -> bool {
281        let size = grid.size();
282        let mut set = USizeSet::new(1, size).unwrap();
283
284        for column in 0..size {
285            set.clear();
286
287            for row in 0..size {
288                if let Some(number) = grid.get_cell(column, row).unwrap() {
289                    if !set.insert(number).unwrap() {
290                        return false;
291                    }
292                }
293            }
294        }
295
296        true
297    }
298
299    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
300            number: usize) -> bool {
301        let size = grid.size();
302
303        for other_row in 0..size {
304            if other_row != row &&
305                    grid.has_number(column, other_row, number).unwrap() {
306                return false;
307            }
308        }
309
310        true
311    }
312
313    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
314        let size = grid.size();
315        let mut groups = Vec::new();
316
317        for column in 0..size {
318            let mut group = Group::new();
319
320            for row in 0..size {
321                group.push((column, row));
322            }
323
324            groups.push(group);
325        }
326
327        groups
328    }
329}
330
331fn check_number_block(grid: &SudokuGrid, column: usize, row: usize,
332        number: usize, bop: impl Fn(bool, bool) -> bool) -> bool {
333    let block_width = grid.block_width();
334    let block_height = grid.block_height();
335    let block_column = (column / block_width) * block_width;
336    let block_row = (row / block_height) * block_height;
337
338    for other_row in block_row..(block_row + block_height) {
339        for other_column in block_column..(block_column + block_width) {
340            if bop(other_row != row, other_column != column) &&
341                    grid.has_number(other_column, other_row, number).unwrap() {
342                return false;
343            }
344        }
345    }
346
347    true
348}
349
350fn get_groups_block(grid: &SudokuGrid) -> Vec<Group> {
351    let block_width = grid.block_width();
352    let block_height = grid.block_height();
353    let mut groups = Vec::new();
354
355    for block_row in 0..block_width {
356        let base_row = block_row * block_height;
357
358        for block_column in 0..block_height {
359            let base_column = block_column * block_width;
360            let mut group = Group::new();
361
362            for sub_row in 0..block_height {
363                let row = base_row + sub_row;
364
365                for sub_column in 0..block_width {
366                    let column = base_column + sub_column;
367                    group.push((column, row));
368                }
369            }
370
371            groups.push(group);
372        }
373    }
374
375    groups
376}
377
378/// A [Constraint] that there are no duplicates in each block.
379#[derive(Clone)]
380pub struct BlockConstraint;
381
382impl Constraint for BlockConstraint {
383    
384    // TODO investigate whether code duplication between this and RowConstraint
385    // and ColumnConstraint can be avoided.
386
387    fn check(&self, grid: &SudokuGrid) -> bool {
388        let block_width = grid.block_width();
389        let block_height = grid.block_height();
390        let size = grid.size();
391        let mut set = USizeSet::new(1, size).unwrap();
392
393        for block_row in 0..block_width {
394            for block_column in 0..block_height {
395                set.clear();
396
397                let start_column = block_column * block_width;
398                let start_row = block_row * block_height;
399
400                for row in start_row..(start_row + block_height) {
401                    for column in start_column..(start_column + block_width) {
402                        if let Some(number) =
403                                grid.get_cell(column, row).unwrap() {
404                            if !set.insert(number).unwrap() {
405                                return false;
406                            }
407                        }
408                    }
409                }
410            }
411        }
412
413        true
414    }
415
416    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
417            number: usize) -> bool {
418        check_number_block(grid, column, row, number, |a, b| a || b)
419    }
420
421    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
422        get_groups_block(grid)
423    }
424}
425
426/// Similar to [BlockConstraint], but does not check numbers in the same row
427/// and column to save some time. For use in the [DefaultConstraint].
428#[derive(Clone)]
429struct BlockConstraintNoLineColumn;
430
431impl Constraint for BlockConstraintNoLineColumn {
432    fn check(&self, grid: &SudokuGrid) -> bool {
433        BlockConstraint.check(grid)
434    }
435
436    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
437            number: usize) -> bool {
438        check_number_block(grid, column, row, number, |a, b| a && b)
439    }
440
441    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
442        get_groups_block(grid)
443    }
444}
445
446/// The default Sudoku [Constraint] which is a logical conjunction of
447/// [RowConstraint], [ColumnConstraint], and [BlockConstraint].
448#[derive(Clone)]
449pub struct DefaultConstraint;
450
451impl Constraint for DefaultConstraint {
452    fn check(&self, grid: &SudokuGrid) -> bool {
453        RowConstraint.check(grid) &&
454            ColumnConstraint.check(grid) &&
455            BlockConstraintNoLineColumn.check(grid)
456    }
457
458    fn check_cell(&self, grid: &SudokuGrid, column: usize, row: usize)
459            -> bool {
460        RowConstraint.check_cell(grid, column, row) &&
461            ColumnConstraint.check_cell(grid, column, row) &&
462            BlockConstraintNoLineColumn.check_cell(grid, column, row)
463    }
464
465    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
466            number: usize) -> bool {
467        RowConstraint.check_number(grid, column, row, number) &&
468            ColumnConstraint.check_number(grid, column, row, number) &&
469            BlockConstraintNoLineColumn.check_number(grid, column, row, number)
470    }
471
472    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
473        let mut groups = RowConstraint.get_groups(grid);
474        groups.append(&mut ColumnConstraint.get_groups(grid));
475        groups.append(&mut BlockConstraintNoLineColumn.get_groups(grid));
476        groups
477    }
478}
479
480/// A [Constraint] which checks that there are no duplicates in each of the two
481/// diagonals ( ╲ and ╱ ).
482#[derive(Clone)]
483pub struct DiagonalsConstraint;
484
485impl Constraint for DiagonalsConstraint {
486    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
487            number: usize) -> bool {
488        let size = grid.size();
489
490        if column == row {
491            // main diagonal
492
493            for i in 0..size {
494                if i != column &&
495                        grid.has_number(i, i, number).unwrap() {
496                    return false;
497                }
498            }
499        }
500
501        if column + row == size - 1 {
502            // anti diagonal
503
504            for i in 0..size {
505                if i != column &&
506                        grid.has_number(i, size - i - 1, number).unwrap() {
507                    return false;
508                }
509            }
510        }
511
512        true
513    }
514
515    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
516        let size = grid.size();
517        let mut main_diagonal = Group::new();
518        let mut anti_diagonal = Group::new();
519
520        for i in 0..size {
521            main_diagonal.push((i, i));
522            anti_diagonal.push((i, size - i - 1));
523        }
524
525        vec![
526            main_diagonal,
527            anti_diagonal
528        ]
529    }
530}
531
532struct RelativeCellIter<'a, I>
533where
534    I : Iterator<Item = (isize, isize)>
535{
536    coords: I,
537    grid: &'a SudokuGrid,
538    center_column: usize,
539    center_row: usize
540}
541
542impl<'a, I> Iterator for RelativeCellIter<'a, I>
543where
544    I : Iterator<Item = (isize, isize)>
545{
546    type Item = Option<usize>;
547
548    fn next(&mut self) -> Option<Self::Item> {
549        while let Some((delta_column, delta_row)) = self.coords.next() {
550            let column = self.center_column as isize + delta_column;
551            let row = self.center_row as isize + delta_row;
552            let size = self.grid.size() as isize;
553
554            if column >= 0 && column < size && row >= 0 && row < size {
555                return Some(
556                    self.grid.get_cell(column as usize, row as usize)
557                        .unwrap());
558            }
559        }
560
561        None
562    }
563}
564
565type ISizePairIterator<'a> = Cloned<Iter<'a, (isize, isize)>>;
566
567impl<'a> RelativeCellIter<'a, ISizePairIterator<'a>> {
568    fn new(coords: &'a [(isize, isize)], grid: &'a SudokuGrid,
569            column: usize, row: usize)
570            -> RelativeCellIter<'a, ISizePairIterator<'a>> {
571        RelativeCellIter {
572            coords: coords.iter().cloned(),
573            grid,
574            center_column: column,
575            center_row: row
576        }
577    }
578}
579
580/// A trait for `Constraint`s that are defined by having no forbidden numbers
581/// in some relative configuration to the reference cell. Whether a number is
582/// forbidden is defined by [RelativeCellConstraint::is_forbidden], which is a
583/// boolean relation between the reference cell and the other cell. By default,
584/// this checks for equality.
585///
586/// As an example, the constraint that no diagonally adjacent cells have the
587/// same number may be formulated as a `RelativeCellConstraint` with the
588/// relative coordinates `[(-1, -1), (-1, +1), (+1, -1), (+1, +1)]`, with the
589/// default equality being used for `is_forbidden`.
590pub trait RelativeCellConstraint {
591
592    /// A slice of coordinates relative to the cell in question that must not
593    /// contain the same number.
594    const RELATIVE_COORDINATES: &'static [(isize, isize)];
595
596    /// Given the contents of the reference cell and one other cell that is
597    /// removed by one set of coordinates specified in
598    /// [RelativeCellConstraint::RELATIVE_COORDINATES], this method determines
599    /// whether the reference cell violates the constraint. Since it is assumed
600    /// that an empty cell cannot violate the constraint, this method is only
601    /// called if both cells contain a number.
602    ///
603    /// As an example, for ordinary constraints such as the no-knight's-move-
604    /// constraint, this is usually an equality check. A cell removed by a
605    /// knight's move may not be equal to the reference cell. This is actually
606    /// the default behavior for this method.
607    ///
608    /// However, in some situations this may be different. As an example, for
609    /// the no-adjacent-consecutive-constraint, this is a predicate that
610    /// determines whether the two numbers are consecutive.
611    ///
612    /// # Arguments
613    ///
614    /// * `reference_cell`: The cell which is currently tested, i.e. relative
615    /// to which the coordinates are defined.
616    /// * `other_cell`: A cell removed from the `reference_cell` by a set of
617    /// coordinates from [RelativeCellConstraint::RELATIVE_COORDINATES].
618    fn is_forbidden(&self, reference_cell: usize, other_cell: usize) -> bool {
619        reference_cell == other_cell
620    }
621}
622
623impl<C: RelativeCellConstraint> Constraint for C {
624    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
625            number: usize) -> bool {
626        let iter =
627            RelativeCellIter::new(&C::RELATIVE_COORDINATES, grid, column, row);
628        
629        for other_cell in iter {
630            if let Some(other_number) = other_cell {
631                if self.is_forbidden(number, other_number) {
632                    return false;
633                }
634            }
635        }
636        
637        true
638    }
639
640    fn get_groups(&self, _: &SudokuGrid) -> Vec<Group> {
641        Vec::new()
642    }
643}
644
645/// A [RelativeCellConstraint] that excludes duplicates a Chess-Knight's move
646/// away from the reference cell.
647///
648/// As a visualization, the cells marked with 'X' in the following grid are
649/// excluded from being a 3:
650///
651/// ```text
652/// ┌───┬───┬───┬───┬───┐
653/// │   │ X │   │ X │   │
654/// ├───┼───┼───┼───┼───┤
655/// │ X │   │   │   │ X │
656/// ├───┼───┼───┼───┼───┤
657/// │   │   │ 3 │   │   │
658/// ├───┼───┼───┼───┼───┤
659/// │ X │   │   │   │ X │
660/// ├───┼───┼───┼───┼───┤
661/// │   │ X │   │ X │   │
662/// └───┴───┴───┴───┴───┘
663/// ```
664#[derive(Clone)]
665pub struct KnightsMoveConstraint;
666
667const KNIGHTS_MOVES: [(isize, isize); 8] = [
668    (-1, -2),
669    (1, -2),
670    (-2, -1),
671    (2, -1),
672    (-2, 1),
673    (2, 1),
674    (-1, 2),
675    (1, 2)
676];
677
678impl RelativeCellConstraint for KnightsMoveConstraint {
679    const RELATIVE_COORDINATES: &'static [(isize, isize)] = &KNIGHTS_MOVES;
680}
681
682/// A [RelativeCellConstraint] that excludes duplicates a Chess-Kings's move
683/// away from the reference cell (orthogonally or diagonally adjacent). Note
684/// that some checks performed by this constraint are redundant if standard
685/// Sudoku rules apply, since orthogonally adjacent cells are either in the
686/// same row or column as the reference cell. In that case, using the
687/// [DiagonallyAdjacentConstraint] is more efficient and has the same effect.
688#[derive(Clone)]
689pub struct KingsMoveConstraint;
690
691const KINGS_MOVES: [(isize, isize); 8] = [
692    (-1, -1),
693    (0, -1),
694    (1, -1),
695    (-1, 0),
696    (1, 0),
697    (-1, 1),
698    (0, 1),
699    (1, 1)
700];
701
702impl RelativeCellConstraint for KingsMoveConstraint {
703    const RELATIVE_COORDINATES: &'static [(isize, isize)] = &KINGS_MOVES;
704}
705
706/// A [RelativeCellConstraint] that excludes duplicates in a diagonally
707/// adjacent cell to the reference cell. If normal Sudoku rules apply, this is
708/// equivalent to a [KingsMoveConstraint].
709///
710/// As a visualization, the cells marked with 'X' in the following grid are
711/// excluded from being a 3:
712///
713/// ```text
714/// ┌───┬───┬───┐
715/// │ X │   │ X │
716/// ├───┼───┼───┤
717/// │   │ 3 │   │
718/// ├───┼───┼───┤
719/// │ X │   │ X │
720/// └───┴───┴───┘
721/// ```
722#[derive(Clone)]
723pub struct DiagonallyAdjacentConstraint;
724
725const DIAGONALLY_ADJACENT: [(isize, isize); 4] = [
726    (-1, -1),
727    (1, -1),
728    (-1, 1),
729    (1, 1)
730];
731
732impl RelativeCellConstraint for DiagonallyAdjacentConstraint {
733    const RELATIVE_COORDINATES: &'static [(isize, isize)] =
734        &DIAGONALLY_ADJACENT;
735}
736
737/// A [RelativeCellConstraint] that excludes consecutive digits in orthogonally
738/// adjacent cells. As a visualization, the cells marked with 'X' in the
739/// following grid are excluded from being a 2 or a 4:
740///
741/// ```text
742/// ┌───┬───┬───┐
743/// │   │ X │   │
744/// ├───┼───┼───┤
745/// │ X │ 3 │ X │
746/// ├───┼───┼───┤
747/// │   │ X │   │
748/// └───┴───┴───┘
749/// ```
750#[derive(Clone)]
751pub struct AdjacentConsecutiveConstraint;
752
753const ORTHOGONALLY_ADJACENT: [(isize, isize); 4] = [
754    (-1, 0),
755    (1, 0),
756    (0, -1),
757    (0, 1)
758];
759
760impl RelativeCellConstraint for AdjacentConsecutiveConstraint {
761    const RELATIVE_COORDINATES: &'static [(isize, isize)] =
762        &ORTHOGONALLY_ADJACENT;
763
764    fn is_forbidden(&self, reference_cell: usize, other_cell: usize) -> bool {
765        reference_cell + 1 == other_cell || reference_cell == other_cell + 1
766    }
767}
768
769/// A [Constraint] which simultaneously enforces two other constraints. This
770/// allows the construction of complex constraints by nesting composite
771/// constraints.
772///
773/// As an example, a constraint with [DefaultConstraint],
774/// [DiagonalsConstraint], and [KnightsMoveConstraint] would be constructed
775/// as follows:
776///
777/// ```
778/// use sudoku_variants::constraint::{
779///     CompositeConstraint,
780///     DefaultConstraint,
781///     DiagonalsConstraint,
782///     KnightsMoveConstraint
783/// };
784///
785/// let constraint = CompositeConstraint::new(
786///     DefaultConstraint,
787///     CompositeConstraint::new(
788///         DiagonalsConstraint,
789///         KnightsMoveConstraint
790///     )
791/// );
792/// ```
793///
794/// The advantage of using this over a [DynamicConstraint] is that it is
795/// statically known which types of constraints are used, so no dynamic
796/// dispatch is necessary. On the contrary, a `CompositeConstraint` is less
797/// flexible.
798#[derive(Clone)]
799pub struct CompositeConstraint<C1, C2>
800where
801    C1: Constraint + Clone + 'static,
802    C2: Constraint + Clone + 'static
803{
804    c1: C1,
805    c2: C2
806}
807
808impl<C1, C2> CompositeConstraint<C1, C2>
809where
810    C1: Constraint + Clone + 'static,
811    C2: Constraint + Clone + 'static
812{
813    /// Creates a new composite constraint from the two child consraints which
814    /// will be enforced.
815    pub fn new(c1: C1, c2: C2) -> CompositeConstraint<C1, C2> {
816        CompositeConstraint {
817            c1,
818            c2
819        }
820    }
821}
822
823impl<C1, C2> Constraint for CompositeConstraint<C1, C2>
824where
825    C1: Constraint + Clone + 'static,
826    C2: Constraint + Clone + 'static
827{
828    fn check(&self, grid: &SudokuGrid) -> bool {
829        self.c1.check(grid) && self.c2.check(grid)
830    }
831
832    fn check_cell(&self, grid: &SudokuGrid, column: usize, row: usize)
833            -> bool {
834        self.c1.check_cell(grid, column, row) &&
835            self.c2.check_cell(grid, column, row)
836    }
837
838    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
839            number: usize) -> bool {
840        self.c1.check_number(grid, column, row, number) &&
841            self.c2.check_number(grid, column, row, number)
842    }
843
844    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
845        let mut groups = self.c1.get_groups(grid);
846        groups.append(&mut self.c2.get_groups(grid));
847        groups
848    }
849}
850
851/// A trait for cloneable [Constraint]s which is used in the
852/// [DynamicConstraint] to clone trait objects. Normally a user should not have
853/// to implement this trait manually, as it is automatically implemented for
854/// all `Constraint`s that implement [Clone] (and have static lifetime).
855pub trait CloneConstraint : Constraint {
856
857    /// Clones a trait object of this constraint.
858    fn clone_box(&self) -> Box<dyn CloneConstraint>;
859}
860
861impl<C: Constraint + Clone + 'static> CloneConstraint for C {
862    fn clone_box(&self) -> Box<dyn CloneConstraint> {
863        Box::new(self.clone())
864    }
865}
866
867/// A [Constraint] that contains a vector of trait objects representing
868/// constraints and verifies all of them. This is more flexible than a
869/// [CompositeConstraint], but also less efficient, since it needs dynamic
870/// dispatch.
871pub struct DynamicConstraint {
872    constraints: Vec<Box<dyn CloneConstraint>>
873}
874
875impl DynamicConstraint {
876
877    /// Creates a new dynamic constraint from the given child constraints. The
878    /// created constraint is defined to be satisfied if all children are
879    /// satisfied.
880    pub fn with_children(constraints: Vec<Box<dyn CloneConstraint>>)
881            -> DynamicConstraint {
882        DynamicConstraint {
883            constraints
884        }
885    }
886
887    /// Creates a new dynamic constraint without any child constraint. Children
888    /// can be added later using [DynamicConstraint::add].
889    pub fn new() -> DynamicConstraint {
890        DynamicConstraint {
891            constraints: Vec::new()
892        }
893    }
894
895    /// Adds a [CloneConstraint] to this dynamic constraint as a child. It is
896    /// wrapped in a trait object.
897    pub fn add(&mut self, constraint: impl CloneConstraint + 'static) {
898        self.constraints.push(Box::new(constraint))
899    }
900}
901
902impl Constraint for DynamicConstraint {
903    fn check(&self, grid: &SudokuGrid) -> bool {
904        self.constraints.iter().all(|c| c.check(grid))
905    }
906
907    fn check_cell(&self, grid: &SudokuGrid, column: usize, row: usize) -> bool {
908        self.constraints.iter().all(|c| c.check_cell(grid, column, row))
909    }
910
911    fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
912            number: usize) -> bool {
913        self.constraints.iter().all(
914            |c| c.check_number(grid, column, row, number))
915    }
916
917    fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group> {
918        self.constraints.iter()
919            .map(|c| c.get_groups(grid))
920            .flat_map(|g| g.into_iter())
921            .collect()
922    }
923}
924
925impl Clone for DynamicConstraint {
926    fn clone(&self) -> Self {
927        let constraints = self.constraints.iter()
928            .map(|c| c.clone_box())
929            .collect();
930        DynamicConstraint {
931            constraints
932        }
933    }
934}
935
936impl Default for DynamicConstraint {
937    fn default() -> DynamicConstraint {
938        DynamicConstraint::new()
939    }
940}
941
942#[cfg(test)]
943mod tests {
944
945    use super::*;
946
947    use crate::Sudoku;
948
949    #[test]
950    fn row_satisfied() {
951        let code = "2x2;\
952            1, , ,2,\
953             ,2, ,3,\
954             ,4,1, ,\
955            3, , ,2";
956        let sudoku = Sudoku::parse(code, RowConstraint).unwrap();
957        assert!(sudoku.is_valid());
958        assert!(sudoku.is_valid_cell(3, 2).unwrap());
959        assert!(sudoku.is_valid_cell(3, 3).unwrap());
960        assert!(sudoku.is_valid_number(2, 2, 3).unwrap());
961    }
962
963    #[test]
964    fn row_violated() {
965        let code = "2x2;\
966            1, , ,2,\
967             ,2, ,3,\
968             , ,1, ,\
969            4, , ,4";
970        let sudoku = Sudoku::parse(code, RowConstraint).unwrap();
971        assert!(!sudoku.is_valid());
972        assert!(!sudoku.is_valid_cell(0, 3).unwrap());
973        assert!(!sudoku.is_valid_cell(3, 3).unwrap());
974        assert!(sudoku.is_valid_cell(2, 2).unwrap());
975        assert!(!sudoku.is_valid_number(2, 0, 1).unwrap());
976        assert!(!sudoku.is_valid_number(2, 1, 3).unwrap());
977        assert!(sudoku.is_valid_number(3, 3, 1).unwrap());
978    }
979
980    #[test]
981    fn column_satisfied() {
982        let code = "2x2;\
983            1, ,3, ,\
984             ,2, ,2,\
985            3, , ,1,\
986             ,4, , ";
987        let sudoku = Sudoku::parse(code, ColumnConstraint).unwrap();
988        assert!(sudoku.is_valid());
989        assert!(sudoku.is_valid_cell(1, 1).unwrap());
990        assert!(sudoku.is_valid_cell(1, 2).unwrap());
991        assert!(sudoku.is_valid_number(3, 0, 3).unwrap());
992    }
993
994    #[test]
995    fn column_violated() {
996        let code = "2x2;\
997            1, ,3, ,\
998             ,2, ,4,\
999            1, , ,3,\
1000             ,4, , ";
1001        let sudoku = Sudoku::parse(code, ColumnConstraint).unwrap();
1002        assert!(!sudoku.is_valid());
1003        assert!(!sudoku.is_valid_cell(0, 0).unwrap());
1004        assert!(!sudoku.is_valid_cell(0, 2).unwrap());
1005        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1006        assert!(!sudoku.is_valid_number(2, 1, 3).unwrap());
1007        assert!(!sudoku.is_valid_number(1, 0, 4).unwrap());
1008        assert!(sudoku.is_valid_number(3, 3, 1).unwrap());
1009    }
1010
1011    #[test]
1012    fn block_satisfied() {
1013        let code = "2x2;\
1014            1,2, , ,\
1015             ,3, ,3,\
1016             ,2,4, ,\
1017            3, , ,1";
1018        let sudoku = Sudoku::parse(code, BlockConstraint).unwrap();
1019        assert!(sudoku.is_valid());
1020        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1021        assert!(sudoku.is_valid_cell(3, 2).unwrap());
1022        assert!(sudoku.is_valid_number(3, 2, 2).unwrap());
1023    }
1024
1025    #[test]
1026    fn block_violated() {
1027        let code = "2x2;\
1028            1, , ,3,\
1029             ,3, , ,\
1030             ,2,4, ,\
1031            2, , ,1";
1032        let sudoku = Sudoku::parse(code, BlockConstraint).unwrap();
1033        assert!(!sudoku.is_valid());
1034        assert!(!sudoku.is_valid_cell(0, 3).unwrap());
1035        assert!(!sudoku.is_valid_cell(1, 2).unwrap());
1036        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1037        assert!(!sudoku.is_valid_number(2, 0, 3).unwrap());
1038        assert!(!sudoku.is_valid_number(3, 3, 4).unwrap());
1039        assert!(sudoku.is_valid_number(2, 1, 4).unwrap());
1040    }
1041
1042    #[test]
1043    fn diagonals_satisfied() {
1044        let code = "2x2;\
1045            2,3,4,1,\
1046             , , , ,\
1047             , ,4, ,\
1048            3, , ,3";
1049        let sudoku = Sudoku::parse(code, DiagonalsConstraint).unwrap();
1050        assert!(sudoku.is_valid());
1051        assert!(sudoku.is_valid_cell(2, 2).unwrap());
1052        assert!(sudoku.is_valid_cell(3, 0).unwrap());
1053        assert!(sudoku.is_valid_cell(2, 0).unwrap());
1054        assert!(sudoku.is_valid_number(1, 1, 1).unwrap());
1055    }
1056
1057    #[test]
1058    fn diagonals_violated() {
1059        let code = "2x2;\
1060            2,3,4,1,\
1061             , , , ,\
1062             , ,2, ,\
1063            3, , ,4";
1064        let sudoku = Sudoku::parse(code, DiagonalsConstraint).unwrap();
1065        assert!(!sudoku.is_valid());
1066        assert!(!sudoku.is_valid_cell(0, 0).unwrap());
1067        assert!(!sudoku.is_valid_cell(2, 2).unwrap());
1068        assert!(sudoku.is_valid_cell(0, 3).unwrap());
1069        assert!(sudoku.is_valid_cell(2, 0).unwrap());
1070        assert!(!sudoku.is_valid_number(1, 2, 1).unwrap());
1071        assert!(!sudoku.is_valid_number(1, 1, 4).unwrap());
1072        assert!(sudoku.is_valid_number(2, 2, 3).unwrap());
1073        assert!(sudoku.is_valid_number(1, 1, 3).unwrap());
1074    }
1075
1076    #[test]
1077    fn knights_move_satisfied() {
1078        let code = "2x2;\
1079            1, ,3, ,\
1080             ,2, ,3,\
1081             ,4, ,1,\
1082            1,4,1,2";
1083        let sudoku = Sudoku::parse(code, KnightsMoveConstraint).unwrap();
1084        assert!(sudoku.is_valid());
1085        assert!(sudoku.is_valid_cell(3, 2).unwrap());
1086        assert!(sudoku.is_valid_cell(0, 2).unwrap());
1087        assert!(sudoku.is_valid_number(2, 1, 3).unwrap());
1088    }
1089
1090    #[test]
1091    fn knights_move_violated() {
1092        let code = "2x2;\
1093            1, ,3, ,\
1094             ,2, ,4,\
1095             ,4, ,1,\
1096            3, ,2, ";
1097        let sudoku = Sudoku::parse(code, KnightsMoveConstraint).unwrap();
1098        assert!(!sudoku.is_valid());
1099        assert!(!sudoku.is_valid_cell(1, 1).unwrap());
1100        assert!(!sudoku.is_valid_cell(2, 3).unwrap());
1101        assert!(!sudoku.is_valid_cell(3, 1).unwrap());
1102        assert!(!sudoku.is_valid_cell(1, 2).unwrap());
1103        assert!(sudoku.is_valid_cell(2, 0).unwrap());
1104        assert!(sudoku.is_valid_cell(2, 1).unwrap());
1105        assert!(!sudoku.is_valid_number(2, 2, 3).unwrap());
1106        assert!(sudoku.is_valid_number(1, 1, 4).unwrap());
1107    }
1108
1109    #[test]
1110    fn kings_move_satisfied() {
1111        let code = "2x2;\
1112            2,3, , ,\
1113             ,4,2,1,\
1114             ,1, ,4,\
1115             ,2, ,2";
1116        let sudoku = Sudoku::parse(code, KingsMoveConstraint).unwrap();
1117        assert!(sudoku.is_valid());
1118        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1119        assert!(sudoku.is_valid_cell(1, 3).unwrap());
1120        assert!(sudoku.is_valid_number(2, 2, 3).unwrap());
1121    }
1122
1123    #[test]
1124    fn kings_move_violated() {
1125        let code = "2x2;\
1126            1,3, , ,\
1127             ,2,2,1,\
1128             ,1, ,4,\
1129             , ,1,3";
1130        let sudoku = Sudoku::parse(code, KingsMoveConstraint).unwrap();
1131        assert!(!sudoku.is_valid());
1132        assert!(!sudoku.is_valid_cell(1, 1).unwrap());
1133        assert!(!sudoku.is_valid_cell(2, 1).unwrap());
1134        assert!(!sudoku.is_valid_cell(1, 2).unwrap());
1135        assert!(!sudoku.is_valid_cell(2, 3).unwrap());
1136        assert!(sudoku.is_valid_cell(3, 2).unwrap());
1137        assert!(sudoku.is_valid_cell(2, 2).unwrap());
1138        assert!(!sudoku.is_valid_number(2, 2, 3).unwrap());
1139        assert!(!sudoku.is_valid_number(2, 2, 4).unwrap());
1140        assert!(sudoku.is_valid_number(2, 0, 4).unwrap());
1141    }
1142
1143    #[test]
1144    fn diagonally_adjacent_satisfied() {
1145        let code = "2x2;\
1146            1,3, , ,\
1147             ,3,2, ,\
1148            2,1,1, ,\
1149            4, , , ";
1150        let sudoku =
1151            Sudoku::parse(code, DiagonallyAdjacentConstraint).unwrap();
1152        assert!(sudoku.is_valid());
1153        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1154        assert!(sudoku.is_valid_cell(2, 2).unwrap());
1155        assert!(sudoku.is_valid_number(1, 2, 3).unwrap());
1156    }
1157
1158    #[test]
1159    fn diagonally_adjacent_violated() {
1160        let code = "2x2;\
1161            1,2, , ,\
1162             ,3,2, ,\
1163             ,2, ,4,\
1164            4, ,1, ";
1165        let sudoku =
1166            Sudoku::parse(code, DiagonallyAdjacentConstraint).unwrap();
1167        assert!(!sudoku.is_valid());
1168        assert!(!sudoku.is_valid_cell(1, 0).unwrap());
1169        assert!(!sudoku.is_valid_cell(2, 1).unwrap());
1170        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1171        assert!(!sudoku.is_valid_number(2, 1, 4).unwrap());
1172        assert!(!sudoku.is_valid_number(3, 0, 2).unwrap());
1173        assert!(sudoku.is_valid_number(1, 2, 3).unwrap());
1174    }
1175
1176    #[test]
1177    fn adjacent_consecutive_satisfied() {
1178        let code = "2x2;\
1179            4,2,4,1,\
1180             ,4, ,3,\
1181             ,1,3, ,\
1182            2, ,1, ";
1183        let sudoku =
1184            Sudoku::parse(code, AdjacentConsecutiveConstraint).unwrap();
1185        assert!(sudoku.is_valid());
1186        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1187        assert!(sudoku.is_valid_cell(2, 2).unwrap());
1188        assert!(sudoku.is_valid_number(2, 1, 1).unwrap());
1189    }
1190
1191    #[test]
1192    fn adjacent_consecutive_violated() {
1193        let code = "2x2;\
1194            4,2, ,1,\
1195             ,3, ,4,\
1196             ,1,3,2,\
1197            2, , , ";
1198        let sudoku =
1199            Sudoku::parse(code, AdjacentConsecutiveConstraint).unwrap();
1200        assert!(!sudoku.is_valid());
1201        assert!(!sudoku.is_valid_cell(1, 0).unwrap());
1202        assert!(!sudoku.is_valid_cell(1, 1).unwrap());
1203        assert!(!sudoku.is_valid_cell(2, 2).unwrap());
1204        assert!(!sudoku.is_valid_cell(3, 2).unwrap());
1205        assert!(sudoku.is_valid_cell(1, 2).unwrap());
1206        assert!(!sudoku.is_valid_number(2, 1, 2).unwrap());
1207        assert!(sudoku.is_valid_number(1, 0, 1).unwrap());
1208    }
1209
1210    fn test_column_row_satisfied(constraint: impl Constraint + Clone) {
1211        let code = "2x2;\
1212            2,4, ,1,\
1213            1,3,2, ,\
1214             ,1, ,3,\
1215            4, ,3, ";
1216        let sudoku = Sudoku::parse(code, constraint).unwrap();
1217        assert!(sudoku.is_valid());
1218        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1219        assert!(sudoku.is_valid_number(2, 2, 4).unwrap());
1220    }
1221
1222    fn test_column_row_violated(constraint: impl Constraint + Clone) {
1223        let code1 = "2x2;\
1224            2,4, ,4,\
1225            1,3,2, ,\
1226             ,1, ,3,\
1227            4, ,3, ";
1228        let sudoku = Sudoku::parse(code1, constraint).unwrap();
1229        assert!(!sudoku.is_valid());
1230        assert!(!sudoku.is_valid_cell(1, 0).unwrap());
1231        assert!(!sudoku.is_valid_cell(3, 0).unwrap());
1232        assert!(sudoku.is_valid_cell(1, 1).unwrap());
1233        assert!(!sudoku.is_valid_number(2, 2, 1).unwrap());
1234        assert!(sudoku.is_valid_number(2, 0, 1).unwrap());
1235    }
1236
1237    #[test]
1238    fn composite_satisfied() {
1239        test_column_row_satisfied(CompositeConstraint::new(
1240            RowConstraint, ColumnConstraint));
1241    }
1242
1243    #[test]
1244    fn composite_violated() {
1245        test_column_row_violated(CompositeConstraint::new(
1246            RowConstraint, ColumnConstraint));
1247    }
1248
1249    #[test]
1250    fn dynamic_satisfied() {
1251        test_column_row_satisfied(DynamicConstraint::with_children(vec![
1252            Box::new(RowConstraint),
1253            Box::new(ColumnConstraint)
1254        ]));
1255    }
1256
1257    #[test]
1258    fn dynamic_violated() {
1259        test_column_row_violated(DynamicConstraint::with_children(vec![
1260            Box::new(RowConstraint),
1261            Box::new(ColumnConstraint)
1262        ]));
1263    }
1264}