1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /*
3  *  Main authors:
4  *     Mikael Lagerkvist <lagerkvist@gecode.org>
5  *
6  *  Contributing authors:
7  *     Guido Tack <tack@gecode.org>
8  *
9  *  Copyright:
10  *     Mikael Lagerkvist, 2006
11  *     Guido Tack, 2006
12  *
13  *  This file is part of Gecode, the generic constraint
14  *  development environment:
15  *     http://www.gecode.org
16  *
17  *  Permission is hereby granted, free of charge, to any person obtaining
18  *  a copy of this software and associated documentation files (the
19  *  "Software"), to deal in the Software without restriction, including
20  *  without limitation the rights to use, copy, modify, merge, publish,
21  *  distribute, sublicense, and/or sell copies of the Software, and to
22  *  permit persons to whom the Software is furnished to do so, subject to
23  *  the following conditions:
24  *
25  *  The above copyright notice and this permission notice shall be
26  *  included in all copies or substantial portions of the Software.
27  *
28  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35  *
36  */
37 
38 #include <gecode/driver.hh>
39 #include <gecode/int.hh>
40 #include <gecode/minimodel.hh>
41 
42 using namespace Gecode;
43 
44 /** \brief Specification of one tile
45  *
46  * This structure can be used to specify a tile with specified width
47  * and height, number of such tiles (all with unique values), and a
48  * char-array tile showing the tile in row-major order.
49  *
50  * \relates Pentominoes
51  */
52 class TileSpec {
53 public:
54   int width;  ///< Width of tile
55   int height; ///< Height of tile
56   int amount; ///< Number of tiles
57   const char *tile; ///< Picture of tile
58 };
59 
60 /** \brief Board specifications
61  *
62  * Each board specification repurposes the first two TileSpecs to
63  * record width and height of the board (TileSpec 0) as well as the
64  * number of tiles and whether the board is filled (TileSpec 1).
65  *
66  * \relates Pentominoes
67  */
68 extern const TileSpec *examples[];
69 /** \brief Board specification sizes
70  *
71  * \relates Pentominoes
72  */
73 extern const int examples_size[];
74 /** \brief Number of board specifications
75  *
76  * \relates Pentominoes
77  */
78 extern const unsigned int n_examples;
79 
80 namespace {
81   /** \name Symmetry functions
82    *
83    * These functions implement the 8 symmetries of 2D planes. The
84    * functions are templatized so that they can be used both for the
85    * pieces (defined using C-strings) and for arrays of variables.
86    *
87    * \relates Pentominoes
88    */
89   //@{
90   /** Return index of (\a h, \a w) in the row-major layout of a matrix with
91    * width \a w1 and height \a h1.
92    */
93   int pos(int h, int w, int h1, int w1);
94   /// Type for tile symmetry functions
95   typedef void (*tsymmfunc)(const char*, int, int, char*, int&, int&);
96   /// Type for board symmetry functions
97   typedef void (*bsymmfunc)(const IntVarArgs, int, int, IntVarArgs&, int&, int&);
98   /// Identity symmetry
99   template<class CArray, class Array>
100   void id(CArray t1, int w1, int h1, Array t2, int& w2, int&h2);
101   /// Rotate 90 degrees
102   template<class CArray, class Array>
103   void rot90(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
104   /// Rotate 180 degrees
105   template<class CArray, class Array>
106   void rot180(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
107   /// Rotate 270 degrees
108   template<class CArray, class Array>
109   void rot270(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
110   /// Flip x-wise
111   template<class CArray, class Array>
112   void flipx(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
113   /// Flip y-wise
114   template<class CArray, class Array>
115   void flipy(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
116   /// Flip diagonal 1
117   template<class CArray, class Array>
118   void flipd1(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
119   /// Flip diagonal 2
120   template<class CArray, class Array>
121   void flipd2(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
122   //@}
123 }
124 
125 /**
126  * \brief %Example: %Pentominoes
127  *
128  * \section ScriptPentominoesProblem The Problem
129  *
130  * This example places pieces of a puzzle, where each piece is
131  * composed of a collection of squares, onto a grid. The pieces may
132  * all be rotated and flipped freely. The goal is to place all the
133  * pieces on the grid, without any overlaps. An example piece to be
134  * placed looks like
135  * \code
136  *   XXX
137  *   X
138  * XXX
139  * \endcode
140  * in one of its rotations.
141  *
142  * The most famous instance of such a puzzle is the Pentominoes
143  * puzzle, where the pieces are all pieces formed by 5 four-connected
144  * squares.
145  *
146  *
147  * \section ScriptPentominoesVariables The Variables
148  *
149  * The variables for the model is the grid of squares that the  pieces
150  * are placed on, where each of the variables for the squares takes
151  * the value of the number of the piece which is placed overonto it.
152  *
153  *
154  * \section ScriptPentominoesOnePiece Placing one piece
155  *
156  * The constraint for each piece placement uses regular expressions
157  * (and consequently the extensional constraint) for expressing
158  * placement of (rotated) pieces on the grid. Consider the simple
159  * example of placing the piece
160  * \code
161  * XX
162  *  X
163  *  X
164  * \endcode
165  * onto the 4 by 4 board
166  * \code
167  * 0123
168  * 4567
169  * 89AB
170  * CDEF
171  * \endcode
172  *
173  * Let the variables 0-F be 0/1-variables indicating if the piece is
174  * placed on that position or not. First consider placing the piece on
175  * some location, say covering 1,2,6, and A. Then, writing the
176  * sequence of values for the variables 0-F out, we get the string
177  * 0110001000100000. This string and all other strings corresponding
178  * to placing the above piece in that particular rotation can be
179  * described using the regular expression \f$0^*11000100010^*\f$. The
180  * expression indicates that first comes some number of zeroes, then
181  * two ones in a row (covering places 1 and 2 in our example
182  * placement), then comes exactly three 0's (not covering places 3, 4,
183  * and 5), and so on. The variable number of 0's at the beginning and at the end
184  * makes the expression match any placement of the piece on the board.
185  *
186  * There is one problem with the above constraint, since it allows
187  * placing the piece covering places 3, 4, 8, and C. That is, the
188  * piece may wrap around the board. To prohibit this, we add a new
189  * dummy-column to the board, so that it looks like
190  * \code
191  * 0123G
192  * 4567H
193  * 89ABI
194  * CDEFJ
195  * \endcode
196  * The variables for places G to J are all set to zero initially, and the
197  * regular expression for  the placement of the piece is modified to
198  * include the extra column, \f$0^*1100001000010^*\f$.
199  *
200  *
201  * \section ScriptPentominoesRotatingPiece Rotating pieces
202  *
203  * To handle rotations of the piece, we can use disjunctions of
204  * regular expressions for all the relevant rotations. Consider the
205  * rotated version of the above piece, depicted below.
206  * \code
207  *   X
208  * XXX
209  * \endcode
210  * The corresponding regular expression for this piece is
211  * \f$0^*1001110^*\f$. To combine these two regular expressions, we
212  * can simply use disjunction of regular expressions, arriving at the
213  * expression \f$0^*1100001000010^*|0^*1001110^*\f$ for enforcing
214  * the placement of the piece in one of the above two rotations.
215  *
216  * There are 8 symmetries for the pieces in general. The 8 disjuncts
217  * for a particular piece might, however, contain less than 8 distinct
218  * expressions (for example, any square has only one distinct
219  * disjunct). This is removed when then automaton for the expression
220  * is computed, since it is minimized.
221  *
222  *
223  * \section ScriptPentominoesSeveral Placing several pieces
224  *
225  * To generalize the above model to several pieces, we let the
226  * variables range from 0 to n, where n is the number of pieces to
227  * place. Given that we place three pieces, and that the above shown
228  * piece is number one, we will replace each \f$0\f$-expression with
229  * the expression \f$(0|2|3)\f$. Thus, the second regular expression
230  * becomes \f$(0|2|3)^*1(0|2|3)(0|2|3)111(0|2|3)^*\f$. Additionaly,
231  * the end of line marker gets its own value.
232  *
233  * This generalization suffers from the fact that the automata become
234  * much more complex. This problem can be solved by instead
235  * projecting out each component, which gives a new board of
236  * 0/1-variables for each piece to place.
237  *
238  *
239  * \section ScriptPentominoesHeuristic The Branching
240  *
241  * This model does not use any advanced heuristic for the
242  * branching. The variables selection is simply in order, and the
243  * value selection is minimum value first.
244  *
245  * The static value selection allows us to order the pieces in the
246  * specification of the problem. The pieces are approximately ordered by
247  * largness or hardness to place.
248  *
249  *
250  * \section ScriptPentominoesSymmetries Removing board symmetries
251  *
252  * Especially when searching for all solutions of a puzzle instance,
253  * we might want to remove the symmetrical boards from the
254  * solutions-space. This is done using the same symmetry functions as
255  * for the piece symmetries and lexicographical order constraints.
256  *
257  *
258  * \ingroup Example
259  *
260  */
261 class Pentominoes : public Script {
262 public:
263   /// Choice of propagators
264   enum {
265     PROPAGATION_INT,       ///< Use integer propagators
266     PROPAGATION_BOOLEAN,   ///< Use Boolean propagators
267   };
268   /// Choice of symmetry breaking
269   enum {
270     SYMMETRY_NONE, ///< Do not remove symmetric solutions
271     SYMMETRY_FULL, ///< Remove symmetric solutions
272   };
273 private:
274   /// Specification of the tiles to place.
275   const TileSpec *spec;
276   /// Width and height of the board
277   int width, height;
278   /// Whether the board is filled or not
279   bool filled;
280   /// Number of specifications of tiles to place
281   int nspecs;
282   /// Number of tiles to place
283   int ntiles;
284 
285   /// The variables for the board.
286   IntVarArray board;
287 
288   /// Compute number of tiles
compute_number_of_tiles(const TileSpec * ts,int nspecs) const289   int compute_number_of_tiles(const TileSpec* ts, int nspecs) const {
290     int res = 0;
291     for (int i=0; i<nspecs; i++)
292       res += ts[i].amount;
293     return res;
294   }
295 
296   /// Returns the regular expression for placing a specific tile \a
297   /// tile in a specific rotation.
tile_reg(int twidth,int theight,const char * tile,REG mark,REG other,REG eol) const298   REG tile_reg(int twidth, int theight, const char* tile,
299                REG mark, REG other, REG eol) const {
300     REG oe = other | eol;
301     REG res = *oe;
302     REG color[] = {other, mark};
303     for (int h = 0; h < theight; ++h) {
304       for (int w = 0; w < twidth; ++w) {
305 	int which = tile[h*twidth + w] == 'X';
306 	res += color[which];
307       }
308       if (h < theight-1) {
309 	res += oe(width-twidth, width-twidth);
310       }
311     }
312     res += *oe + oe;
313     return res;
314   }
315 
316   /// Returns the regular expression for placing tile number \a t in
317   /// any rotation.
get_constraint(int t,REG mark,REG other,REG eol)318   REG get_constraint(int t, REG mark, REG other, REG eol) {
319     // This should be done for all rotations
320     REG res;
321     char *t2 = new char[width*height];
322     int w2, h2;
323     tsymmfunc syms[] = {id, flipx, flipy, flipd1, flipd2, rot90, rot180, rot270};
324     int symscnt = sizeof(syms)/sizeof(tsymmfunc);
325     for (int i = 0; i < symscnt; ++i) {
326       syms[i](spec[t].tile, spec[t].width, spec[t].height, t2, w2, h2);
327       res = res | tile_reg(w2, h2, t2, mark, other, eol);
328     }
329     delete [] t2;
330 
331     return res;
332   }
333 
334 
335 public:
336   /// Construction of the model.
Pentominoes(const SizeOptions & opt)337   Pentominoes(const SizeOptions& opt)
338     : Script(opt), spec(examples[opt.size()]),
339       width(spec[0].width+1), // Add one for extra row at end.
340       height(spec[0].height),
341       filled(spec[0].amount),
342       nspecs(examples_size[opt.size()]-1),
343       ntiles(compute_number_of_tiles(spec+1, nspecs)),
344       board(*this, width*height, filled,ntiles+1) {
345     spec += 1; // No need for the specification-part any longer
346 
347     // Set end-of-line markers
348     for (int h = 0; h < height; ++h) {
349       for (int w = 0; w < width-1; ++w)
350 	rel(*this, board[h*width + w], IRT_NQ, ntiles+1);
351       rel(*this, board[h*width + width - 1], IRT_EQ, ntiles+1);
352     }
353 
354     // Post constraints
355     if (opt.propagation() == PROPAGATION_INT) {
356       int tile = 0;
357       for (int i = 0; i < nspecs; ++i) {
358         for (int j = 0; j < spec[i].amount; ++j) {
359           // Color
360           int col = tile+1;
361           // Expression for color col
362           REG mark(col);
363           // Build expression for complement to color col
364           REG other;
365           bool first = true;
366           for (int j = filled; j <= ntiles; ++j) {
367             if (j == col) continue;
368             if (first) {
369               other = REG(j);
370               first = false;
371             } else {
372               other |= REG(j);
373             }
374           }
375           // End of line marker
376           REG eol(ntiles+1);
377           extensional(*this, board, get_constraint(i, mark, other, eol));
378           ++tile;
379         }
380       }
381     } else { // opt.propagation() == PROPAGATION_BOOLEAN
382       int ncolors = ntiles + 2;
383       // Boolean variables for channeling
384       BoolVarArgs p(*this,ncolors * board.size(),0,1);
385 
386       // Post channel constraints
387       for (int i=board.size(); i--; ) {
388         BoolVarArgs c(ncolors);
389         for (int j=ncolors; j--; )
390           c[j]=p[i*ncolors+j];
391         channel(*this, c, board[i]);
392       }
393 
394       // For placing tile i, we construct the expression over
395       // 0/1-variables and apply it to the projection of
396       // the board on the color for the tile.
397       REG other(0), mark(1);
398       int tile = 0;
399       for (int i = 0; i < nspecs; ++i) {
400         for (int j = 0; j < spec[i].amount; ++j) {
401           int col = tile+1;
402           // Projection for color col
403           BoolVarArgs c(board.size());
404 
405           for (int k = board.size(); k--; ) {
406             c[k] = p[k*ncolors+col];
407           }
408 
409           extensional(*this, c, get_constraint(i, mark, other, other));
410           ++tile;
411         }
412       }
413     }
414 
415     if (opt.symmetry() == SYMMETRY_FULL) {
416       // Remove symmetrical boards
417       IntVarArgs orig(board.size()-height), symm(board.size()-height);
418       int pos = 0;
419       for (int i = 0; i < board.size(); ++i) {
420         if ((i+1)%width==0) continue;
421         orig[pos++] = board[i];
422       }
423 
424       int w2, h2;
425       bsymmfunc syms[] = {flipx, flipy, flipd1, flipd2, rot90, rot180, rot270};
426       int symscnt = sizeof(syms)/sizeof(bsymmfunc);
427       for (int i = 0; i < symscnt; ++i) {
428         syms[i](orig, width-1, height, symm, w2, h2);
429         if (width-1 == w2 && height == h2)
430           rel(*this, orig, IRT_LQ, symm);
431       }
432     }
433 
434     // Install branching
435     branch(*this, board, INT_VAR_NONE(), INT_VAL_MIN());
436   }
437 
438   /// Constructor for cloning \a s
Pentominoes(Pentominoes & s)439   Pentominoes(Pentominoes& s) :
440     Script(s), spec(s.spec), width(s.width), height(s.height),
441     filled(s.filled), nspecs(s.nspecs) {
442     board.update(*this, s.board);
443   }
444 
445   /// Copy space during cloning
446   virtual Space*
copy(void)447   copy(void) {
448     return new Pentominoes(*this);
449   }
450 
451   /// Print solution
452   virtual void
print(std::ostream & os) const453   print(std::ostream& os) const {
454     for (int h = 0; h < height; ++h) {
455       os << "\t";
456       for (int w = 0; w < width-1; ++w) {
457         int val =  board[h*width + w].val();
458         char c = val < 10 ? '0'+val : 'A' + (val-10);
459         os << c;
460       }
461       os << std::endl;
462     }
463     os << std::endl;
464   }
465 };
466 
467 
468 /** \brief Main-function
469  *  \relates Pentominoes
470  */
471 int
main(int argc,char * argv[])472 main(int argc, char* argv[]) {
473   SizeOptions opt("Pentominoes");
474   opt.size(1);
475   opt.symmetry(Pentominoes::SYMMETRY_FULL);
476   opt.symmetry(Pentominoes::SYMMETRY_NONE,
477             "none", "do not remove symmetric solutions");
478   opt.symmetry(Pentominoes::SYMMETRY_FULL,
479             "full", "remove symmetric solutions");
480 
481   opt.propagation(Pentominoes::PROPAGATION_BOOLEAN);
482   opt.propagation(Pentominoes::PROPAGATION_INT,
483                   "int", "use integer propagators");
484   opt.propagation(Pentominoes::PROPAGATION_BOOLEAN,
485                   "bool", "use Boolean propagators");
486 
487   opt.parse(argc,argv);
488   if (opt.size() >= n_examples) {
489     std::cerr << "Error: size must be between 0 and "
490 	      << n_examples-1 << std::endl;
491     return 1;
492   }
493   Script::run<Pentominoes,DFS,SizeOptions>(opt);
494   return 0;
495 }
496 
497 
498 /** \name Puzzle specifications
499  *
500  * \relates Pentominoes
501  */
502 //@{
503 /// Small specification
504 static const TileSpec puzzle0[] =
505   {
506     // Width and height of board
507     {4, 4, true, ""},
508     {2, 3, 1,
509      "XX"
510      "X "
511      "X "},
512     {2, 1, 1,
513      "XX"},
514     {3, 3, 1,
515      " XX"
516      "  X"
517      "XXX"},
518     {1, 1, 1,
519      "X"},
520     {3, 1, 1,
521      "XXX"}
522   };
523 /// Standard specification
524 static const TileSpec puzzle1[] =
525   {
526     // Width and height of board
527     {8, 8, true, ""},
528     {3, 3, 1,
529      "XXX"
530      "XXX"
531      "XX "},
532     {5, 3, 1,
533      "  XXX"
534      "  X  "
535      "XXX  "},
536     {3, 4, 1,
537      "XXX"
538      "XXX"
539      "  X"
540      "  X"},
541     {3, 4, 1,
542      "XXX"
543      "  X"
544      "  X"
545      "  X"},
546     {2, 5, 1,
547      " X"
548      " X"
549      " X"
550      "XX"
551      "XX"},
552     {4, 2, 1,
553      "XX  "
554      "XXXX"},
555     {3, 3, 1,
556      "XXX"
557      "  X"
558      "  X"},
559     {2, 3, 1,
560      "XX"
561      "X "
562      "X "},
563     {2, 4, 1,
564      "XX"
565      "XX"
566      "XX"
567      "XX"},
568     {3, 2, 1,
569      "XX "
570      "XXX"}
571   };
572 
573 // Perfect square number 2 from examples/perfect-square.cc
574 static const TileSpec square2[] =
575   {
576     // Width and height of board
577     {10, 10, true, ""},
578     {6, 6, 1,
579      "XXXXXX"
580      "XXXXXX"
581      "XXXXXX"
582      "XXXXXX"
583      "XXXXXX"
584      "XXXXXX"
585     },
586     {4, 4, 3,
587      "XXXX"
588      "XXXX"
589      "XXXX"
590      "XXXX"},
591     {2, 2, 4,
592      "XX"
593      "XX"}
594   };
595 
596 // Perfect square number 3 from examples/perfect-square.cc
597 static const TileSpec square3[] =
598   {
599     // Width and height of board
600     {20, 20, true, ""},
601     {9, 9, 1,
602      "XXXXXXXXX"
603      "XXXXXXXXX"
604      "XXXXXXXXX"
605      "XXXXXXXXX"
606      "XXXXXXXXX"
607      "XXXXXXXXX"
608      "XXXXXXXXX"
609      "XXXXXXXXX"
610      "XXXXXXXXX"
611     },
612     {8, 8, 2,
613      "XXXXXXXX"
614      "XXXXXXXX"
615      "XXXXXXXX"
616      "XXXXXXXX"
617      "XXXXXXXX"
618      "XXXXXXXX"
619      "XXXXXXXX"
620      "XXXXXXXX"
621     },
622     {7, 7, 1,
623      "XXXXXXX"
624      "XXXXXXX"
625      "XXXXXXX"
626      "XXXXXXX"
627      "XXXXXXX"
628      "XXXXXXX"
629      "XXXXXXX"
630     },
631     {5, 5, 1,
632      "XXXXX"
633      "XXXXX"
634      "XXXXX"
635      "XXXXX"
636      "XXXXX"
637     },
638     {4, 4, 5,
639      "XXXX"
640      "XXXX"
641      "XXXX"
642      "XXXX"},
643     {3, 3, 3,
644      "XXX"
645      "XXX"
646      "XXX"},
647     {2, 2, 2,
648      "XX"
649      "XX"},
650     {1, 1, 2,
651      "X"}
652   };
653 
654 static const TileSpec pentomino6x10[] =
655   {
656     // Width and height of board
657     {10, 6, true, ""},
658     {2, 4, 1,
659      "X "
660      "X "
661      "X "
662      "XX"},
663     {3,3, 1,
664      "XX "
665      " XX"
666      " X "},
667     {3,3, 1,
668      "XXX"
669      " X "
670      " X "},
671     {3,3, 1,
672      "  X"
673      " XX"
674      "XX "},
675     {2,4, 1,
676      " X"
677      "XX"
678      " X"
679      " X"},
680     {5,1, 1,
681      "XXXXX"},
682     {3,3, 1,
683      "X  "
684      "XXX"
685      "  X"},
686     {4,2, 1,
687      " XXX"
688      "XX  "},
689     {2,3, 1,
690      "XX"
691      "XX"
692      " X"},
693     {3,2, 1,
694      "X X"
695      "XXX"},
696     {3,3, 1,
697      " X "
698      "XXX"
699      " X "},
700     {3,3, 1,
701      "  X"
702      "  X"
703      "XXX"}
704   };
705 
706 static const TileSpec pentomino5x12[] =
707   {
708     // Width and height of board
709     {12, 5, true, ""},
710     {2, 4, 1,
711      "X "
712      "X "
713      "X "
714      "XX"},
715     {3,3, 1,
716      "XX "
717      " XX"
718      " X "},
719     {3,3, 1,
720      "XXX"
721      " X "
722      " X "},
723     {3,3, 1,
724      "  X"
725      " XX"
726      "XX "},
727     {2,4, 1,
728      " X"
729      "XX"
730      " X"
731      " X"},
732     {5,1, 1,
733      "XXXXX"},
734     {3,3, 1,
735      "X  "
736      "XXX"
737      "  X"},
738     {4,2, 1,
739      " XXX"
740      "XX  "},
741     {2,3, 1,
742      "XX"
743      "XX"
744      " X"},
745     {3,2, 1,
746      "X X"
747      "XXX"},
748     {3,3, 1,
749      " X "
750      "XXX"
751      " X "},
752     {3,3, 1,
753      "  X"
754      "  X"
755      "XXX"}
756   };
757 
758 static const TileSpec pentomino4x15[] =
759   {
760     // Width and height of board
761     {15, 4, true, ""},
762     {2, 4, 1,
763      "X "
764      "X "
765      "X "
766      "XX"},
767     {3,3, 1,
768      "XX "
769      " XX"
770      " X "},
771     {3,3, 1,
772      "XXX"
773      " X "
774      " X "},
775     {3,3, 1,
776      "  X"
777      " XX"
778      "XX "},
779     {2,4, 1,
780      " X"
781      "XX"
782      " X"
783      " X"},
784     {5,1, 1,
785      "XXXXX"},
786     {3,3, 1,
787      "X  "
788      "XXX"
789      "  X"},
790     {4,2, 1,
791      " XXX"
792      "XX  "},
793     {2,3, 1,
794      "XX"
795      "XX"
796      " X"},
797     {3,2, 1,
798      "X X"
799      "XXX"},
800     {3,3, 1,
801      " X "
802      "XXX"
803      " X "},
804     {3,3, 1,
805      "  X"
806      "  X"
807      "XXX"}
808   };
809 
810 static const TileSpec pentomino3x20[] =
811   {
812     // Width and height of board
813     {20, 3, true, ""},
814     {2, 4, 1,
815      "X "
816      "X "
817      "X "
818      "XX"},
819     {3,3, 1,
820      "XX "
821      " XX"
822      " X "},
823     {3,3, 1,
824      "XXX"
825      " X "
826      " X "},
827     {3,3, 1,
828      "  X"
829      " XX"
830      "XX "},
831     {2,4, 1,
832      " X"
833      "XX"
834      " X"
835      " X"},
836     {5,1, 1,
837      "XXXXX"},
838     {3,3, 1,
839      "X  "
840      "XXX"
841      "  X"},
842     {4,2, 1,
843      " XXX"
844      "XX  "},
845     {2,3, 1,
846      "XX"
847      "XX"
848      " X"},
849     {3,2, 1,
850      "X X"
851      "XXX"},
852     {3,3, 1,
853      " X "
854      "XXX"
855      " X "},
856     {3,3, 1,
857      "  X"
858      "  X"
859      "XXX"}
860   };
861 
862 /// List of specifications
863 const TileSpec *examples[] = {puzzle0, puzzle1, square2, square3,
864                            pentomino6x10,pentomino5x12,
865                            pentomino4x15,pentomino3x20};
866 const int examples_size[] = {sizeof(puzzle0)/sizeof(TileSpec),
867                              sizeof(puzzle1)/sizeof(TileSpec),
868                              sizeof(square2)/sizeof(TileSpec),
869                              sizeof(square3)/sizeof(TileSpec),
870                              sizeof(pentomino6x10)/sizeof(TileSpec),
871                              sizeof(pentomino5x12)/sizeof(TileSpec),
872                              sizeof(pentomino4x15)/sizeof(TileSpec),
873                              sizeof(pentomino3x20)/sizeof(TileSpec)};
874 
875 /// Number of specifications
876 const unsigned n_examples = sizeof(examples)/sizeof(TileSpec*);
877 //@}
878 
879 // Symmetry functions
880 namespace {
pos(int h,int w,int h1,int w1)881   int pos(int h, int w, int h1, int w1) {
882     if (!(0 <= h && h < h1) ||
883         !(0 <= w && w < w1)) {
884       std::cerr << "Cannot place (" << h << "," << w
885                 << ") on board of size " << h1 << "x" << w1 << std::endl;
886     }
887     return h * w1 + w;
888   }
889   template<class CArray, class Array>
id(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)890   void id(CArray t1, int w1, int h1, Array t2, int& w2, int&h2) {
891     w2 = w1; h2 = h1;
892     for (int h = 0; h < h1; ++h)
893       for (int w = 0; w < w1; ++w)
894 	t2[pos(h, w, h2, w2)] = t1[pos(h, w, h1, w1)];
895   }
896   template<class CArray, class Array>
rot90(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)897   void rot90(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
898     w2 = h1; h2 = w1;
899     for (int h = 0; h < h1; ++h)
900       for (int w = 0; w < w1; ++w)
901 	t2[pos(w, w2-h-1, h2, w2)] = t1[pos(h, w, h1, w1)];
902   }
903   template<class CArray, class Array>
rot180(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)904   void rot180(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
905     w2 = w1; h2 = h1;
906     for (int h = 0; h < h1; ++h)
907       for (int w = 0; w < w1; ++w)
908 	t2[pos(h2-h-1, w2-w-1, h2, w2)] = t1[pos(h, w, h1, w1)];
909   }
910   template<class CArray, class Array>
rot270(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)911   void rot270(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
912     w2 = h1; h2 = w1;
913     for (int h = 0; h < h1; ++h)
914       for (int w = 0; w < w1; ++w)
915 	t2[pos(h2-w-1, h, h2, w2)] = t1[pos(h, w, h1, w1)];
916   }
917   template<class CArray, class Array>
flipx(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)918   void flipx(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
919     w2 = w1; h2 = h1;
920     for (int h = 0; h < h1; ++h)
921       for (int w = 0; w < w1; ++w)
922 	t2[pos(h, w2-w-1, h2, w2)] = t1[pos(h, w, h1, w1)];
923   }
924   template<class CArray, class Array>
flipy(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)925   void flipy(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
926     w2 = w1; h2 = h1;
927     for (int h = 0; h < h1; ++h)
928       for (int w = 0; w < w1; ++w)
929 	t2[pos(h2-h-1, w, h2, w2)] = t1[pos(h, w, h1, w1)];
930   }
931   template<class CArray, class Array>
flipd1(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)932   void flipd1(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
933     w2 = h1; h2 = w1;
934     for (int h = 0; h < h1; ++h)
935       for (int w = 0; w < w1; ++w)
936 	t2[pos(w, h, h2, w2)] = t1[pos(h, w, h1, w1)];
937   }
938   template<class CArray, class Array>
flipd2(CArray t1,int w1,int h1,Array t2,int & w2,int & h2)939   void flipd2(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
940     w2 = h1; h2 = w1;
941     for (int h = 0; h < h1; ++h)
942       for (int w = 0; w < w1; ++w)
943 	t2[pos(h2-w-1, w2-h-1, h2, w2)] = t1[pos(h, w, h1, w1)];
944   }
945 }
946 
947 // STATISTICS: example-any
948