120 lines
3.0 KiB
Rust
120 lines
3.0 KiB
Rust
//! Hidato.
|
|
//!
|
|
//! https://en.wikipedia.org/wiki/Hidato
|
|
|
|
extern crate puzzle_solver;
|
|
|
|
use puzzle_solver::{Puzzle, Solution, Val, VarToken};
|
|
|
|
const WIDTH: usize = 8;
|
|
const HEIGHT: usize = 8;
|
|
const NA: i32 = -1;
|
|
type Board = [[i32; WIDTH]; HEIGHT];
|
|
|
|
fn make_hidato(board: &Board) -> (Puzzle, Vec<VarToken>) {
|
|
let mut sys = Puzzle::new();
|
|
let mut pos = Vec::new();
|
|
let mut count = 0;
|
|
|
|
for y in 0..HEIGHT {
|
|
for x in 0..WIDTH {
|
|
if board[y][x] != NA {
|
|
pos.push((WIDTH * y + x) as Val);
|
|
count += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
let vars = sys.new_vars_with_candidates_1d(count, &pos);
|
|
|
|
for y in 0..HEIGHT {
|
|
for x in 0..WIDTH {
|
|
if board[y][x] > 0 {
|
|
let idx = (board[y][x] - 1) as usize;
|
|
sys.set_value(vars[idx], (WIDTH * y + x) as Val);
|
|
}
|
|
}
|
|
}
|
|
|
|
sys.all_different(&vars);
|
|
|
|
let stride = WIDTH as Val;
|
|
let deltas = [
|
|
-stride - 1,
|
|
-stride,
|
|
-stride + 1,
|
|
-1,
|
|
1,
|
|
stride - 1,
|
|
stride,
|
|
stride + 1,
|
|
];
|
|
|
|
for i in 1..vars.len() {
|
|
let step = sys.new_var_with_candidates(&deltas);
|
|
sys.equals(vars[i], vars[i - 1] + step);
|
|
}
|
|
|
|
(sys, vars)
|
|
}
|
|
|
|
fn print_hidato(dict: &Solution, vars: &[VarToken]) {
|
|
let mut board = [[NA; WIDTH]; HEIGHT];
|
|
|
|
for (idx, &var) in vars.iter().enumerate() {
|
|
let x = (dict[var] as usize) % WIDTH;
|
|
let y = (dict[var] as usize) / WIDTH;
|
|
board[y][x] = (idx as i32) + 1;
|
|
}
|
|
|
|
for y in 0..HEIGHT {
|
|
for x in 0..WIDTH {
|
|
if board[y][x] == NA {
|
|
print!(" --");
|
|
} else {
|
|
print!(" {:2}", board[y][x]);
|
|
}
|
|
}
|
|
println!();
|
|
}
|
|
}
|
|
|
|
fn verify_hidato(dict: &Solution, vars: &[VarToken], expected: &Board) {
|
|
for (idx, &var) in vars.iter().enumerate() {
|
|
let x = (dict[var] as usize) % WIDTH;
|
|
let y = (dict[var] as usize) / WIDTH;
|
|
assert_eq!((idx as i32) + 1, expected[y][x]);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn hidato_wikipedia() {
|
|
let puzzle = [
|
|
[0, 33, 35, 0, 0, NA, NA, NA],
|
|
[0, 0, 24, 22, 0, NA, NA, NA],
|
|
[0, 0, 0, 21, 0, 0, NA, NA],
|
|
[0, 26, 0, 13, 40, 11, NA, NA],
|
|
[27, 0, 0, 0, 9, 0, 1, NA],
|
|
[NA, NA, 0, 0, 18, 0, 0, NA],
|
|
[NA, NA, NA, NA, 0, 7, 0, 0],
|
|
[NA, NA, NA, NA, NA, NA, 5, 0],
|
|
];
|
|
|
|
let expected = [
|
|
[32, 33, 35, 36, 37, NA, NA, NA],
|
|
[31, 34, 24, 22, 38, NA, NA, NA],
|
|
[30, 25, 23, 21, 12, 39, NA, NA],
|
|
[29, 26, 20, 13, 40, 11, NA, NA],
|
|
[27, 28, 14, 19, 9, 10, 1, NA],
|
|
[NA, NA, 15, 16, 18, 8, 2, NA],
|
|
[NA, NA, NA, NA, 17, 7, 6, 3],
|
|
[NA, NA, NA, NA, NA, NA, 5, 4],
|
|
];
|
|
|
|
let (mut sys, vars) = make_hidato(&puzzle);
|
|
let dict = sys.solve_any().expect("solution");
|
|
print_hidato(&dict, &vars);
|
|
verify_hidato(&dict, &vars, &expected);
|
|
println!("hidato_wikipedia: {} guesses", sys.num_guesses());
|
|
}
|