puzzle-solver 0.4.1

Solve logic puzzles by describing their constraints. Suitable for puzzles such as Sudoku and Kakuro.
Documentation
//! 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 = 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: &Vec<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: &Vec<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());
}