Generated on Mon Jul 6 18:09:01 2009 for Gecode by doxygen 1.5.9

black-hole.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Mikael Lagerkvist, 2006
00008  *
00009  *  Last modified:
00010  *     $Date: 2009-04-02 20:58:46 +0200 (Thu, 02 Apr 2009) $ by $Author: schulte $
00011  *     $Revision: 8649 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <gecode/driver.hh>
00039 #include <gecode/int.hh>
00040 
00041 #include <vector>
00042 #include <algorithm>
00043 #include <sstream>
00044 
00045 using namespace Gecode;
00046 
00047 namespace {
00048   using std::vector;
00049 
00051   vector<vector<int> > layout;
00053   vector<int> layer, pile;
00054 
00061   void generate(int seed) {
00062     // The layout consists of 17 piles of 3 cards each
00063     layout = vector<vector<int> >(17, vector<int>(3));
00064     // Deck without the Ace of Spades
00065     vector<int> deck(51);
00066     for (int i = 51; i--; ) deck[i] = i+1;
00067     Support::RandomGenerator rnd(seed+1);
00068     std::random_shuffle(deck.begin(), deck.end(), rnd);
00069 
00070     // Place cards from deck
00071     int pos = 0;
00072     for (int i = 17; i--; )
00073       for (int j = 3; j--; )
00074         layout[i][j] = deck[pos++];
00075 
00076     // Location-information for each card
00077     layer = vector<int>(52);
00078     pile  = vector<int>(52);
00079     for (int i = 17; i--; ) {
00080       for (int j = 3; j--; ) {
00081         layer[layout[i][j]] = j;
00082         pile[ layout[i][j]] = i;
00083       }
00084     }
00085   }
00086 }
00087 
00088 
00089 
00098 class BlackHoleBranch : Branching {
00100   ViewArray<Int::IntView> x;
00102   mutable int pos, val;
00104   class Description : public BranchingDesc {
00105   public:
00107     int pos;
00109     int val;
00113     Description(const Branching& b, unsigned int a, int pos0, int val0)
00114       : BranchingDesc(b,a), pos(pos0), val(val0) {}
00116     virtual size_t size(void) const {
00117       return sizeof(Description);
00118     }
00119   };
00120 
00122   BlackHoleBranch(Space& home, ViewArray<Int::IntView>& xv)
00123     : Branching(home), x(xv), pos(-1), val(-1) {}
00125   BlackHoleBranch(Space& home, bool share, BlackHoleBranch& b)
00126     : Branching(home, share, b), pos(b.pos), val(b.val) {
00127     x.update(home, share, b.x);
00128   }
00129 
00130 public:
00132   virtual bool status(const Space&) const {
00133     for (pos = 0; pos < x.size(); ++pos) {
00134       if (!x[pos].assigned()) {
00135         int w = 4;
00136         for (Int::ViewValues<Int::IntView> vals(x[pos]); vals(); ++vals) {
00137           if (layer[vals.val()] < w) {
00138             val = vals.val();
00139             if ((w = layer[vals.val()]) == 0) break;
00140           }
00141         }
00142         return true;
00143       }
00144     }
00145     // No non-assigned variables left
00146     return false;
00147   }
00149   virtual BranchingDesc* description(Space&) {
00150     assert(pos >= 0 && pos < x.size() && val >= 1 && val < 52);
00151     return new Description(*this, 2, pos, val);
00152   }
00154   virtual ExecStatus commit(Space& home, const BranchingDesc& d,
00155                             unsigned int a) {
00156     const Description& desc =
00157       static_cast<const Description&>(d);
00158     pos = val = -1;
00159     if (a)
00160       return me_failed(x[desc.pos].nq(home, desc.val))
00161         ? ES_FAILED : ES_OK;
00162     else
00163       return me_failed(x[desc.pos].eq(home, desc.val))
00164         ? ES_FAILED : ES_OK;
00165   }
00167   virtual Actor* copy(Space& home, bool share) {
00168     return new (home) BlackHoleBranch(home, share, *this);
00169   }
00171   static void post(Space& home, IntVarArgs x) {
00172     ViewArray<Int::IntView> xv(home, x);
00173     (void) new (home) BlackHoleBranch(home, xv);
00174   }
00175 };
00176 
00177 
00194 class BlackHole : public Script {
00195 protected:
00196   IntVarArray x, 
00197     y; 
00198 
00200   std::string
00201   card(int val) const {
00202     const char* suit = "SCHD";
00203     std::ostringstream o;
00204     o << std::setw(2) << (1 + (val%13)) << suit[val/13];
00205     return o.str();
00206   }
00207 
00208 public:
00210   enum {
00211     MODEL_NONE,    
00212     MODEL_SYMMETRY 
00213   };
00215   enum {
00216     PROPAGATION_REIFIED,  
00217     PROPAGATION_DFA,      
00218     PROPAGATION_TUPLE_SET 
00219   };
00221   BlackHole(const SizeOptions& opt)
00222     : x(*this, 52, 0,51), y(*this, 52, 0,51)
00223   {
00224     // Black ace at bottom
00225     rel(*this, x[0], IRT_EQ, 0);
00226 
00227     // x is order and y is placement
00228     channel(*this, x, y, opt.icl());
00229 
00230     // The placement rules: the absolute value of the difference
00231     // between two consecutive cards is 1 or 12.
00232     if (opt.propagation() == PROPAGATION_REIFIED) {
00233       // Build table for accessing the rank of a card
00234       IntArgs modtable(52);
00235       for (int i = 0; i < 52; ++i) {
00236         modtable[i] = i%13;
00237       }
00238       for (int i = 0; i < 51; ++i) {
00239         IntVar x1(*this, 0, 12), x2(*this, 0, 12);
00240         element(*this, modtable, x[i], x1);
00241         element(*this, modtable, x[i+1], x2);
00242         const int dr[2] = {1, 12};
00243         IntVar diff(*this, IntSet(dr, 2));
00244         post(*this, abs(*this, minus(*this, x1, x2, ICL_DOM), ICL_DOM)
00245              == diff, ICL_DOM);
00246       }
00247     } else if (opt.propagation() == PROPAGATION_DFA) {
00248       // Build table for allowed tuples
00249       REG expression;
00250       for (int r = 13; r--; ) {
00251         for (int s1 = 4; s1--; ) {
00252           for (int s2 = 4; s2--; ) {
00253             for (int i = -1; i <= 1; i+=2) {
00254               REG r1 = REG(r+13*s1);
00255               REG r2 = REG((r+i+52+13*s2)%52);
00256               REG r = r1 + r2;
00257               expression |= r;
00258             }
00259           }
00260         }
00261       }
00262       DFA table(expression);
00263 
00264       for (int i = 51; i--; ) {
00265         IntVarArgs iva(2);
00266         iva[0] = x[i]; iva[1] = x[i+1];
00267         extensional(*this, iva, table);
00268       }
00269 
00270     } else { // opt.propagation() == PROPAGATION_TUPLE_SET)
00271       // Build table for allowed tuples
00272       TupleSet tupleSet;
00273       for (int r = 13; r--; )
00274         for (int s1 = 4; s1--; )
00275           for (int s2 = 4; s2--; )
00276             for (int i = -1; i <= 1; i+=2) {
00277               IntArgs t(2);
00278               t[0] = r+13*s1;
00279               t[1] = (r+i+52+13*s2)%52;
00280               tupleSet.add(t);
00281             }
00282       tupleSet.finalize();
00283       for (int i = 51; i--; ) {
00284         IntVarArgs iva(2);
00285         iva[0] = x[i]; iva[1] = x[i+1];
00286         extensional(*this, iva, tupleSet, EPK_DEF, ICL_DOM);
00287       }
00288     }
00289     // A card must be played before the one under it.
00290     for (int i = 17; i--; )
00291       for (int j = 2; j--; )
00292         post(*this, y[layout[i][j]] < y[layout[i][j+1]]);
00293 
00294     // Compute and break the conditional symmetries that are dependent
00295     // on the current layout.
00296     if (opt.model() == MODEL_SYMMETRY) {
00297       // For all ranks
00298       for (int r = 13; r--; ) {
00299         // For all pairs of suits
00300         for (int s1 = 4; s1--; ) {
00301           for (int s2 = s1; s2--; ) {
00302             int c1 = 13*s1 + r,
00303               c2 = 13*s2 + r;
00304             // The ace of spades is already placed
00305             if (c1 == 0 || c2 == 0) continue;
00306             // Piles are handled by the rules of the game
00307             if (pile[c1] == pile[c2]) continue;
00308             // Get the right order of the cards
00309             int o1 = c1, o2 = c2;
00310             if (pile[c1] > pile[c2] && layer[c2] >= layer[c1])
00311               std::swap(o1, o2);
00312             // cond is the condition for the symmetry
00313             BoolVarArgs ba(4);
00314             int pos = 0;
00315             // Both cards played after the ones on top of them
00316             for (int i = 0; i < layer[o1]; ++i)
00317               ba[pos++] = post(*this, ~(y[layout[pile[o1]][i]] < y[o2]));
00318             for (int i = 0; i < layer[o2]; ++i)
00319               ba[pos++] = post(*this, ~(y[layout[pile[o2]][i]] < y[o1]));
00320             // Both cards played before the ones under them
00321             for (int i = layer[o1]+1; i < 3; ++i)
00322               ba[pos++] = post(*this, ~(y[o2] < y[layout[pile[o1]][i]]));
00323             for (int i = layer[o2]+1; i < 3; ++i)
00324               ba[pos++] = post(*this, ~(y[o1] < y[layout[pile[o2]][i]]));
00325             // Cond holds when all the above holds
00326             BoolVar cond(*this, 0, 1);
00327             rel(*this, BOT_AND, ba, cond);
00328 
00329             // If cond is fulfilled, then we can order the cards
00330             // cond -> (y[o1] < y[o2])
00331             post(*this, tt(!cond || ~(y[o1] < y[o2])));
00332           }
00333         }
00334       }
00335     }
00336 
00337     // Install custom branching
00338     BlackHoleBranch::post(*this, x);
00339   }
00340 
00342   virtual void
00343   print(std::ostream& os) const {
00344     os << "Layout:" << std::endl;
00345     for (int i = 0; i < 17; i++) {
00346       for (int j = 0; j < 3; j++)
00347         os << card(layout[i][j]) << " ";
00348       if ((i+1) % 3 == 0)
00349         os << std::endl;
00350       else
00351         os << "  \t";
00352     }
00353     os << std::endl << std::endl;
00354 
00355     os << "Solution:" << std::endl;
00356     for (int i = 0; i < 52; ++i) {
00357       if (x[i].assigned())
00358         os << card(x[i].val()) << " ";
00359       else
00360         os << "   ";
00361       if ((i + 1) % 13 == 0)
00362         os << std::endl;
00363     }
00364     os << std::endl;
00365     os << std::endl;
00366   }
00367 
00369   BlackHole(bool share, BlackHole& s) : Script(share,s) {
00370     x.update(*this, share, s.x);
00371     y.update(*this, share, s.y);
00372   }
00374   virtual Space*
00375   copy(bool share) {
00376     return new BlackHole(share,*this);
00377   }
00378 };
00379 
00383 int
00384 main(int argc, char* argv[]) {
00385   SizeOptions opt("Black Hole patience");
00386   opt.model(BlackHole::MODEL_SYMMETRY);
00387   opt.model(BlackHole::MODEL_NONE,"none");
00388   opt.model(BlackHole::MODEL_SYMMETRY,"symmetry");
00389   opt.propagation(BlackHole::PROPAGATION_DFA);
00390   opt.propagation(BlackHole::PROPAGATION_REIFIED,
00391                   "reified", "use reified propagation");
00392   opt.propagation(BlackHole::PROPAGATION_DFA,
00393                   "dfa", "use DFA-based extensional propagation");
00394   opt.propagation(BlackHole::PROPAGATION_TUPLE_SET,
00395                   "tuple-set", "use TupleSet-based extensional propagation");
00396   opt.icl(ICL_DOM);
00397   opt.parse(argc,argv);
00398   // Generates the new board
00399   generate(opt.size());
00400   Script::run<BlackHole,DFS,SizeOptions>(opt);
00401   return 0;
00402 }
00403 
00404 // STATISTICS: example-any