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