1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

137 lines
3.8 KiB
MiniZinc

%------------------------------------------------------------------------------%
include "count.mzn";
%------------------------------------------------------------------------------%
% Parameters
int: X; % Number of cells in the x-direction
int: Y; % NUmber of cells in the y-direction
int: N; % Number of pairs
set of int: Pairs = 1..N;
set of int: Xs = 1..X;
set of int: Ys = 1..Y;
% These arrays all correspond.
%
array[Pairs] of Xs: end_points_start_x;
array[Pairs] of Ys: end_points_start_y;
array[Pairs] of Xs: end_points_end_x;
array[Pairs] of Ys: end_points_end_y;
set of int: Dom = 0..N;
%------------------------------------------------------------------------------%
% Variables
array [Xs, Ys] of var Dom: board;
%------------------------------------------------------------------------------%
% Tests
test is_end_point(int: x, int: y) =
exists(i in Pairs)(
(end_points_start_x[i] = x /\ end_points_start_y[i] = y)
\/ (end_points_end_x [i] = x /\ end_points_end_y [i] = y)
);
test is_neighbour_from_xy(int: x, int: y, int: u, int: v) = (
u in Xs /\ v in Ys /\ x in Xs /\ y in Ys
/\ ( (x == u /\ y in {v - 1, v + 1})
\/ (y == v /\ x in {u - 1, u + 1})
)
);
%------------------------------------------------------------------------------%
% Constraints
% Endpoints must be match with input
%
constraint
forall(i in Pairs)(
board[end_points_start_x[i], end_points_start_y[i]] = i
/\ board[end_points_end_x [i], end_points_end_y [i]] = i
);
% Every endpoint has exactly one neighbour
%
constraint
forall(i in Pairs)(
let {
int: x1 = end_points_start_x[i],
int: y1 = end_points_start_y[i],
int: y2 = end_points_end_y [i],
int: x2 = end_points_end_x [i]
} in (
count([board[u, v] | u in x1-1..x1+1, v in y1-1..y1+1 where
is_neighbour_from_xy(x1, y1, u, v)], i, 1
)
/\ count([board[u, v] | u in x2-1..x2+1, v in y2-1..y2+1 where
is_neighbour_from_xy(x2, y2, u, v)], i, 1
)
)
);
% Interior points has exactly two neighbours
%
constraint
forall(x in Xs, y in Ys)(
if is_end_point(x, y) then
true
else
board[x, y] != 0 ->
count([board[u, v] | u in x-1..x+1, v in y-1..y+1 where
is_neighbour_from_xy(x, y, u, v)], board[x, y], 2)
endif
);
% Some redudant constraints
%
constraint redundant_constraint(
forall(i in Pairs)(
let {
int: x1 = min(end_points_start_x[i], end_points_end_x[i]),
int: y1 = min(end_points_start_y[i], end_points_end_y[i]),
int: x2 = max(end_points_start_x[i], end_points_end_x[i]),
int: y2 = max(end_points_start_y[i], end_points_end_y[i])
} in (
if x1 + 1 < x2 then
forall(x in x1+1..x2-1)(
sum(z in Ys)(bool2int(board[x, z] == i)) > 0
)
else
true
endif
/\ if y1 + 1 < y2 then
forall(y in y1+1..y2-1)(
sum(z in Xs)(bool2int(board[z, y] == i)) > 0
)
else
true
endif
)
)
);
%------------------------------------------------------------------------------%
% Search
solve
:: int_search(array1d(1..X*Y, board), input_order, indomain_split, complete)
satisfy;
%------------------------------------------------------------------------------%
% Output
output [
"% "
] ++ [
show_int(floor(log10(int2float(N)) + 1.0), board[x, y]) ++
if x = X then "\n% " else " " endif
| y in Ys, x in Xs
] ++ [
"\nboard = array2d(", show(Xs), ", ", show(Ys), ", ", show(board), ");\n"
];