miracle_sudoku = {
const _ = 0,
board_clauses = [];
const sudoku = parse_sudoku(`
_ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _
_ _ 1 _ _ _ _ _ _
_ _ _ _ _ _ 2 _ _
_ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _
`);
for (let i = 0; i < 9; i++)
for (let j = 0; j < 9; j++) {
if (sudoku[i * 9 + j] !== 0)
board_clauses.push(`${i + 1}x${j + 1} = ${sudoku[i * 9 + j]}`);
}
const rule_clauses = [];
const knights_move_offsets = [[ 2, 1], [ 2, -1], [-2, 1], [-2, -1],
[ 1, 2], [ 1, -2], [-1, 2], [-1, -2]],
kings_move_offsets = [[ 0, 1], [ 0, -1], [ 1, 0], [-1, 0],
[ 1, 1], [ 1, -1], [-1, 1], [-1, -1]],
moves_offsets = knights_move_offsets.concat(kings_move_offsets),
orthogonal_offsets = [[ 1, 1], [ 1, -1], [-1, 1], [-1, -1]];
for (let i = 1; i <= 9; i++)
for (let j = 1; j <= 9; j++) {
for (let k = 1; k <= 9; k++) {
const assignment = `${i}x${j} = ${k}`;
const moves = [];
for (const [offset_i, offset_j] of moves_offsets) {
let i_ = i + offset_i,
j_ = j + offset_j;
if (i_ >= 1 && i_ <= 9 && j_ >= 1 && j_ <= 9)
moves.push(`${i_}x${j_} = ${k}`);
}
rule_clauses.push(imply(assignment, not(or(...moves))));
const consecutive_digits = k === 1 ? [2] : k === 9 ? [8] : [k - 1, k + 1];
for (const [offset_i, offset_j] of orthogonal_offsets) {
let i_ = i + offset_i,
j_ = j + offset_j;
if (i_ >= 1 && i_ <= 9 && j_ >= 1 && j_ <= 9) {
for (const consecutive_digit of consecutive_digits)
moves.push(`${i_}x${j_} = ${consecutive_digit}`);
}
}
}
}
return and(...board_clauses, ...rule_clauses, ...empty_board.clauses);
}