Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

StoneBoard.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file StoneBoard.cpp
00003  */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "BoardUtils.hpp"
00007 #include "StoneBoard.hpp"
00008 
00009 using namespace benzene;
00010 
00011 //----------------------------------------------------------------------------
00012 
00013 StoneBoard::StoneBoard()
00014     : m_const(0),
00015       m_hash(0, 0)
00016 {
00017 }
00018 
00019 StoneBoard::StoneBoard(unsigned size)
00020     : m_const(&ConstBoard::Get(size)),
00021       m_hash(size, size)
00022 {
00023     StartNewGame();
00024 }
00025 
00026 StoneBoard::StoneBoard(unsigned width, unsigned height)
00027     : m_const(&ConstBoard::Get(width, height)),
00028       m_hash(width, height)
00029 {
00030     StartNewGame();
00031 }
00032 
00033 StoneBoard::StoneBoard(unsigned width, unsigned height, const std::string& str)
00034     : m_const(&ConstBoard::Get(width, height)),
00035       m_hash(width, height)
00036 {
00037     SetPosition(str);
00038 }
00039 
00040 StoneBoard::~StoneBoard()
00041 {
00042 }
00043 
00044 //----------------------------------------------------------------------------
00045 
00046 HexColor StoneBoard::GetColor(HexPoint cell) const
00047 {
00048     HexAssert(Const().IsValid(cell));
00049     if (IsBlack(cell)) return BLACK;
00050     if (IsWhite(cell)) return WHITE;
00051     return EMPTY;
00052 }
00053 
00054 bitset_t StoneBoard::GetLegal() const
00055 {
00056     bitset_t legal;
00057     if (IsPlayed(RESIGN)) 
00058         return legal;
00059     
00060     legal = ~GetPlayed() & Const().GetCells();
00061     legal.set(RESIGN);
00062     
00063     // Swap is available only when 4 edges and exactly
00064     // one cell have been played
00065     if (GetPlayed().count() == 5) 
00066     {
00067     HexAssert(!IsPlayed(SWAP_PIECES));
00068     HexAssert(GetColor(FIRST_TO_PLAY).count() >= 3);
00069     HexAssert((GetPlayed(FIRST_TO_PLAY)).count() == 3);
00070     HexAssert(GetColor(!FIRST_TO_PLAY).count() == 2);
00071     legal.set(SWAP_PIECES);
00072     }
00073     HexAssert(Const().IsValid(legal));
00074     return legal;
00075 }
00076 
00077 bool StoneBoard::IsLegal(HexPoint cell) const
00078 {
00079     HexAssert(Const().IsValid(cell));
00080     return GetLegal().test(cell);
00081 }
00082 
00083 BoardIterator StoneBoard::Stones(HexColorSet colorset) const
00084 {
00085     if (!m_stones_calculated) 
00086     {
00087         for (int i = 0; i < NUM_COLOR_SETS; ++i)
00088         {
00089             m_stones_list[i].clear();
00090             for (BoardIterator p(Const().EdgesAndInterior()); p; ++p) 
00091                 if (HexColorSetUtil::InSet(GetColor(*p), (HexColorSet)i))
00092                     m_stones_list[i].push_back(*p);
00093             m_stones_list[i].push_back(INVALID_POINT);
00094         }
00095         m_stones_calculated = true;
00096     }
00097     return BoardIterator(m_stones_list[colorset]);
00098 }
00099 
00100 //----------------------------------------------------------------------------
00101 
00102 void StoneBoard::MarkAsDirty()
00103 {
00104     m_stones_calculated = false;
00105 }
00106 
00107 void StoneBoard::AddColor(HexColor color, const bitset_t& b)
00108 {
00109     HexAssert(HexColorUtil::isBlackWhite(color));
00110     m_stones[color] |= b;
00111     HexAssert(IsBlackWhiteDisjoint());
00112     if (b.any()) MarkAsDirty();
00113 }
00114 
00115 void StoneBoard::RemoveColor(HexColor color, const bitset_t& b)
00116 {
00117     HexAssert(HexColorUtil::isBlackWhite(color));
00118     m_stones[color] = m_stones[color] - b;
00119     HexAssert(IsBlackWhiteDisjoint());
00120     if (b.any()) MarkAsDirty();
00121 }
00122 
00123 void StoneBoard::SetColor(HexColor color, HexPoint cell)
00124 {
00125     HexAssert(HexColorUtil::isValidColor(color));
00126     HexAssert(Const().IsValid(cell));
00127 
00128     if (color == EMPTY) {
00129     for (BWIterator it; it; ++it)
00130         m_stones[*it].reset(cell);
00131     } else {
00132         m_stones[color].set(cell);
00133         HexAssert(IsBlackWhiteDisjoint());
00134     }
00135 
00136     MarkAsDirty();
00137 }
00138 
00139 void StoneBoard::SetColor(HexColor color, const bitset_t& bs)
00140 {
00141     /** @todo Should we make this support EMPTY color too? */
00142     HexAssert(HexColorUtil::isBlackWhite(color));
00143     HexAssert(Const().IsValid(bs));
00144 
00145     m_stones[color] = bs;
00146     HexAssert(IsBlackWhiteDisjoint());
00147 
00148     MarkAsDirty();
00149 }
00150 
00151 void StoneBoard::SetPlayed(const bitset_t& played)
00152 {
00153     m_played = played;
00154     ComputeHash();
00155     MarkAsDirty();
00156 }
00157 
00158 //----------------------------------------------------------------------------
00159 
00160 void StoneBoard::ComputeHash()
00161 {
00162     // do not include swap in hash value
00163     bitset_t mask = m_played & Const().GetLocations();
00164     m_hash.Compute(m_stones[BLACK] & mask, m_stones[WHITE] & mask);
00165 }
00166 
00167 void StoneBoard::StartNewGame()
00168 {
00169     m_played.reset();
00170     for (BWIterator it; it; ++it) 
00171     {
00172         m_stones[*it].reset();
00173         PlayMove(*it, HexPointUtil::colorEdge1(*it));
00174         PlayMove(*it, HexPointUtil::colorEdge2(*it));
00175     }
00176     ComputeHash();
00177     MarkAsDirty();
00178 }
00179 
00180 void StoneBoard::PlayMove(HexColor color, HexPoint cell)
00181 {
00182     HexAssert(HexColorUtil::isBlackWhite(color));
00183     HexAssert(Const().IsValid(cell));
00184 
00185     m_played.set(cell);
00186     if (Const().IsLocation(cell))
00187         m_hash.Update(color, cell);
00188     SetColor(color, cell);
00189 
00190     MarkAsDirty();
00191 }
00192 
00193 void StoneBoard::UndoMove(HexPoint cell)
00194 {
00195     HexAssert(Const().IsValid(cell));
00196     HexColor color = GetColor(cell);
00197     HexAssert(color != EMPTY);
00198 
00199     m_played.reset(cell);
00200     if (Const().IsLocation(cell))
00201         m_hash.Update(color, cell);
00202     SetColor(EMPTY, cell);
00203 
00204     MarkAsDirty();
00205 }
00206 
00207 //----------------------------------------------------------------------------
00208 
00209 void StoneBoard::RotateBoard()
00210 {
00211     m_played = BoardUtils::Rotate(Const(), m_played);
00212     for (BWIterator it; it; ++it)
00213         m_stones[*it] = BoardUtils::Rotate(Const(), m_stones[*it]);
00214     ComputeHash();
00215     MarkAsDirty();
00216 }
00217 
00218 bool StoneBoard::IsSelfRotation() const
00219 {
00220     if (m_stones[BLACK] != BoardUtils::Rotate(Const(), m_stones[BLACK]))
00221         return false;
00222     if (m_stones[WHITE] != BoardUtils::Rotate(Const(), m_stones[WHITE]))
00223         return false;
00224     return true;
00225 }
00226 
00227 void StoneBoard::MirrorBoard()
00228 {
00229     m_played = BoardUtils::Mirror(Const(), m_played);
00230     for (BWIterator it; it; ++it)
00231         m_stones[*it] = BoardUtils::Mirror(Const(), m_stones[*it]);
00232     ComputeHash();
00233     MarkAsDirty();
00234 }
00235 
00236 //----------------------------------------------------------------------------
00237 
00238 BoardID StoneBoard::GetBoardID() const
00239 {
00240     /** Packs each interior cell into 2 bits.
00241         @note Assumes all valid HexColors lie between [0,2]. */
00242     std::size_t n = (Width() * Height() + 3) / 4 * 4;
00243 
00244     /** @note When this code was written, the cells were iterated over
00245         in the order (a1, b1, c1, ..., a2, b2, c2, ... , etc). Any
00246         changes to the order in Interior() will break all existing
00247         databases that use BoardID as a lookup, unless this method is
00248         updated to always compute in the above order. */
00249     std::size_t i = 0;
00250     std::vector<byte> val(n, 0);
00251     bitset_t played = GetPlayed();
00252     for (BoardIterator p(Const().Interior()); p; ++p, ++i) 
00253         val[i] = (played.test(*p)) 
00254             ? static_cast<byte>(GetColor(*p))
00255             : static_cast<byte>(EMPTY);
00256 
00257     BoardID id;
00258     for (i = 0; i < n; i += 4)
00259         id.push_back(static_cast<byte>(val[i] 
00260                                        + (val[i+1] << 2)
00261                                        + (val[i+2] << 4)
00262                                        + (val[i+3] << 6)));
00263     return id;
00264 }
00265 
00266 std::string StoneBoard::GetBoardIDString() const
00267 {
00268     std::string hexval[16] = {"0", "1", "2", "3", "4", "5", "6", "7",
00269                   "8", "9", "a", "b", "c", "d", "e", "f"};
00270     BoardID brdID = GetBoardID();
00271     std::string idString;
00272     for (std::size_t i = 0; i < brdID.size(); ++i) {
00273     byte b = brdID[i];
00274     idString += hexval[((b >> 4) & 0xF)];
00275     idString += hexval[b & 0x0F];
00276     }
00277     return idString;
00278 }
00279 
00280 void StoneBoard::SetPosition(const StoneBoard& brd)
00281 {
00282     StartNewGame();
00283     SetColor(BLACK, brd.GetBlack());
00284     SetColor(WHITE, brd.GetWhite());
00285     SetPlayed(brd.GetPlayed());
00286 }
00287 
00288 void StoneBoard::SetPositionOnlyPlayed(const StoneBoard& brd)
00289 {
00290     StartNewGame();
00291     SetColor(BLACK, brd.GetBlack() & brd.GetPlayed());
00292     SetColor(WHITE, brd.GetWhite() & brd.GetPlayed());
00293     SetPlayed(brd.GetPlayed());
00294 }
00295 
00296 void StoneBoard::SetPosition(const BoardID& id)
00297 {
00298     std::size_t n = (Width() * Height() + 3) / 4 * 4;
00299     HexAssert(id.size() == n / 4);
00300 
00301     std::vector<byte> val(n, 0);
00302     for (std::size_t i = 0; i < n; i += 4) 
00303     {
00304         byte packed = id[i/4];
00305         val[i] = packed & 0x3;
00306         val[i+1] = (packed >> 2) & 0x3;
00307         val[i+2] = (packed >> 4) & 0x3;
00308         val[i+3] = (packed >> 6) & 0x3;
00309     }
00310 
00311     /** @note This depends on the order defined by Interior().
00312         See note in implementation of GetBoardID(). */
00313     StartNewGame();
00314     std::size_t i = 0;
00315     for (BoardIterator p(Const().Interior()); p; ++p, ++i) 
00316     {
00317         HexColor color = static_cast<HexColor>(val[i]);
00318         if (color == BLACK || color == WHITE)
00319             PlayMove(color, *p);
00320     }
00321 
00322     ComputeHash();
00323     MarkAsDirty();
00324 }
00325 
00326 void StoneBoard::SetPosition(const std::string& str)
00327 {
00328     /** @note This depends on the order defined by Interior(). */
00329     StartNewGame();
00330     int cell = 0;
00331     for (std::size_t i = 0;
00332          i < str.size() && cell < Width() * Height();
00333          ++i)
00334     {
00335         int x = cell % Width();
00336         int y = cell / Width();
00337         HexPoint p = HexPointUtil::coordsToPoint(x, y);
00338         if (str[i] == '.')
00339             cell++;
00340         else if (str[i] == 'B')
00341         {
00342             PlayMove(BLACK, p);
00343             cell++;
00344         }
00345         else if (str[i] == 'W')
00346         {
00347             PlayMove(WHITE, p);
00348             cell++;
00349         }
00350         else if (str[i] == 'b')
00351         {
00352             SetColor(BLACK, p);
00353             cell++;
00354         }
00355         else if (str[i] == 'w')
00356         {
00357             SetColor(WHITE, p);
00358             cell++;
00359         }
00360     }
00361     ComputeHash();
00362     MarkAsDirty();
00363 }
00364 
00365 //----------------------------------------------------------------------------
00366 
00367 std::string StoneBoard::Write() const
00368 {
00369     return Write(EMPTY_BITSET);
00370 }
00371 
00372 std::string StoneBoard::Write(const bitset_t& b) const
00373 {
00374     std::ostringstream out;
00375     out << '\n';
00376     out << "  " << HashUtil::toString(Hash()) << '\n';
00377     out << "  ";
00378     for (int i = 0; i < Width(); i++) 
00379         out << (char)('a' + i) << "  ";
00380     out << '\n';
00381     for (int i = 0; i < Height(); i++) 
00382     {
00383         for (int j = 0; j < i; j++) 
00384             out << " ";
00385         if (i + 1 < 10) 
00386             out << " ";
00387         out << (i + 1) << "\\";
00388         for (int j = 0; j < Width(); j++) 
00389         {
00390             HexPoint p = HexPointUtil::coordsToPoint(j, i);
00391             if (j) 
00392                 out << "  ";
00393             if (b.test(p))
00394                 out << "*";
00395             else if (IsBlack(p) && IsPlayed(p))
00396                 out << "B";
00397             else if (IsBlack(p))
00398                 out << "b";
00399             else if (IsWhite(p) && IsPlayed(p))
00400                 out << "W";
00401             else if (IsWhite(p))
00402                 out << "w";
00403             else
00404                 out << ".";
00405         }
00406         out << "\\";
00407         out << (i + 1); 
00408         out << '\n';
00409     }
00410     for (int j = 0; j < Height(); j++) 
00411         out << " ";
00412     out << "   ";
00413     for (int i = 0; i < Width(); i++)
00414         out << (char)('a' + i) << "  ";
00415     return out.str();
00416 }
00417 
00418 bool StoneBoard::IsBlackWhiteDisjoint()
00419 {
00420     if ((m_stones[BLACK] & m_stones[WHITE]).any()) 
00421     {
00422         for (BWIterator it; it; ++it)
00423             LogWarning() << HexPointUtil::ToString(m_stones[*it]) << '\n';
00424         return false;
00425     }
00426     return true;
00427 }
00428 
00429 //----------------------------------------------------------------------------


6 Jan 2011 Doxygen 1.6.3