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