00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <gecode/driver.hh>
00039 #include <gecode/int.hh>
00040 #include <gecode/minimodel.hh>
00041
00042 using namespace Gecode;
00043
00052 class TileSpec {
00053 public:
00054 int width;
00055 int height;
00056 int amount;
00057 const char *tile;
00058 };
00059
00068 extern const TileSpec *examples[];
00073 extern const int examples_size[];
00078 extern const unsigned int n_examples;
00079
00080 namespace {
00093 int pos(int h, int w, int h1, int w1);
00095 typedef void (*tsymmfunc)(const char*, int, int, char*, int&, int&);
00097 typedef void (*bsymmfunc)(const IntVarArgs, int, int, IntVarArgs&, int&, int&);
00099 template<class CArray, class Array>
00100 void id(CArray t1, int w1, int h1, Array t2, int& w2, int&h2);
00102 template<class CArray, class Array>
00103 void rot90(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00105 template<class CArray, class Array>
00106 void rot180(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00108 template<class CArray, class Array>
00109 void rot270(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00111 template<class CArray, class Array>
00112 void flipx(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00114 template<class CArray, class Array>
00115 void flipy(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00117 template<class CArray, class Array>
00118 void flipd1(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00120 template<class CArray, class Array>
00121 void flipd2(CArray t1, int w1, int h1, Array t2, int& w2, int& h2);
00123 }
00124
00261 class Pentominoes : public Script {
00262 public:
00264 enum {
00265 PROPAGATION_INT,
00266 PROPAGATION_BOOLEAN,
00267 };
00269 enum {
00270 SYMMETRY_NONE,
00271 SYMMETRY_FULL,
00272 };
00273 private:
00275 const TileSpec *spec;
00277 int width, height;
00279 bool filled;
00281 int nspecs;
00283 int ntiles;
00284
00286 IntVarArray board;
00287
00289 int compute_number_of_tiles(const TileSpec* ts, int nspecs) {
00290 int res = 0;
00291 for (int i = nspecs; i--; ) {
00292 res += ts[i].amount;
00293 }
00294 return res;
00295 }
00296
00299 REG tile_reg(int twidth, int theight, const char* tile,
00300 REG mark, REG other, REG eol) {
00301 REG oe = other | eol;
00302 REG res = *oe;
00303 REG color[] = {other, mark};
00304 for (int h = 0; h < theight; ++h) {
00305 for (int w = 0; w < twidth; ++w) {
00306 int which = tile[h*twidth + w] == 'X';
00307 res += color[which];
00308 }
00309 if (h < theight-1) {
00310 res += oe(width-twidth, width-twidth);
00311 }
00312 }
00313 res += *oe + oe;
00314 return res;
00315 }
00316
00319 REG get_constraint(int t, REG mark, REG other, REG eol) {
00320
00321 REG res;
00322 char *t2 = new char[width*height];
00323 int w2, h2;
00324 tsymmfunc syms[] = {id, flipx, flipy, flipd1, flipd2, rot90, rot180, rot270};
00325 int symscnt = sizeof(syms)/sizeof(tsymmfunc);
00326 for (int i = 0; i < symscnt; ++i) {
00327 syms[i](spec[t].tile, spec[t].width, spec[t].height, t2, w2, h2);
00328 res = res | tile_reg(w2, h2, t2, mark, other, eol);
00329 }
00330 delete [] t2;
00331
00332 return res;
00333 }
00334
00335
00336 public:
00338 Pentominoes(const SizeOptions& opt)
00339 : Script(opt), spec(examples[opt.size()]),
00340 width(spec[0].width+1),
00341 height(spec[0].height),
00342 filled(spec[0].amount),
00343 nspecs(examples_size[opt.size()]-1),
00344 ntiles(compute_number_of_tiles(spec+1, nspecs)),
00345 board(*this, width*height, filled,ntiles+1) {
00346 spec += 1;
00347
00348
00349 for (int h = 0; h < height; ++h) {
00350 for (int w = 0; w < width-1; ++w)
00351 rel(*this, board[h*width + w], IRT_NQ, ntiles+1);
00352 rel(*this, board[h*width + width - 1], IRT_EQ, ntiles+1);
00353 }
00354
00355
00356 if (opt.propagation() == PROPAGATION_INT) {
00357 int tile = 0;
00358 for (int i = 0; i < nspecs; ++i) {
00359 for (int j = 0; j < spec[i].amount; ++j) {
00360
00361 int col = tile+1;
00362
00363 REG mark(col);
00364
00365 REG other;
00366 bool first = true;
00367 for (int j = filled; j <= ntiles; ++j) {
00368 if (j == col) continue;
00369 if (first) {
00370 other = REG(j);
00371 first = false;
00372 } else {
00373 other |= REG(j);
00374 }
00375 }
00376
00377 REG eol(ntiles+1);
00378 extensional(*this, board, get_constraint(i, mark, other, eol));
00379 ++tile;
00380 }
00381 }
00382 } else {
00383 int ncolors = ntiles + 2;
00384
00385 BoolVarArgs p(*this,ncolors * board.size(),0,1);
00386
00387
00388 for (int i=board.size(); i--; ) {
00389 BoolVarArgs c(ncolors);
00390 for (int j=ncolors; j--; )
00391 c[j]=p[i*ncolors+j];
00392 channel(*this, c, board[i]);
00393 }
00394
00395
00396
00397
00398 REG other(0), mark(1);
00399 int tile = 0;
00400 for (int i = 0; i < nspecs; ++i) {
00401 for (int j = 0; j < spec[i].amount; ++j) {
00402 int col = tile+1;
00403
00404 BoolVarArgs c(board.size());
00405
00406 for (int k = board.size(); k--; ) {
00407 c[k] = p[k*ncolors+col];
00408 }
00409
00410 extensional(*this, c, get_constraint(i, mark, other, other));
00411 ++tile;
00412 }
00413 }
00414 }
00415
00416 if (opt.symmetry() == SYMMETRY_FULL) {
00417
00418 IntVarArgs orig(board.size()-height), symm(board.size()-height);
00419 int pos = 0;
00420 for (int i = 0; i < board.size(); ++i) {
00421 if ((i+1)%width==0) continue;
00422 orig[pos++] = board[i];
00423 }
00424
00425 int w2, h2;
00426 bsymmfunc syms[] = {flipx, flipy, flipd1, flipd2, rot90, rot180, rot270};
00427 int symscnt = sizeof(syms)/sizeof(bsymmfunc);
00428 for (int i = 0; i < symscnt; ++i) {
00429 syms[i](orig, width-1, height, symm, w2, h2);
00430 if (width-1 == w2 && height == h2)
00431 rel(*this, orig, IRT_LQ, symm);
00432 }
00433 }
00434
00435
00436 branch(*this, board, INT_VAR_NONE(), INT_VAL_MIN());
00437 }
00438
00440 Pentominoes(Pentominoes& s) :
00441 Script(s), spec(s.spec), width(s.width), height(s.height),
00442 filled(s.filled), nspecs(s.nspecs) {
00443 board.update(*this, s.board);
00444 }
00445
00447 virtual Space*
00448 copy(void) {
00449 return new Pentominoes(*this);
00450 }
00451
00453 virtual void
00454 print(std::ostream& os) const {
00455 for (int h = 0; h < height; ++h) {
00456 os << "\t";
00457 for (int w = 0; w < width-1; ++w) {
00458 int val = board[h*width + w].val();
00459 char c = val < 10 ? '0'+val : 'A' + (val-10);
00460 os << c;
00461 }
00462 os << std::endl;
00463 }
00464 os << std::endl;
00465 }
00466 };
00467
00468
00472 int
00473 main(int argc, char* argv[]) {
00474 SizeOptions opt("Pentominoes");
00475 opt.size(1);
00476 opt.symmetry(Pentominoes::SYMMETRY_FULL);
00477 opt.symmetry(Pentominoes::SYMMETRY_NONE,
00478 "none", "do not remove symmetric solutions");
00479 opt.symmetry(Pentominoes::SYMMETRY_FULL,
00480 "full", "remove symmetric solutions");
00481
00482 opt.propagation(Pentominoes::PROPAGATION_BOOLEAN);
00483 opt.propagation(Pentominoes::PROPAGATION_INT,
00484 "int", "use integer propagators");
00485 opt.propagation(Pentominoes::PROPAGATION_BOOLEAN,
00486 "bool", "use Boolean propagators");
00487
00488 opt.parse(argc,argv);
00489 if (opt.size() >= n_examples) {
00490 std::cerr << "Error: size must be between 0 and "
00491 << n_examples-1 << std::endl;
00492 return 1;
00493 }
00494 Script::run<Pentominoes,DFS,SizeOptions>(opt);
00495 return 0;
00496 }
00497
00498
00504
00505 static const TileSpec puzzle0[] =
00506 {
00507
00508 {4, 4, true, ""},
00509 {2, 3, 1,
00510 "XX"
00511 "X "
00512 "X "},
00513 {2, 1, 1,
00514 "XX"},
00515 {3, 3, 1,
00516 " XX"
00517 " X"
00518 "XXX"},
00519 {1, 1, 1,
00520 "X"},
00521 {3, 1, 1,
00522 "XXX"}
00523 };
00525 static const TileSpec puzzle1[] =
00526 {
00527
00528 {8, 8, true, ""},
00529 {3, 3, 1,
00530 "XXX"
00531 "XXX"
00532 "XX "},
00533 {5, 3, 1,
00534 " XXX"
00535 " X "
00536 "XXX "},
00537 {3, 4, 1,
00538 "XXX"
00539 "XXX"
00540 " X"
00541 " X"},
00542 {3, 4, 1,
00543 "XXX"
00544 " X"
00545 " X"
00546 " X"},
00547 {2, 5, 1,
00548 " X"
00549 " X"
00550 " X"
00551 "XX"
00552 "XX"},
00553 {4, 2, 1,
00554 "XX "
00555 "XXXX"},
00556 {3, 3, 1,
00557 "XXX"
00558 " X"
00559 " X"},
00560 {2, 3, 1,
00561 "XX"
00562 "X "
00563 "X "},
00564 {2, 4, 1,
00565 "XX"
00566 "XX"
00567 "XX"
00568 "XX"},
00569 {3, 2, 1,
00570 "XX "
00571 "XXX"}
00572 };
00573
00574
00575 static const TileSpec square2[] =
00576 {
00577
00578 {10, 10, true, ""},
00579 {6, 6, 1,
00580 "XXXXXX"
00581 "XXXXXX"
00582 "XXXXXX"
00583 "XXXXXX"
00584 "XXXXXX"
00585 "XXXXXX"
00586 },
00587 {4, 4, 3,
00588 "XXXX"
00589 "XXXX"
00590 "XXXX"
00591 "XXXX"},
00592 {2, 2, 4,
00593 "XX"
00594 "XX"}
00595 };
00596
00597
00598 static const TileSpec square3[] =
00599 {
00600
00601 {20, 20, true, ""},
00602 {9, 9, 1,
00603 "XXXXXXXXX"
00604 "XXXXXXXXX"
00605 "XXXXXXXXX"
00606 "XXXXXXXXX"
00607 "XXXXXXXXX"
00608 "XXXXXXXXX"
00609 "XXXXXXXXX"
00610 "XXXXXXXXX"
00611 "XXXXXXXXX"
00612 },
00613 {8, 8, 2,
00614 "XXXXXXXX"
00615 "XXXXXXXX"
00616 "XXXXXXXX"
00617 "XXXXXXXX"
00618 "XXXXXXXX"
00619 "XXXXXXXX"
00620 "XXXXXXXX"
00621 "XXXXXXXX"
00622 },
00623 {7, 7, 1,
00624 "XXXXXXX"
00625 "XXXXXXX"
00626 "XXXXXXX"
00627 "XXXXXXX"
00628 "XXXXXXX"
00629 "XXXXXXX"
00630 "XXXXXXX"
00631 },
00632 {5, 5, 1,
00633 "XXXXX"
00634 "XXXXX"
00635 "XXXXX"
00636 "XXXXX"
00637 "XXXXX"
00638 },
00639 {4, 4, 5,
00640 "XXXX"
00641 "XXXX"
00642 "XXXX"
00643 "XXXX"},
00644 {3, 3, 3,
00645 "XXX"
00646 "XXX"
00647 "XXX"},
00648 {2, 2, 2,
00649 "XX"
00650 "XX"},
00651 {1, 1, 2,
00652 "X"}
00653 };
00654
00655 static const TileSpec pentomino6x10[] =
00656 {
00657
00658 {10, 6, true, ""},
00659 {2, 4, 1,
00660 "X "
00661 "X "
00662 "X "
00663 "XX"},
00664 {3,3, 1,
00665 "XX "
00666 " XX"
00667 " X "},
00668 {3,3, 1,
00669 "XXX"
00670 " X "
00671 " X "},
00672 {3,3, 1,
00673 " X"
00674 " XX"
00675 "XX "},
00676 {2,4, 1,
00677 " X"
00678 "XX"
00679 " X"
00680 " X"},
00681 {5,1, 1,
00682 "XXXXX"},
00683 {3,3, 1,
00684 "X "
00685 "XXX"
00686 " X"},
00687 {4,2, 1,
00688 " XXX"
00689 "XX "},
00690 {2,3, 1,
00691 "XX"
00692 "XX"
00693 " X"},
00694 {3,2, 1,
00695 "X X"
00696 "XXX"},
00697 {3,3, 1,
00698 " X "
00699 "XXX"
00700 " X "},
00701 {3,3, 1,
00702 " X"
00703 " X"
00704 "XXX"}
00705 };
00706
00707 static const TileSpec pentomino5x12[] =
00708 {
00709
00710 {12, 5, true, ""},
00711 {2, 4, 1,
00712 "X "
00713 "X "
00714 "X "
00715 "XX"},
00716 {3,3, 1,
00717 "XX "
00718 " XX"
00719 " X "},
00720 {3,3, 1,
00721 "XXX"
00722 " X "
00723 " X "},
00724 {3,3, 1,
00725 " X"
00726 " XX"
00727 "XX "},
00728 {2,4, 1,
00729 " X"
00730 "XX"
00731 " X"
00732 " X"},
00733 {5,1, 1,
00734 "XXXXX"},
00735 {3,3, 1,
00736 "X "
00737 "XXX"
00738 " X"},
00739 {4,2, 1,
00740 " XXX"
00741 "XX "},
00742 {2,3, 1,
00743 "XX"
00744 "XX"
00745 " X"},
00746 {3,2, 1,
00747 "X X"
00748 "XXX"},
00749 {3,3, 1,
00750 " X "
00751 "XXX"
00752 " X "},
00753 {3,3, 1,
00754 " X"
00755 " X"
00756 "XXX"}
00757 };
00758
00759 static const TileSpec pentomino4x15[] =
00760 {
00761
00762 {15, 4, true, ""},
00763 {2, 4, 1,
00764 "X "
00765 "X "
00766 "X "
00767 "XX"},
00768 {3,3, 1,
00769 "XX "
00770 " XX"
00771 " X "},
00772 {3,3, 1,
00773 "XXX"
00774 " X "
00775 " X "},
00776 {3,3, 1,
00777 " X"
00778 " XX"
00779 "XX "},
00780 {2,4, 1,
00781 " X"
00782 "XX"
00783 " X"
00784 " X"},
00785 {5,1, 1,
00786 "XXXXX"},
00787 {3,3, 1,
00788 "X "
00789 "XXX"
00790 " X"},
00791 {4,2, 1,
00792 " XXX"
00793 "XX "},
00794 {2,3, 1,
00795 "XX"
00796 "XX"
00797 " X"},
00798 {3,2, 1,
00799 "X X"
00800 "XXX"},
00801 {3,3, 1,
00802 " X "
00803 "XXX"
00804 " X "},
00805 {3,3, 1,
00806 " X"
00807 " X"
00808 "XXX"}
00809 };
00810
00811 static const TileSpec pentomino3x20[] =
00812 {
00813
00814 {20, 3, true, ""},
00815 {2, 4, 1,
00816 "X "
00817 "X "
00818 "X "
00819 "XX"},
00820 {3,3, 1,
00821 "XX "
00822 " XX"
00823 " X "},
00824 {3,3, 1,
00825 "XXX"
00826 " X "
00827 " X "},
00828 {3,3, 1,
00829 " X"
00830 " XX"
00831 "XX "},
00832 {2,4, 1,
00833 " X"
00834 "XX"
00835 " X"
00836 " X"},
00837 {5,1, 1,
00838 "XXXXX"},
00839 {3,3, 1,
00840 "X "
00841 "XXX"
00842 " X"},
00843 {4,2, 1,
00844 " XXX"
00845 "XX "},
00846 {2,3, 1,
00847 "XX"
00848 "XX"
00849 " X"},
00850 {3,2, 1,
00851 "X X"
00852 "XXX"},
00853 {3,3, 1,
00854 " X "
00855 "XXX"
00856 " X "},
00857 {3,3, 1,
00858 " X"
00859 " X"
00860 "XXX"}
00861 };
00862
00864 const TileSpec *examples[] = {puzzle0, puzzle1, square2, square3,
00865 pentomino6x10,pentomino5x12,
00866 pentomino4x15,pentomino3x20};
00867 const int examples_size[] = {sizeof(puzzle0)/sizeof(TileSpec),
00868 sizeof(puzzle1)/sizeof(TileSpec),
00869 sizeof(square2)/sizeof(TileSpec),
00870 sizeof(square3)/sizeof(TileSpec),
00871 sizeof(pentomino6x10)/sizeof(TileSpec),
00872 sizeof(pentomino5x12)/sizeof(TileSpec),
00873 sizeof(pentomino4x15)/sizeof(TileSpec),
00874 sizeof(pentomino3x20)/sizeof(TileSpec)};
00875
00877 const unsigned n_examples = sizeof(examples)/sizeof(TileSpec*);
00879
00880
00881 namespace {
00882 int pos(int h, int w, int h1, int w1) {
00883 if (!(0 <= h && h < h1) ||
00884 !(0 <= w && w < w1)) {
00885 std::cerr << "Cannot place (" << h << "," << w
00886 << ") on board of size " << h1 << "x" << w1 << std::endl;
00887 }
00888 return h * w1 + w;
00889 }
00890 template<class CArray, class Array>
00891 void id(CArray t1, int w1, int h1, Array t2, int& w2, int&h2) {
00892 w2 = w1; h2 = h1;
00893 for (int h = 0; h < h1; ++h)
00894 for (int w = 0; w < w1; ++w)
00895 t2[pos(h, w, h2, w2)] = t1[pos(h, w, h1, w1)];
00896 }
00897 template<class CArray, class Array>
00898 void rot90(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00899 w2 = h1; h2 = w1;
00900 for (int h = 0; h < h1; ++h)
00901 for (int w = 0; w < w1; ++w)
00902 t2[pos(w, w2-h-1, h2, w2)] = t1[pos(h, w, h1, w1)];
00903 }
00904 template<class CArray, class Array>
00905 void rot180(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00906 w2 = w1; h2 = h1;
00907 for (int h = 0; h < h1; ++h)
00908 for (int w = 0; w < w1; ++w)
00909 t2[pos(h2-h-1, w2-w-1, h2, w2)] = t1[pos(h, w, h1, w1)];
00910 }
00911 template<class CArray, class Array>
00912 void rot270(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00913 w2 = h1; h2 = w1;
00914 for (int h = 0; h < h1; ++h)
00915 for (int w = 0; w < w1; ++w)
00916 t2[pos(h2-w-1, h, h2, w2)] = t1[pos(h, w, h1, w1)];
00917 }
00918 template<class CArray, class Array>
00919 void flipx(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00920 w2 = w1; h2 = h1;
00921 for (int h = 0; h < h1; ++h)
00922 for (int w = 0; w < w1; ++w)
00923 t2[pos(h, w2-w-1, h2, w2)] = t1[pos(h, w, h1, w1)];
00924 }
00925 template<class CArray, class Array>
00926 void flipy(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00927 w2 = w1; h2 = h1;
00928 for (int h = 0; h < h1; ++h)
00929 for (int w = 0; w < w1; ++w)
00930 t2[pos(h2-h-1, w, h2, w2)] = t1[pos(h, w, h1, w1)];
00931 }
00932 template<class CArray, class Array>
00933 void flipd1(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00934 w2 = h1; h2 = w1;
00935 for (int h = 0; h < h1; ++h)
00936 for (int w = 0; w < w1; ++w)
00937 t2[pos(w, h, h2, w2)] = t1[pos(h, w, h1, w1)];
00938 }
00939 template<class CArray, class Array>
00940 void flipd2(CArray t1, int w1, int h1, Array t2, int& w2, int& h2) {
00941 w2 = h1; h2 = w1;
00942 for (int h = 0; h < h1; ++h)
00943 for (int w = 0; w < w1; ++w)
00944 t2[pos(h2-w-1, w2-h-1, h2, w2)] = t1[pos(h, w, h1, w1)];
00945 }
00946 }
00947
00948