From 34e58114ead933c7de67d381432756ac945bd719 Mon Sep 17 00:00:00 2001 From: David Wang Date: Fri, 24 Feb 2017 07:21:09 +1100 Subject: [PATCH] Add test: Sudoku. sudoku_hardest: 1850 guesses. sudoku_wikipedia: no guesswork! --- tests/sudoku.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 tests/sudoku.rs diff --git a/tests/sudoku.rs b/tests/sudoku.rs new file mode 100644 index 0000000..b2b59d7 --- /dev/null +++ b/tests/sudoku.rs @@ -0,0 +1,135 @@ +//! Sudoku. +//! +//! https://en.wikipedia.org/wiki/Sudoku + +extern crate puzzle_solver; + +use puzzle_solver::{Puzzle,Solution,Val,VarToken}; + +const SQRT_SIZE: usize = 3; +const SIZE: usize = 9; +type Board = [[Val; SIZE]; SIZE]; + +fn make_sudoku(board: &Board) -> (Puzzle, Vec>) { + let mut sys = Puzzle::new(); + let vars = sys.new_vars_with_candidates_2d(SIZE, SIZE, &[1,2,3,4,5,6,7,8,9]); + + for y in 0..SIZE { + sys.all_different(&vars[y]); + } + + for x in 0..SIZE { + sys.all_different(vars.iter().map(|row| &row[x])); + } + + for block in 0..SIZE { + let x0 = SQRT_SIZE * (block % SQRT_SIZE); + let y0 = SQRT_SIZE * (block / SQRT_SIZE); + sys.all_different((0..SIZE).map(|n| + &vars[y0 + (n / SQRT_SIZE)][x0 + (n % SQRT_SIZE)])); + } + + for y in 0..SIZE { + for x in 0..SIZE { + let value = board[y][x]; + if value != 0 { + sys.set_value(vars[y][x], value); + } + } + } + + (sys, vars) +} + +fn print_sudoku(dict: &Solution, vars: &Vec>) { + for y in 0..SIZE { + if y % SQRT_SIZE == 0 { + println!(); + } + + for x in 0..SIZE { + print!("{}{}", + if x % SQRT_SIZE == 0 { " " } else { "" }, + dict[vars[y][x]]); + } + println!(); + } +} + +fn verify_sudoku(dict: &Solution, vars: &Vec>, expected: &Board) { + for y in 0..SIZE { + for x in 0..SIZE { + assert_eq!(dict[vars[y][x]], expected[y][x]); + } + } +} + +#[test] +fn sudoku_hardest() { + let puzzle = [ + [ 8,0,0, 0,0,0, 0,0,0 ], + [ 0,0,3, 6,0,0, 0,0,0 ], + [ 0,7,0, 0,9,0, 2,0,0 ], + + [ 0,5,0, 0,0,7, 0,0,0 ], + [ 0,0,0, 0,4,5, 7,0,0 ], + [ 0,0,0, 1,0,0, 0,3,0 ], + + [ 0,0,1, 0,0,0, 0,6,8 ], + [ 0,0,8, 5,0,0, 0,1,0 ], + [ 0,9,0, 0,0,0, 4,0,0 ] ]; + + let expected = [ + [ 8,1,2, 7,5,3, 6,4,9 ], + [ 9,4,3, 6,8,2, 1,7,5 ], + [ 6,7,5, 4,9,1, 2,8,3 ], + + [ 1,5,4, 2,3,7, 8,9,6 ], + [ 3,6,9, 8,4,5, 7,2,1 ], + [ 2,8,7, 1,6,9, 5,3,4 ], + + [ 5,2,1, 9,7,4, 3,6,8 ], + [ 4,3,8, 5,2,6, 9,1,7 ], + [ 7,9,6, 3,1,8, 4,5,2 ] ]; + + let (mut sys, vars) = make_sudoku(&puzzle); + let solution = sys.solve_any().expect("solution"); + print_sudoku(&solution, &vars); + verify_sudoku(&solution, &vars, &expected); + println!("sudoku_hardest: {} guesses", sys.num_guesses()); +} + +#[test] +fn sudoku_wikipedia() { + let puzzle = [ + [ 5,3,0, 0,7,0, 0,0,0 ], + [ 6,0,0, 1,9,5, 0,0,0 ], + [ 0,9,8, 0,0,0, 0,6,0 ], + + [ 8,0,0, 0,6,0, 0,0,3 ], + [ 4,0,0, 8,0,3, 0,0,1 ], + [ 7,0,0, 0,2,0, 0,0,6 ], + + [ 0,6,0, 0,0,0, 2,8,0 ], + [ 0,0,0, 4,1,9, 0,0,5 ], + [ 0,0,0, 0,8,0, 0,7,9 ] ]; + + let expected = [ + [ 5,3,4, 6,7,8, 9,1,2 ], + [ 6,7,2, 1,9,5, 3,4,8 ], + [ 1,9,8, 3,4,2, 5,6,7 ], + + [ 8,5,9, 7,6,1, 4,2,3 ], + [ 4,2,6, 8,5,3, 7,9,1 ], + [ 7,1,3, 9,2,4, 8,5,6 ], + + [ 9,6,1, 5,3,7, 2,8,4 ], + [ 2,8,7, 4,1,9, 6,3,5 ], + [ 3,4,5, 2,8,6, 1,7,9 ] ]; + + let (mut sys, vars) = make_sudoku(&puzzle); + let solution = sys.solve_any().expect("solution"); + print_sudoku(&solution, &vars); + verify_sudoku(&solution, &vars, &expected); + println!("sudoku_wikipedia: {} guesses", sys.num_guesses()); +}