Add test: Killer Sudoku.
killersudoku_wikipedia: 7 guesses.
This commit is contained in:
parent
c93b9430c1
commit
23ae2331bf
115
tests/killersudoku.rs
Normal file
115
tests/killersudoku.rs
Normal file
@ -0,0 +1,115 @@
|
||||
//! Killer Sudoku.
|
||||
//!
|
||||
//! https://en.wikipedia.org/wiki/Killer_sudoku
|
||||
|
||||
extern crate puzzle_solver;
|
||||
|
||||
use puzzle_solver::{LinExpr,Puzzle,Solution,Val,VarToken};
|
||||
|
||||
const SQRT_SIZE: usize = 3;
|
||||
const SIZE: usize = 9;
|
||||
type Board = [[Val; SIZE]; SIZE];
|
||||
type Point = (usize, usize);
|
||||
|
||||
fn make_killer_sudoku(board: &[(Val, Vec<Point>)]) -> (Puzzle, Vec<Vec<VarToken>>) {
|
||||
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 &(total, ref points) in board.iter() {
|
||||
sys.equals(total, points.iter().fold(LinExpr::from(0), |sum, &(x,y)| sum + vars[y][x]));
|
||||
}
|
||||
|
||||
(sys, vars)
|
||||
}
|
||||
|
||||
fn print_sudoku(dict: &Solution, vars: &Vec<Vec<VarToken>>) {
|
||||
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<Vec<VarToken>>, expected: &Board) {
|
||||
for y in 0..SIZE {
|
||||
for x in 0..SIZE {
|
||||
assert_eq!(dict[vars[y][x]], expected[y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn killersudoku_wikipedia() {
|
||||
let puzzle = [
|
||||
( 3, vec![(0,0), (1,0)]),
|
||||
(15, vec![(2,0), (3,0), (4,0)]),
|
||||
(22, vec![(5,0), (4,1), (5,1), (4,2)]),
|
||||
( 4, vec![(6,0), (6,1)]),
|
||||
(16, vec![(7,0), (7,1)]),
|
||||
(15, vec![(8,0), (8,1), (8,2), (8,3)]),
|
||||
(25, vec![(0,1), (1,1), (0,2), (1,2)]),
|
||||
(17, vec![(2,1), (3,1)]),
|
||||
( 9, vec![(2,2), (3,2), (3,3)]),
|
||||
( 8, vec![(5,2), (5,3), (5,4)]),
|
||||
(20, vec![(6,2), (7,2), (6,3)]),
|
||||
( 6, vec![(0,3), (0,4)]),
|
||||
(14, vec![(1,3), (2,3)]),
|
||||
(17, vec![(4,3), (4,4), (4,5)]),
|
||||
(17, vec![(7,3), (6,4), (7,4)]),
|
||||
(13, vec![(1,4), (2,4), (1,5)]),
|
||||
(20, vec![(3,4), (3,5), (3,6)]),
|
||||
(12, vec![(8,4), (8,5)]),
|
||||
(27, vec![(0,5), (0,6), (0,7), (0,8)]),
|
||||
( 6, vec![(2,5), (1,6), (2,6)]),
|
||||
(20, vec![(5,5), (5,6), (6,6)]),
|
||||
( 6, vec![(6,5), (7,5)]),
|
||||
(10, vec![(4,6), (3,7), (4,7), (3,8)]),
|
||||
(14, vec![(7,6), (8,6), (7,7), (8,7)]),
|
||||
( 8, vec![(1,7), (1,8)]),
|
||||
(16, vec![(2,7), (2,8)]),
|
||||
(15, vec![(5,7), (6,7)]),
|
||||
(13, vec![(4,8), (5,8), (6,8)]),
|
||||
(17, vec![(7,8), (8,8)]),
|
||||
];
|
||||
|
||||
let expected = [
|
||||
[ 2,1,5, 6,4,7, 3,9,8 ],
|
||||
[ 3,6,8, 9,5,2, 1,7,4 ],
|
||||
[ 7,9,4, 3,8,1, 6,5,2 ],
|
||||
|
||||
[ 5,8,6, 2,7,4, 9,3,1 ],
|
||||
[ 1,4,2, 5,9,3, 8,6,7 ],
|
||||
[ 9,7,3, 8,1,6, 4,2,5 ],
|
||||
|
||||
[ 8,2,1, 7,3,9, 5,4,6 ],
|
||||
[ 6,5,9, 4,2,8, 7,1,3 ],
|
||||
[ 4,3,7, 1,6,5, 2,8,9 ] ];
|
||||
|
||||
let (mut sys, vars) = make_killer_sudoku(&puzzle);
|
||||
let dict = sys.solve_any().expect("solution");
|
||||
print_sudoku(&dict, &vars);
|
||||
verify_sudoku(&dict, &vars, &expected);
|
||||
println!("killersudoku_wikipedia: {} guesses", sys.num_guesses());
|
||||
}
|
Loading…
Reference in New Issue
Block a user