polycube: A polyomino and polycube puzzle solver.
Copyright 2011 Matthew T. Busche.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see .
_______________________________________________________________________________
COMPILING THE SOFTWARE
If you're on a windows machine, you can skip the compilation process and
just use the provided windows executable. For maximum compatibility,
this executable was not built to using Gnu builtins (see below), and so
building the software yourself can give you a slightly faster executable.
If you don't have a compiler, you can get the GNU compiler collection (GCC)
for many platforms for free. For windows you can get g++ either by installing
Cygnus or MinGW. I've tried out both and I recommend MinGW for the following
reasons:
1) The applications you build with the Cygnus version of g++ have dependencies
on the Cygnus DLL, so you have to have Cygnus installed on your machine in
order to run the application, making it difficult to share your apps with
your friends. Apps built with the MinGW version of g++ depend only on
standard Windows libs.
2) The default installation selections for Cygnus do not include the g++
compiler so you have to be sure to click off the development package during
installation. In contrast, the whole purpose of MinGW is GCC and the GNU
binutils and so there's no such installation selection step.
3) If all you want to do is build the polycube app, then Cygnus is overkill as
it includes worlds of stuff you don't need. MinGW is a comparatively
miniscule download that includes only GCC and GNU binutils.
The C++ software makes use of two third-party support packages: boost and the
Mersenne Twister random number generator. To make it as easy as possible to
build this software, I've included those portions of those libraries sufficent
to build the solver. (In an effort to keep the download size small, I've
kept only those source files I use and the copyright information. It is
conceivable I've mistakenly stripped boost headers that are conditionally
included for specific build environments. If you get file-not-found errors
during the build I recommend you download the full boost library and wholly
replace the boost directory structure in the polycube download.)
The first (and only) time I tried to build the boost library it blew up in my
face. Clearly I did something wrong, but hadn't the patience to figure it out.
Instead I just added the handful of needed source files from the boost package
to my compile line.
I am not particularly skilled at C++ build systems, and was skeptical I
could construct a bug-free build system that worked for most environments.
To build the solver with g++ you need only execute this single command:
> cd src
> g++ -O3 -std=c++11 -o ../polycube.exe -DDSFMT_MEXP=19937 -DNOSIGNALS -I . -I boost_1_64_0 -I dSFMT_2.1 -lstdc++ *.cpp dSFMT_2.1/dSFMT.c boost_1_64_0/libs/program_options/src/*.cpp
The command line options for other compilers should be about the same.
If you compile with -Wall (to get all warnings) you'll see quite a bit of
warning noise produced from the boost libraries. I use these warning options
when I compile to avoid these problems:
-Wall
-Wno-missing-braces
-Wno-parentheses
-Wno-sign-compare
-Wno-strict-aliasing
-Wno-unused-local-typedefs
If you're on a Unix box, drop the ".exe" from the filename of the generated
executable; and also drop the -DNOSIGNALS from the compile line -- this will
allow you to send signals 10 or 12 to the process to cause it to (respectively)
asynchronously display status or a puzzle trace.
If you're using a gnu compiler, you can add these options to the compile line
-march=native -DUSE_GNU_BUILTINS
which gives the size (s), estimate (e), and first (f) heuristics access to
gnu builtin functions __builtin_popcount, and __builtin_clz which respectively
count the number of set bits in a bit field, and identify the lowest set bit
in a bitfield which can singificantly speed up these heuristics. These
builtins are each implemented as a silicon-based machine instruction (assuming
your processor includes those machine instructions.)
The FILA puzzle solving algorithm models the occupancy state of the puzzle
with a single integer bit field. FILA cannot be activated until the number of
unfilled cells in the puzzle is reduced to the number of bits in this bit
field. The size of the bitfield is set at compile time and can have values
32, 64 or 128. The default size is 64 which has best performance on 64 bit
machines. The bitfield size can be set with one of these compile options:
-DGRIDBITFIELD_SIZE=128
-DGRIDBITFIELD_SIZE=64
-DGRIDBITFIELD_SIZE=32
_______________________________________________________________________________
PUZZLE DEFINITION FILES
Polycube requires at least one puzzle definition file as input. Puzzle
definition files are fairly straightforward and you can probably learn
everything you need to know by looking at a couple of provided samples in the
def directory. Nevertheless, a somewhat formal description of these files
is here provided.
A puzzle definition file is line oriented. Blank lines are ignored (unless
they are in the middle of a layout directive). A pound character begins a
comment that runs to end of line. There are three types of directives that
can appear in a puzzle definition:
D - Definition
C - Coordinate
L - Layout
While a coordinate directive is written on a single line, definition and
layout directives span multiple lines, but the first line for all directives
share a common format:
N[:attribute1=setting1[:attribute2=setting2[:...]]]
where N is the single character name of the directive (D, C or L), and the
rest of the line is a colon-separated list of attribute settings.
D - DEFINITION DIRECTIVE
A definition directive defines a puzzle. The directive begins with a line
having the following format:
D:xDim=:yDim=:zDim=[:oneSide[=1]]
The directive ends with the definition terminator which must appear on a
line by itself:
~D
Nested between these two lines will be L and/or C directives which
define the pieces of the puzzle.
The user defined parameters XDIM, YDIM and ZDIM must all be strictly
positive integers. For 2-D polyomino puzzles, set zDim=1. The optional
parameter oneSide is to declare a one-sided polyomino puzzle. Declaring a
oneSided puzzle requires zDim to be set to 1. Because oneSide is a
boolean valued attribute the assignment of the value 1 is implied and no
explicit assignment is required.
Note that all puzzles have the shape of a cuboid: a 6-sided object
with rectangular sides. To solve puzzles with other shapes, define
a cuboid large enough to encompass your puzzle and define a stationary
piece to fill in the unwanted space.
C - COORDINATE DIRECTIVE
A coordinate directive specifies a single puzzle piece by the
(x,y,z) coordinates of it's constituent cubes. The directive
has this form:
C:name=:[type=M|S:]layout= [, [, ...]]
is an arbitrary string name used in solution output. Although
there is no limitation on the permitted length of names, short names (1 or
2 characters) make for better text-based graphics output. The names "."
and "#" are reserved.
A piece's type may be set to either M (mobile) or S (stationary). A
stationary piece is loaded into the puzzle at the exact coordinates given
in the layout field. A mobile piece is free to be rotated and translated
to fit any open space in the puzzle. If a type is not specified the piece
defaults to type M. As noted above, you can use stationary pieces to
define puzzle spaces that go beyond simple rectangular boxes; but you can
also use them to simply force certain pieces into particular positions in
the puzzle if that suits your fancy.
The layout attribute is a series of (x y z) coordinates with each triplet
separated by a comma. The x, y and z scalars within each coordinate
triplet are separated by white-space (not commas). Here is a sample
coordinate directive for a mobile piece named V in coordinate format:
C:name=V:type=M:layout=0 0 0, 1 0 0, 2 0 0, 2 1 0, 2 2 0
L - LAYOUT DIRECTIVE
A layout directive is a multi-line directive allowing you to define one or
more pieces with simple text-based graphics. The directive has the
following form:
L[:stationary=S1[ S2[ ...]]]
~L
The stationary setting is white-space separated list of names of pieces
that appear in the layout that should be loaded in exactly the positions
shown in the . (By default, the pieces defined in are
mobile.) The is just a text-graphics based representation of one
or more puzzle pieces. Here is a layout directive defining two of the
twelve pentominoes pieces:
L
Z Z
. Z
. Z Z
W
W W
. W W
~L
The lines between the L and ~L are your drawing area which can be as
large as needed to define all your pieces. Horizontal white space is
ignored so you must use the special character "." to indicate an
unoccupied cell. The line immediately following the directive has a y
coordinate value of YDIM-1 and each subsequent line decrements the y
coordinate value. This is important if you are defining stationary
pieces. Here is a layout directive that will fill the center squares of
an 8x8 puzzle with a stationary piece named '*':
L:stationary=*
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . * * . . .
. . . * * . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
~L
For three dimensional puzzles, the layout depicts horizontal slices of the
puzzle box like the layers of a cake. Each layer on each line is separated
by a comma. The first slice (on the left) shows the bottom layer of the
box (Z=0); the next slice is the second layer of the box (Z=1); etc.
Note that if you happen to have a solution to the puzzle you are solving
you can just copy that solution into the layout directive to define
the entire puzzle in one go. For example, here is a layout-based
definition for the Tetris Cube puzzle:
D:xDim=4:yDim=4:zDim=4
L
F F D D, D D D C, K K C C, H H H H
F F J G, K F I I, K C C I, K E H B
A L J G, A L J J, A A A I, E E E B
A G G G, L L L J, E L B I, E B B B
~L
~D
_______________________________________________________________________________
RUNNING THE SOFTWARE
Move the compiled executable to someplace in your PATH or to the directory
where you want to run it. Polycube reads puzzle definitions from either a
user provided file list or from standard input and prints solutions to those
puzzles to standard output. For example:
> polycube def/pentominoes_10x6_def.txt def/tetriscube_def.txt
or
> cat def/tetriscube_def.txt | polycube
By design, every command line option can take an argument, but not all of them
require an argument. For example, the -r option is used to enable the
rotational redundancy image filter. If you include an argument to the -r
option, it is taken to be the name of the piece you want to constrain to
attempt to eliminate rotationally redundant solutions from the search. If you
don't pass an argument, then the argument defaults to the value '#' which is
interpreted as a wild-card and causes the solver to make a good pick for the
piece to constrain. Now, if you try to execute the command line:
> polycube -r mypuzzle.txt
You'll find that the program just sits there and does nothing! The problem
is that it's interpreting mypuzzle.txt as a piece name argument to the -r
option and then having no puzzle definition file, it's trying to read a
definition from standard input! For this reason it's a good idea to get in
the habit of adding the end-of-option indicator (--) to your command lines
between your last program option and your first puzzle definition file name:
> polycube -r -- mypuzzle.txt
Although I'm generally big on having software exhibit good default behaviors,
polycube was written firstly as a tool to analyze the tradeoffs of different
puzzle solving techniques and so defaults to the simplest of behaviors: using
DLX with a min-fit heuristic. But you can usually get much better performance
by turning on various backtrack triggers and/or image filters. Here are a few
suggestions:
1. Use the -r option if you're trying to find all solutions to a puzzle.
This enables the rotational redundancy filter and can give huge
performance benefits if your puzzle has rotational symmetries.
2. Use the -p option for puzzles with extreme parity. This turns on parity
backtrack triggering. If the parity of the puzzle is near the maximum
of parity achievable by your puzzle pieces, this feature can give
a performance kick. It can also immediately identify that some puzzles
are unsolveable due to parity constraints. It has very little overhead,
and can at worst slow things down by maybe 1 to 2 percent.
3. Use the -V option for 2D puzzles. This performs a one-shot volume
constraint filter of all piece images to eliminate images that can't
possibly lead to solutions. This is almost always beneficial and is
sometimes very beneficial indeed.
4. Make sure you use DLX to place the first piece, but otherwise use the -f
option to use FILA to place as many remaining pieces as possible. So
for example if you have 12 pieces, try -f11. (Note that there is a limit
to how soon you can activate FILA due to limitations of the size of the
bitfield used to model the occupancy state as described above.) The
default size ('s') heuristic is usually good for DLX, but very expensive
for FILA as it requires explicit fit counts at each cell, so whenever
you use the -f option, always also use the -o option to change to a
lighter weight ordering heuristic at the same time. My favorites are
'f' and 'e'. So for the same 12 piece puzzle you might try -of=11 or
-oe=11 or maybe a combination -oe=11:f=3.
5. Use the -n option to activate NOF filtering for FILA. This pretty much
always speeds up FILA. In my experience the performance benefit is from
5 to 20 percent.
6. The -i option provides lots of interesting information about your
puzzle, and various statistics about the search performed.
You can learn more about these and other options by reading the synopsis
generated by running polycube with the help option:
> polycube --help
Takes a list of polycube puzzle definition files and outputs all solutions to
them. If no puzzle definition files are provided, puzzle definitions are read
from standard input. Common configuration options are:
-f [ --fila ] arg
Sets the number of remaining pieces when the DLX algorithm is turned off
and the FILA algorithm is turned on. A FILA setting of zero disables
FILA altogether and ensures DLX is used exclusively. There are two
conditions where the transition from DLX to FILA can be delayed. First,
if the number of remaining GridPoints remaining to be filled in the
puzzle is more than the number of bits in the data type gridbitfield_t
then the remaining puzzle cannot be modeled until more pieces are placed.
Second, polycube will not transition to FILA if any DLX column has either
0 or 1 entries. The default value is 0.
-F [ --fitFilter ] [=arg(=-1)]
Set the minimum number of remaining pieces for the invocation of
fit-based filtering of puzzle piece images. A fit filter operation
examines each remaining row in the DLX matrix to see if using that row
would result in a puzzle configuration where some hole can no longer be
filled or some piece can no longer be placed. If this occurs, the row is
temporarily removed. Setting fitFilter to the special fixed value -1 is
equivalent to setting to the number of pieces in the puzzle and results
in fit-based filtering to be applied just once before the search begins.
A setting of 0 disables fit-based filtering altogether. Note that
filtering is implemented on the DLX matrix and so decreasing the setting
below the fila settings has no affect. The default setting is 0.
-g [ --goal ] arg
Each time the number of remaining pieces equals the goal, a solution is
declared and processed, and a backtrack is forced (even if additional
pieces could be placed). The default setting is 0. Setting the goal to
non-zero values is useful for breaking down a large puzzle into many
smaller puzzles. See also the -O and -R options.
-i [ --info ] [=arg(=1)]
If set to true, input configuration, puzzle properties, search
statistics, and performance measurements are output. By default this
feature is off.
-n [ --nof ] [=arg(=1)]
If set to true, neighbor occupancy filtering (NOF) for FILA is enabled.
When NOF is disabled, each ordering heuristic keeps for each puzzle cell,
for each shape, a single list of images of that shape that cover that
cell, fit in the puzzle and do not conflict with puzzle cells that must
be filled due to a fixed target cell selection order enforced by the
heuristic (if any). If NOF is enabled, the heuristic will instead have
up to 64 different lists for each shape at each cell. Each list
corresponds to a different possible compound occupancy state of the 6
adjacent neighbors of the cell. The images in the list are then
guaranteed to not conflict with the associated neighbor occupancy state
which can drastically reduce the number of images in the list that don't
fit the current puzzle state.By default this feature is off.
-o [ --order ] arg
Configure ordering heuristics used to pick which hole to fill or piece to
place at each step of an algorithm. Without restriction, different
heuristics may be specified for use when there are different numbers of
pieces left to place in the puzzle box. The ordering specification (arg)
has the following format:
N1[@A1][=R1][:N2[@A2]=R2[:...]]
where N1, N2, ... are names of available heuristics; A1, A2, ... are
arguments which, depending on the heuristic, may or may not be required;
and R1, R2, ... are the number of remaining pieces causing the heuristic
to be enabled (replacing the previously enabled heuristic). One
heuristic may be specified without an R setting which causes it to be the
first heuristic enabled. There are currently five heuristics to choose
from: s, l, a, A and R. For the special case of DLX, all of these
heuristics will pick a column with zero or one fits over any other column
(with a zero fit column taking precedence over a one fit column).
Currently, the heuristics do not make this optimization for FILA because
it would require explicit fit counting at every hole (which is too
expensive). Otherwise, the heuristics have these behaviors:
s: (The size heuristic.) For the case of DLX, picks the matrix
column with minimum fits (either a hole or a piece). For the case
of FILA, picks the hole with minimum fits. This heuristic takes
no arguments.
e: (The estimated size heuristic.) For the case of DLX, this
heuristic is identical to the s heuristic. For FILA, a hole
having a minimum number of unoccupied nearest neighbor GridPoints
is selected (where a nearest neighbor is one of the 6 GridPoints
in the +x, -x, +y, -y, +z, and -z directions that share a common
side with the target.) In the case of ties, an explicit fit count
is made, and the GridPoint with a minimum number of fits is
selected. This heuristic takes no arguments.
f: (The first heuristic.) Selects the first hole assuming a
GridPoints are sorted in X, Y, Z coordinate priority order. So,
for example, in a 2x2x2 puzzle, the GridPoints have this ordering:
(0,0,0)
(0,0,1)
(0,1,0)
(0,1,1)
(1,0,0)
(1,0,1)
(1,1,0)
(1,1,1)
For best performance, it is important to orient your puzzle so
that the longest dimension lies along the X axis, and the shortest
is along the Z axis. This is the ordering heuristic used by the
Fletcher (1965) and de Bruijn (1969) algorithms. This heuristic
takes no arguments.
l@a,b,c: (The linear heuristic.) Picks the GridPoint that minimizes
the linear sum a*x + b*y + c*z.
a[@i[,xc,yc]]: Picks the GridPoint with minimum angle from origin
(xc, yc) in the X-Y plane relative to the reference angle i (which
should be given in degrees -- not radians). The default values
for (xc, yc) are the mid point of the puzzle. The default value
for i is zero.
A[@i[,xc,yc]]: Identical to a, but maximizes the angle instead.
R[@xc,yc,zc]: Picks the GridPoint with maximum distance from (xc, yc,
zc). The default value for (xc, yc, zc) is the center of the
puzzle.
In addition, these shorthand notations are available:
x: Equivalent to l@1,0,0
y: Equivalent to l@0,1,0
z: Equivalent to l@0,0,1
X: Equivalent to l@-1,0,0
Y: Equivalent to l@0,-1,0
Z: Equivalent to l@0,0,-1
xyz: Equivalent to l@1,1,1
The default heuristic is s.
-O [ --output ] arg
Selects the format of solution and trace output. The configuration
argument may be up to two characters. The overall format of each
solution or trace output is specified by one character:
B - Brief (default)
F - Full
S - Sub-puzzle
Brief output only displays placed pieces. Full output is in the form of
complete puzzle definitions which may be reapplied as input. Sub-puzzle
output is like full output, but placed pieces are encoded as stationary,
which is useful when combined with the -g and -R options to break one
large puzzle into smaller subpuzzles.
The output format of pieces is specfied by one character:
L - Layout (default)
C - Coordinate
These two output formats are identical to the puzzle piece input formats
of the layout (L) and coordinate (C) directives.
-p [ --parityBacktrack ] [=arg(=1)]
If set, parity constraint violations are checked after each piece
placement. If the check fails, the algorithm will immediately backtrack.
These checks are implemented in both DLX and FILA. Unlike parity
filtering, a parity backtrack check is extremely fast and adds little
processing overhead to the algorithms. If the puzzle was parity filtered
immediately prior to placing the subject piece, then this parity check
cannot fail (since all images causing a parity check failure would have
already been filtered from the DLX matrix. By default this feature is
off.
-P [ --parityFilter ] [=arg(=-1)]
Set the minimum number of remaining pieces for the invocation of
parity-based filtering of puzzle piece images. A parity filter operation
examines each remaining row in the DLX matrix to see if using that row
would result in a parity violation for the puzzle as a whole. If a
violation would occur, the row is temporarily removed. Setting
parityFilter to the special fixed value -1 is equivalent setting it to
the number of pieces in the puzzle and results in parity-based filtering
to be applied just once before the search begins. A setting of 0
disables parity-based filtering altogether. Note that filtering is
implemented on the DLX matrix and so decreasing the setting below the
fila setting has no affect. The default setting is 0.
-q [ --quiet ] [=arg(=1)]
If set to true, solutions are not displayed. This is useful if you're
only interested in the run time or statistical information output by the
info option. By default this feature is off.
-r [ --redundancyFilter ] [=arg(=#)]
Set the name of the piece the Solver limits rotations and/or translations
to reduce or potentially eliminate rotationally redundant solutions
without loss of unique solutions. The special value ' #' causes the
solver to pick a piece for you. The special value '.' turns this feature
off. The redundancyFilter piece must have a shape that is unique from
other pieces in the puzzle. The default value is '.'.
-R [ --redundancyFilterFirst ] [=arg(=1)]
If set to true, the DLX column corresponding to the piece selected for
rotational redundancy filtering is forcibly selected to be processed
first. This option is meaningless if not combined with the -r option.
This option is useful when also combined the -O, and -g options to try to
make a set of generated puzzle subproblems rotationally unique. By
default this feature is off.
-s [ --sample ] arg
Enables Monte Carlo sampling of the search space. The configuration
argument is of the form T,R,S where T is the number of trials to perform,
R is the number of remaining pieces that triggers the start and end of a
trial, and S is the 64 bit seed value for the Mersenne Twister 19937
random number generator. When enabled, prior to the execution of any
backtracking algorithm, but after initial application of requested image
filters, the nodes under each DLX column are reordered randomly so that
the order of the search executed by DLX will be randomized. The first
time a piece is removed from the puzzle when exactly R pieces remain
(prior to the removal) the Monte Carlo trial is ended. DLX then
completely unwinds and the matrix is randomly ordered again to start the
next trial. Statistics output at the end of the program will be for all
trials, so you must divide by T to get per trial statistics. The
conditionals to terminate a trial are only implemented in the DLX
algorithm, so R must be greater than or equal to the enabling threshold
of FILA.
-t [ --trace ] [=arg(=1)]
If trace is set to some positive number K, then after each piece
placement, if there are at least K-1 pieces remaining to be placed, then
the state of the puzzle is displayed. Also, after each piece removal if
there are at least K pieces remaining to be placed, then the state of the
puzzle is displayed again. If K is negative, then the state of the
puzzle is displayed only after a piece is placed and only if there are
exactly -(K-1) pieces left to place. If K is zero, then trace output is
disabled. The default value is 0.
-u [ --unique ] [=arg(=1)]
If enabled only rotationally unique solutions are output. Activating
this option enables a solution filter that compares each solution found
to all rotations of all previously discovered solutions (via binary
search). If the new solution is found to be identical to some rotation
of some previously discovered solution, then the solution will still
increment the total solution counter, but is otherwise discarded. If the
solution is found to be unique, then all rotations of that solution are
calculated and added to the list of solutions filtered against. This
filter is forcibly disabled if the puzzle has no symmetric rotations, or
if the redundancyFilter is enabled and it successfully expunges redundant
solutions from the search space. By default this feature is off.
Note: The filter uses 1 byte per GridPoint in the puzzle cuboid per
unique soltuion per symmetric rotation, plus additional memory for
STL vector overhead. So if a puzzle has hundreds of millions of
unique solutions, use of this filter may cause you trouble.
-v [ --volumeBacktrack ] arg
After placing a piece, if the number of remaining pieces equals at least
the volumeBacktrack setting, then the remaining puzzle space is examined
for volume constraint violations. If an isolated sub-space is found that
cannot possibly be filled by the remaining pieces (because no combination
of those pieces gives a total volume that matches the volume of the
sub-space), then the search algorithm immediately backtracks. Unlike
volume filtering, volume backtracks do not require the use of DLX. A
setting of 0 disables volume-based backtrack altogether. The default
setting is 0.
WARNING: the memory required by the internal volume monitor grows
geometrically with the number of different piece sizes.
-V [ --volumeFilter ] [=arg(=-1)]
Set the minimum number of remaining pieces for the invocation of
volume-based filtering of puzzle piece images. A volume filter operation
examines each remaining row in the DLX matrix to see if using that row
would result in the parititioning of the remaining puzzle space with one
of these new subspaces having a volume that cannot possibly be filled
with the remaining pieces of the puzzle. If this occurs, the row is
temporarily removed. Setting volumeFilter to the special fixed value -1
is equivalent to setting to the number of pieces in the puzzle and
results in volume-based filtering to be applied just once before the
search begins. A setting of 0 disables volume-based filtering
altogether. Note that filtering is implemented on the DLX matrix and so
decreasing the setting below the fila setting has no affect. The default
setting is 0.
WARNING: the memory required by the internal volume monitor grows
geometrically with the number of different piece sizes.
Command line only options:
--conf arg
Set configuration file name.
--help [=arg(=1)]
Print program synopsis and exit.
--version [=arg(=1)]
Print version information and exit.
_______________________________________________________________________________
SOLUTION OUTPUT
Solution output is sent to standard out (i.e., to the console). Solution
and trace output format is controlled by the -O (output format) option. The
format has two single character settings. First, the puzzle format which
is one of:
B - Brief (default)
F - Full
S - Sub-puzzle
Second, the piece format which is one of:
L - Layout (default)
C - Coordinate
Here is a sample Tetris Cube solution output with default output format
settings:
# --- SOLUTION 1 ---
D E E C, D L E C, D H K K, H H H H
E E C C, L L B K, D L L K, D G J K
A E C F, A L B F, A A A J, I G J J
A B F F, B B B F, I I I J, I G G G
In this layout piece format, the occupancy of horizontal slices of the puzzle
box are depicted like the layers of a cake. The first slice (on the left) shows
the bottom layer of the box (Z=0); the next slice is the second layer of the
box (Z=1); etc. This output format is the same as the field of a
layout directive described above.
If you switch to Full puzzle output (-OF), you get a full puzzle definition:
# --- SOLUTION 1 ---
D:xDim=4:yDim=4:zDim=4
L
D E E C, D L E C, D H K K, H H H H
E E C C, L L B K, D L L K, D G J K
A E C F, A L B F, A A A J, I G J J
A B F F, B B B F, I I I J, I G G G
~L
~D
Here is a sample of full puzzle format with coordinate piece format (-OFC):
# --- SOLUTION 1 ---
D:xDim=4:yDim=4:zDim=4
C:name=A:type=M:layout=0 0 0,0 1 0,0 1 1,0 1 2,1 1 2,2 1 2
C:name=B:type=M:layout=0 0 1,1 0 0,1 0 1,2 0 1,2 1 1,2 2 1
C:name=I:type=M:layout=0 0 2,0 0 3,0 1 3,1 0 2,2 0 2
C:name=G:type=M:layout=1 0 3,1 1 3,1 2 3,2 0 3,3 0 3
C:name=J:type=M:layout=2 1 3,2 2 3,3 0 2,3 1 2,3 1 3
C:name=F:type=M:layout=2 0 0,3 0 0,3 0 1,3 1 0,3 1 1
C:name=C:type=M:layout=2 1 0,2 2 0,3 2 0,3 3 0,3 3 1
C:name=K:type=M:layout=2 3 2,3 2 1,3 2 2,3 2 3,3 3 2
C:name=E:type=M:layout=0 2 0,1 1 0,1 2 0,1 3 0,2 3 0,2 3 1
C:name=D:type=M:layout=0 2 2,0 2 3,0 3 0,0 3 1,0 3 2
C:name=L:type=M:layout=0 2 1,1 1 1,1 2 1,1 2 2,1 3 1,2 2 2
C:name=H:type=M:layout=0 3 3,1 3 2,1 3 3,2 3 3,3 3 3
~D
When breaking up a large puzzle with the -g (goal) option, the pieces placed
are better listed as stationary so that a subsequent invocation of polycube on
the sub-puzzle definition will not move the placed pieces. This is the purpose
of the -OS (sub-puzzle) output format. As an example, here is how you can
break up the pentominoes 10x6 puzzle into 7 sub-puzzles.
o Use -g11 to force solution output when there are 11 pieces left to
place (i.e., after just one piece has been placed).
o Use -r to get polycube to select and constrain a piece to eliminate
rotational redundancies among solutions found.
o Use -R to force that constrained piece into the puzzle box first.
(Turns out this is not necessary as DLX would have made this decision
anyway, but this makes sure it gets done.)
o Use -OS for sub-puzzle output which causes placed pieces to be displayed
as stationary in solution output. (Note that the X piece is listed as
stationary in the output below.)
o Use -V just because it's a wonderful. In this case it eliminates the
solution where the X piece is jammed into the corner of the solution box.
Here is the result:
> ./polycube -r -R -V -g11 -OS -- def/pentominoes_10x6_def.txt
# --- SOLUTION 1 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. X . . . . . . . .
X X X . . . . . . .
. X . . . . . . . .
. . . . . . . . . .
~L
~D
# --- SOLUTION 2 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . X . . . . . . .
. X X X . . . . . .
. . X . . . . . . .
~L
~D
# --- SOLUTION 3 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. . X . . . . . . .
. X X X . . . . . .
. . X . . . . . . .
. . . . . . . . . .
~L
~D
# --- SOLUTION 4 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . X . . . . . .
. . X X X . . . . .
. . . X . . . . . .
~L
~D
# --- SOLUTION 5 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. . . X . . . . . .
. . X X X . . . . .
. . . X . . . . . .
. . . . . . . . . .
~L
~D
# --- SOLUTION 6 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . X . . . . .
. . . X X X . . . .
. . . . X . . . . .
~L
~D
# --- SOLUTION 7 ---
D:xDim=10:yDim=6:zDim=1
C:name=F:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0
C:name=I:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0
C:name=L:type=M:layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0
C:name=N:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0
C:name=P:type=M:layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0
C:name=T:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0
C:name=U:type=M:layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0
C:name=V:type=M:layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0
C:name=W:type=M:layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0
C:name=Y:type=M:layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0
C:name=Z:type=M:layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0
L:stationary=X
. . . . . . . . . .
. . . . . . . . . .
. . . . X . . . . .
. . . X X X . . . .
. . . . X . . . . .
. . . . . . . . . .
~L
~D
_______________________________________________________________________________
TRACE OUTPUT
For purposes of debugging, understanding, or progress monitoring you can dump
the state of the puzzle solution space using the trace option. See the
trace option description above for the configuration settings available.
Here is some sample output:
TRACE 1:
. . . ., . . . ., . . . ., . . . .
. . . ., . . . ., . . . ., . . . .
A . . ., A . . ., A A A ., . . . .
A . . ., . . . ., . . . ., . . . .
END TRACE
TRACE 2:
. . . ., . . . ., . . . ., . . . .
. . . ., . . B ., . . . ., . . . .
A . . ., A . B ., A A A ., . . . .
A B . ., B B B ., . . . ., . . . .
END TRACE
TRACE 3:
. . . ., . . . ., . . . ., . . . .
. . . ., . . B ., . . . ., . . . .
A . . ., A . B ., A A A ., . . C .
A B . ., B B B ., C C . ., . C C .
END TRACE
TRACE 4:
. . . ., . . . ., . . . ., . . . .
. . . ., . . B E, . . . ., . . . .
A . . E, A . B E, A A A E, . . C .
A B . ., B B B ., C C E E, . C C .
END TRACE
TRACE 5:
. . . ., . . . ., . . . ., . . . .
. . I ., . . B E, . . . ., . . . .
A . I E, A . B E, A A A E, . . C .
A B I I, B B B I, C C E E, . C C .
END TRACE
_______________________________________________________________________________
INFORMATIONAL OUTPUT
With the --info option activated, before the search begins, polycube prints
out various information about optimization settings, puzzle properties, etc;
and after the search is complete, it prints out various statistics (like the
number of solutions found, number of solutions filtered due to rotational
symmetry, and run time.) This should all be self explanatory. Here is sample
run with informational output enabled:
> ./polycube -i -r -V -f11 -of=11 -n -- def/pentominoes_10x6.txt
# Program start time
START_TIME=06/Jan/2019 13:23:28 MST
# Polycube version
VERSION=2.0.1
# Puzzle occupancy bit field size. (See GRIDBITFIELD_SIZE in README.txt.)
GRIDBITFIELD_SIZE=64
# Solver configuration settings
fila=11
fitFilter=0
goal=0
info=1
nof=1
orderingHeuristicConfig=f=11
outputFormat=BL
parityBacktrack=0
parityFilter=0
quiet=0
redundancyFilter=#
redundancyFilterFirst=0
sample=0,0,0
trace=0
unique=0
volumeBacktrack=0
volumeFilter=-1
# Puzzle file:
PUZZLE_FILE=def/pentominoes_10x6.txt
# Puzzle size:
DIMENSION=10x6x1
# Shape list:
SHAPE[0]={layout=0 1 0,0 2 0,1 0 0,1 1 0,2 1 0:parity=-1:numRow=256:count=1:id=0:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=256:numMobileImagesWithNegativeParity=128:pieceList={F}}
SHAPE[1]={layout=0 0 0,1 0 0,2 0 0,3 0 0,4 0 0:parity=1:numRow=56:count=1:id=1:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=56:numMobileImagesWithNegativeParity=28:pieceList={I}}
SHAPE[2]={layout=0 0 0,1 0 0,2 0 0,3 0 0,3 1 0:parity=1:numRow=248:count=1:id=2:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=248:numMobileImagesWithNegativeParity=124:pieceList={L}}
SHAPE[3]={layout=0 0 0,1 0 0,2 0 0,2 1 0,3 1 0:parity=1:numRow=248:count=1:id=3:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=248:numMobileImagesWithNegativeParity=124:pieceList={N}}
SHAPE[4]={layout=0 0 0,0 1 0,1 0 0,1 1 0,2 0 0:parity=1:numRow=304:count=1:id=4:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=304:numMobileImagesWithNegativeParity=152:pieceList={P}}
SHAPE[5]={layout=0 0 0,1 0 0,1 1 0,1 2 0,2 0 0:parity=1:numRow=128:count=1:id=5:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=128:numMobileImagesWithNegativeParity=64:pieceList={T}}
SHAPE[6]={layout=0 0 0,0 1 0,1 0 0,2 0 0,2 1 0:parity=-1:numRow=152:count=1:id=6:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=152:numMobileImagesWithNegativeParity=76:pieceList={U}}
SHAPE[7]={layout=0 0 0,0 1 0,0 2 0,1 0 0,2 0 0:parity=1:numRow=128:count=1:id=7:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=128:numMobileImagesWithNegativeParity=64:pieceList={V}}
SHAPE[8]={layout=0 1 0,0 2 0,1 0 0,1 1 0,2 0 0:parity=1:numRow=128:count=1:id=8:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=128:numMobileImagesWithNegativeParity=64:pieceList={W}}
SHAPE[9]={layout=0 1 0,1 0 0,1 1 0,1 2 0,2 1 0:parity=-3:numRow=8:count=1:id=9:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=8:numMobileImagesWithNegativeParity=4:pieceList={X}}
SHAPE[10]={layout=0 0 0,1 0 0,2 0 0,2 1 0,3 0 0:parity=-1:numRow=248:count=1:id=10:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=248:numMobileImagesWithNegativeParity=124:pieceList={Y}}
SHAPE[11]={layout=0 0 0,1 0 0,1 1 0,1 2 0,2 2 0:parity=1:numRow=128:count=1:id=11:numCopies=1:numStationary=0:numMobile=1:numStationaryImages=0:numMobileImages=128:numMobileImagesWithNegativeParity=64:pieceList={Z}}
# One sided polyomino constraint:
ONE_SIDE=OFF
# Redundancy filter piece name:
REDUNDANCY_FILTER=X
# Piece rotations and translations that fit in the solution space:
BOUNDED=2032
# Are solutions guaranteed to be rotationally unique without filtering?
ROTATIONALLY_UNIQUE=true
# Parity of solution space (after all fixed-position pieces are placed):
PUZZLE_PARITY=0
# --- SOLUTION 1 ---
V V V Y I I I I I T
V Y Y Y Y W W T T T
V X Z Z P P W W F T
X X X Z P P P W F F
U X U Z Z N N F F L
U U U N N N L L L L
# --- SOLUTION 2 ---
V V V Y I I I I I T
V Y Y Y Y W W T T T
V X Z Z W W P P F T
X X X Z W P P P F F
U X U Z Z N N F F L
U U U N N N L L L L
# --- SOLUTION 3 ---
V V V Y I I I I I W
V Y Y Y Y N N N W W
V X Z Z N N F W W T
X X X Z F F F T T T
U X U Z Z F L P P T
U U U L L L L P P P
# --- SOLUTION 4 ---
V V V Y T T T N N N
V Y Y Y Y T N N L L
V X Z Z W T P P P L
X X X Z W W P P F L
U X U Z Z W W F F L
U U U I I I I I F F
# .
# .
# .
# MORE SOLUTIONS HERE
# .
# .
# .
# --- SOLUTION 2338 ---
N N N W W Z Z U U U
I T N N W W Z U V U
I T T T X W Z Z V Y
I T F X X X V V V Y
I F F F X L P P Y Y
I F L L L L P P P Y
# --- SOLUTION 2339 ---
N N N W W Z Z U U U
I T N N W W Z U Y U
I T T T X W Z Z Y Y
I T F X X X P P Y V
I F F F X L P P Y V
I F L L L L P V V V
# Number of solutions found:
SOLUTIONS=2339
# Number of solutions found per second:
SOLUTIONS_PER_SEC=11884.7399
# Number of rotationally unique solutions found:
UNIQUE=2339
# Number of rotationally unique solutions found per second:
UNIQUE_PER_SEC=11884.7399
# Number of rotationally redundant solutions found but filtered out:
REDUNDANT=0
# Number of backtracks due to parity constraint:
PARITY_BACKTRACK_TOTAL=0
# Number of backtracks due to volume constraint:
VOLUME_BACKTRACK_TOTAL=0
# Number of rows filtered due to fit constraint:
FIT_FILTER_TOTAL=0
# Number of rows filtered due to parity constraint:
PARITY_FILTER_TOTAL=0
# Number of rows filtered due to volume constraint:
VOLUME_FILTER_TOTAL=125
# Number of times pieces were attempted to be placed:
ATTEMPTS_TOTAL=6774101
# Number of times pieces fit:
FITS_TOTAL=2091215
# Number of DLX list deletions when N pieces were left to be placed:
DLX_LIST_DELETES[ 1]= 0
DLX_LIST_DELETES[ 2]= 0
DLX_LIST_DELETES[ 3]= 0
DLX_LIST_DELETES[ 4]= 0
DLX_LIST_DELETES[ 5]= 0
DLX_LIST_DELETES[ 6]= 0
DLX_LIST_DELETES[ 7]= 0
DLX_LIST_DELETES[ 8]= 0
DLX_LIST_DELETES[ 9]= 0
DLX_LIST_DELETES[10]= 0
DLX_LIST_DELETES[11]= 22045
DLX_LIST_DELETES[12]= 786
# Number of times a piece was placed with a parity moving away from the target parity when N pieces were left to be placed:
WRONG_WAY_PARITY_WALK[ 1]= 0
WRONG_WAY_PARITY_WALK[ 2]= 0
WRONG_WAY_PARITY_WALK[ 3]= 0
WRONG_WAY_PARITY_WALK[ 4]= 0
WRONG_WAY_PARITY_WALK[ 5]= 0
WRONG_WAY_PARITY_WALK[ 6]= 0
WRONG_WAY_PARITY_WALK[ 7]= 0
WRONG_WAY_PARITY_WALK[ 8]= 0
WRONG_WAY_PARITY_WALK[ 9]= 0
WRONG_WAY_PARITY_WALK[10]= 0
WRONG_WAY_PARITY_WALK[11]= 0
WRONG_WAY_PARITY_WALK[12]= 0
# Number of backtracks due to parity constraint when N pieces were left to be placed:
PARITY_BACKTRACK[ 1]= 0
PARITY_BACKTRACK[ 2]= 0
PARITY_BACKTRACK[ 3]= 0
PARITY_BACKTRACK[ 4]= 0
PARITY_BACKTRACK[ 5]= 0
PARITY_BACKTRACK[ 6]= 0
PARITY_BACKTRACK[ 7]= 0
PARITY_BACKTRACK[ 8]= 0
PARITY_BACKTRACK[ 9]= 0
PARITY_BACKTRACK[10]= 0
PARITY_BACKTRACK[11]= 0
PARITY_BACKTRACK[12]= 0
# Number of backtracks due to volume constraint when N pieces were left to be placed:
VOLUME_BACKTRACK[ 1]= 0
VOLUME_BACKTRACK[ 2]= 0
VOLUME_BACKTRACK[ 3]= 0
VOLUME_BACKTRACK[ 4]= 0
VOLUME_BACKTRACK[ 5]= 0
VOLUME_BACKTRACK[ 6]= 0
VOLUME_BACKTRACK[ 7]= 0
VOLUME_BACKTRACK[ 8]= 0
VOLUME_BACKTRACK[ 9]= 0
VOLUME_BACKTRACK[10]= 0
VOLUME_BACKTRACK[11]= 0
VOLUME_BACKTRACK[12]= 0
# Number of filters due to parity constraint when N pieces were left to be placed:
PARITY_FILTER[ 1]= 0
PARITY_FILTER[ 2]= 0
PARITY_FILTER[ 3]= 0
PARITY_FILTER[ 4]= 0
PARITY_FILTER[ 5]= 0
PARITY_FILTER[ 6]= 0
PARITY_FILTER[ 7]= 0
PARITY_FILTER[ 8]= 0
PARITY_FILTER[ 9]= 0
PARITY_FILTER[10]= 0
PARITY_FILTER[11]= 0
PARITY_FILTER[12]= 0
# Number of filters due to fit constraint when N pieces were left to be placed:
FIT_FILTER[ 1]= 0
FIT_FILTER[ 2]= 0
FIT_FILTER[ 3]= 0
FIT_FILTER[ 4]= 0
FIT_FILTER[ 5]= 0
FIT_FILTER[ 6]= 0
FIT_FILTER[ 7]= 0
FIT_FILTER[ 8]= 0
FIT_FILTER[ 9]= 0
FIT_FILTER[10]= 0
FIT_FILTER[11]= 0
FIT_FILTER[12]= 0
# Number of filters due to volume constraint when N pieces were left to be placed:
VOLUME_FILTER[ 1]= 0
VOLUME_FILTER[ 2]= 0
VOLUME_FILTER[ 3]= 0
VOLUME_FILTER[ 4]= 0
VOLUME_FILTER[ 5]= 0
VOLUME_FILTER[ 6]= 0
VOLUME_FILTER[ 7]= 0
VOLUME_FILTER[ 8]= 0
VOLUME_FILTER[ 9]= 0
VOLUME_FILTER[10]= 0
VOLUME_FILTER[11]= 0
VOLUME_FILTER[12]= 125
# Number of placement attempts when N pieces were left to be placed:
ATTEMPTS[ 1]= 78883
ATTEMPTS[ 2]= 1346664
ATTEMPTS[ 3]= 2551252
ATTEMPTS[ 4]= 1775873
ATTEMPTS[ 5]= 660506
ATTEMPTS[ 6]= 196017
ATTEMPTS[ 7]= 80724
ATTEMPTS[ 8]= 62568
ATTEMPTS[ 9]= 19118
ATTEMPTS[10]= 2358
ATTEMPTS[11]= 131
ATTEMPTS[12]= 7
# Number of fits when N pieces were left to be placed:
FITS[ 1]= 2339
FITS[ 2]= 302256
FITS[ 3]= 760374
FITS[ 4]= 617667
FITS[ 5]= 272072
FITS[ 6]= 82406
FITS[ 7]= 26950
FITS[ 8]= 17275
FITS[ 9]= 7994
FITS[10]= 1744
FITS[11]= 131
FITS[12]= 7
NAME : TOTAL TIME : PERCENTAGE : NUM EVENTS : AVG TIME
_______________________________________________________________________________________________________________________________
all : 0.197411 : * : 1: 0.197
parsing : 0.000550 : 0.279% : 1: 0.001
puzzleInit : 0.000790 : 0.400% : 1: 0.001
solve : 0.195728 : 99.147% : 1: 0.196
solveInit : 0.011655 : 5.955% : 1: 0.012
genImageLists : 0.010767 : 92.381% : 1: 0.011
dlxLoad : 0.000330 : 2.831% : 1: 0.000
solveAlgo : 0.183781 : 93.896% : 1: 0.184
solveFilter : 0.001312 : 0.714% : 1: 0.001
fila : 0.182165 : 99.121% : 7: 0.026
filaInit : 0.001145 : 0.629% : 7: 0.000
filaLoad : 0.000974: 85.066%: 7: 0.000
filaAlgo : 0.180946 : 99.331% : 7: 0.026
filaCleanup : 0.000073 : 0.040% : 7: 0.000
solveCleanup : 0.000283 : 0.145% : 1: 0.000
puzzleCleanup : 0.000134 : 0.068% : 1: 0.000
# Program stop time
STOP_TIME=06/Jan/2019 13:24:24 MST
_______________________________________________________________________________
BUGS
There are no known bugs.
Please send bug reports and/or build problems to my email address given below.
_______________________________________________________________________________
AUTHOR: Matthew T Busche
EMAIL: mtbusche AT gmail.com
ADDRESS: 8813 W Iliff Ave
Lakewood, CO 80227
USA