You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.4 KiB
118 lines
3.4 KiB
/* Rectifiable polyomino tilings generator */
|
|
|
|
/* Written and converted to GNU MathProg by NASZVADI, Peter, 2007-2017
|
|
<vuk@cs.elte.hu> */
|
|
|
|
/*
|
|
This model searches for a maximal packing of a given polyomino
|
|
composed of unit squares in a given rectangle. In a feasible packing, a
|
|
placed polyomino and its intersection of a unit square's inner part in
|
|
the rectangle must be the square or empty. If there exists a packing
|
|
that covers totally the rectangle, then the polyomino is called
|
|
"rectifiable"
|
|
|
|
Summary:
|
|
Decides if an Im * Jm rectangle could be tiled with given pattern
|
|
and prints a (sub)optimal solution if found
|
|
|
|
Generated magic numbers are implicit tables, check them:
|
|
|
|
# for magic in 3248 688 1660 3260
|
|
do printf "Magic % 5d:" "$magic"
|
|
for e in 0 1 2 3 4 5 6 7
|
|
do printf "% 3d" "$((-1 + ((magic / (3**e)) % 3)))"
|
|
done
|
|
echo
|
|
done
|
|
Magic 3248: 1 1 -1 -1 0 0 0 0
|
|
Magic 688: 0 0 0 0 1 1 -1 -1
|
|
Magic 1660: 0 0 0 0 1 -1 1 -1
|
|
Magic 3260: 1 -1 1 -1 0 0 0 0
|
|
#
|
|
*/
|
|
|
|
param Im, default 3;
|
|
/* vertical edge length of the box */
|
|
|
|
param Jm, default 3;
|
|
/* horizontal edge length of the box */
|
|
|
|
set S, default {(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2)};
|
|
/* P-heptomino is the default shape. More info on this heptomino:
|
|
http://www.cflmath.com/Polyomino/7omino4_rect.html */
|
|
|
|
set I := 1..Im;
|
|
/* rows of rectangle */
|
|
|
|
set J := 1..Jm;
|
|
/* columns of rectangle */
|
|
|
|
set IJ := I cross J;
|
|
/* the rectangle itself */
|
|
|
|
set E := 0..7;
|
|
/* helper set to allow iterating on all transformations of the S shape */
|
|
|
|
set Shifts := setof{(i, j, e) in IJ cross E:
|
|
setof{(x, y) in S}
|
|
((x * (-1 + floor(3248 / 3^e) mod 3)) +
|
|
(y * (-1 + floor(688 / 3^e) mod 3)) + i,
|
|
(x * (-1 + floor(1660 / 3^e) mod 3)) +
|
|
(y * (-1 + floor(3260 / 3^e) mod 3)) + j) within IJ}(i, j, e);
|
|
/* all shifted, flipped, rotated, mirrored mappings of polyomino that
|
|
contained by the rectangle */
|
|
|
|
var cell{IJ}, binary;
|
|
/* booleans denoting if a cell is covered in the rectangle */
|
|
|
|
var tile{Shifts}, binary;
|
|
/* booleans denoting usage of a shift */
|
|
|
|
var objvalue;
|
|
|
|
s.t. covers{(i, j) in IJ}: sum{(k, l, e, a, b) in Shifts cross S:
|
|
i = k + a * (-1 + floor(3248 / 3^e) mod 3) +
|
|
b * (-1 + floor(688 / 3^e) mod 3)
|
|
and
|
|
j = l + a * (-1 + floor(1660 / 3^e) mod 3) +
|
|
b * (-1 + floor(3260 / 3^e) mod 3)
|
|
}tile[k, l, e] = cell[i, j];
|
|
|
|
s.t. objeval: sum{(i, j) in IJ}cell[i, j] - objvalue = 0;
|
|
|
|
maximize obj: objvalue;
|
|
|
|
solve;
|
|
|
|
printf '\nCovered cells/all cells = %d/%d\n\n', objvalue.val, Im * Jm;
|
|
printf '\nA tiling:\n\n';
|
|
for{i in I}{
|
|
for{j in J}{
|
|
printf '%s', if cell[i, j].val then '' else ' *** ';
|
|
for{(k, l, e, a, b) in Shifts cross S:
|
|
cell[i, j].val
|
|
and i = k + a * (-1 + floor(3248 / 3^e) mod 3) +
|
|
b * (-1 + floor(688 / 3^e) mod 3)
|
|
and j = l + a * (-1 + floor(1660 / 3^e) mod 3) +
|
|
b * (-1 + floor(3260 / 3^e) mod 3)
|
|
and tile[k, l, e].val
|
|
}{
|
|
printf '% 5d', (k * Jm + l) * 8 + e;
|
|
}
|
|
}
|
|
printf '\n';
|
|
}
|
|
printf '\n';
|
|
|
|
data;
|
|
|
|
param Im := 14;
|
|
/* here can be set rectangle's one side */
|
|
|
|
param Jm := 14;
|
|
/* here can be set rectangle's other side */
|
|
|
|
set S := (0,0),(1,0),(2,0),(0,1),(1,1),(2,1),(0,2);
|
|
/* here you can specify arbitrary polyomino */
|
|
|
|
end;
|