1use crate::SudokuGrid;
121use crate::util::USizeSet;
122
123use std::iter::Cloned;
124use std::slice::Iter;
125
126pub type Group = Vec<(usize, usize)>;
129
130pub trait Constraint {
149
150 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 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 fn check_number(&self, grid: &SudokuGrid, column: usize, row: usize,
197 number: usize) -> bool;
198
199 fn get_groups(&self, grid: &SudokuGrid) -> Vec<Group>;
213}
214
215#[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#[derive(Clone)]
273pub struct ColumnConstraint;
274
275impl Constraint for ColumnConstraint {
276
277 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#[derive(Clone)]
380pub struct BlockConstraint;
381
382impl Constraint for BlockConstraint {
383
384 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#[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#[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#[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 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 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
580pub trait RelativeCellConstraint {
591
592 const RELATIVE_COORDINATES: &'static [(isize, isize)];
595
596 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#[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#[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#[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#[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#[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 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
851pub trait CloneConstraint : Constraint {
856
857 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
867pub struct DynamicConstraint {
872 constraints: Vec<Box<dyn CloneConstraint>>
873}
874
875impl DynamicConstraint {
876
877 pub fn with_children(constraints: Vec<Box<dyn CloneConstraint>>)
881 -> DynamicConstraint {
882 DynamicConstraint {
883 constraints
884 }
885 }
886
887 pub fn new() -> DynamicConstraint {
890 DynamicConstraint {
891 constraints: Vec::new()
892 }
893 }
894
895 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}