//! Kakuro. //! //! https://en.wikipedia.org/wiki/Kakuro extern crate puzzle_solver; use puzzle_solver::{LinExpr, Puzzle, Solution, Val, VarToken}; const SIZE: usize = 7; const X: Val = 0; type Board = [[Val; SIZE]; SIZE]; type KakuroVars = Vec>>; enum Rule { H { total: Val, y: usize, x1: usize, x2: usize, }, V { total: Val, x: usize, y1: usize, y2: usize, }, } fn make_kakuro(board: &[Rule]) -> (Puzzle, KakuroVars) { let mut sys = Puzzle::new(); let mut vars = vec![vec![None; SIZE]; SIZE]; for rule in board.iter() { let (total, x1, y1, x2, y2) = match rule { &Rule::H { total, y, x1, x2 } => (total, x1, y, x2, y), &Rule::V { total, x, y1, y2 } => (total, x, y1, x, y2), }; let mut vec = Vec::new(); for y in y1..(y2 + 1) { for x in x1..(x2 + 1) { let var = vars[y][x].unwrap_or_else(|| { let var = sys.new_var(&[1, 2, 3, 4, 5, 6, 7, 8, 9]); vars[y][x] = Some(var); var }); vec.push(var); } } sys.all_different(&vec); sys.equals( total, vec.iter().fold(LinExpr::from(0), |sum, &var| sum + var), ); } (sys, vars) } fn print_kakuro(dict: &Solution, vars: &KakuroVars) { for y in 0..SIZE { for x in 0..SIZE { if let Some(var) = vars[y][x] { print!(" {}", dict[var]); } else { print!(" ."); } } println!(); } } fn verify_kakuro(dict: &Solution, vars: &KakuroVars, expected: &Board) { for y in 0..SIZE { for x in 0..SIZE { let val = vars[y][x].map_or(X, |var| dict[var]); assert_eq!(val, expected[y][x]); } } } #[test] fn kakuro_wikipedia() { let puzzle = [ Rule::H { total: 16, y: 0, x1: 0, x2: 1, }, Rule::H { total: 24, y: 0, x1: 4, x2: 6, }, Rule::H { total: 17, y: 1, x1: 0, x2: 1, }, Rule::H { total: 29, y: 1, x1: 3, x2: 6, }, Rule::H { total: 35, y: 2, x1: 0, x2: 4, }, Rule::H { total: 7, y: 3, x1: 1, x2: 2, }, Rule::H { total: 8, y: 3, x1: 4, x2: 5, }, Rule::H { total: 16, y: 4, x1: 2, x2: 6, }, Rule::H { total: 21, y: 5, x1: 0, x2: 3, }, Rule::H { total: 5, y: 5, x1: 5, x2: 6, }, Rule::H { total: 6, y: 6, x1: 0, x2: 2, }, Rule::H { total: 3, y: 6, x1: 5, x2: 6, }, Rule::V { total: 23, x: 0, y1: 0, y2: 2, }, Rule::V { total: 11, x: 0, y1: 5, y2: 6, }, Rule::V { total: 30, x: 1, y1: 0, y2: 3, }, Rule::V { total: 10, x: 1, y1: 5, y2: 6, }, Rule::V { total: 15, x: 2, y1: 2, y2: 6, }, Rule::V { total: 17, x: 3, y1: 1, y2: 2, }, Rule::V { total: 7, x: 3, y1: 4, y2: 5, }, Rule::V { total: 27, x: 4, y1: 0, y2: 4, }, Rule::V { total: 12, x: 5, y1: 0, y2: 1, }, Rule::V { total: 12, x: 5, y1: 3, y2: 6, }, Rule::V { total: 16, x: 6, y1: 0, y2: 1, }, Rule::V { total: 7, x: 6, y1: 4, y2: 6, }, ]; let expected = [ [9, 7, X, X, 8, 7, 9], [8, 9, X, 8, 9, 5, 7], [6, 8, 5, 9, 7, X, X], [X, 6, 1, X, 2, 6, X], [X, X, 4, 6, 1, 3, 2], [8, 9, 3, 1, X, 1, 4], [3, 1, 2, X, X, 2, 1], ]; let (mut sys, vars) = make_kakuro(&puzzle); let dict = sys.solve_any().expect("solution"); print_kakuro(&dict, &vars); verify_kakuro(&dict, &vars, &expected); println!("kakuro_wikipedia: {} guesses", sys.num_guesses()); }