Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoUctBoard.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoBoard.cpp
00003     See GoBoard.h */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "SgSystem.h"
00007 #include "GoUctBoard.h"
00008 
00009 #include <boost/static_assert.hpp>
00010 #include <algorithm>
00011 #include "GoBoardUtil.h"
00012 #include "SgNbIterator.h"
00013 #include "SgStack.h"
00014 
00015 using namespace std;
00016 
00017 //----------------------------------------------------------------------------
00018 
00019 namespace {
00020 
00021 /** Do a consistency check.
00022     Check some data structures for consistency after and before each play
00023     (and at some other places).
00024     This is an expensive check and therefore has to be enabled at compile
00025     time. */
00026 const bool CONSISTENCY = false;
00027 
00028 } // namespace
00029 
00030 //----------------------------------------------------------------------------
00031 
00032 GoUctBoard::GoUctBoard(const GoBoard& bd)
00033     : m_const(bd.Size())
00034 {
00035     m_size = -1;
00036     Init(bd);
00037 }
00038 
00039 GoUctBoard::~GoUctBoard()
00040 {
00041 }
00042 
00043 void GoUctBoard::CheckConsistency() const
00044 {
00045     if (! CONSISTENCY)
00046         return;
00047     for (SgPoint p = 0; p < SG_MAXPOINT; ++p)
00048     {
00049         if (IsBorder(p))
00050             continue;
00051         int c = m_color[p];
00052         SG_ASSERT_EBW(c);
00053         int n = 0;
00054         for (SgNb4Iterator it(p); it; ++it)
00055             if (m_color[*it] == SG_EMPTY)
00056                 ++n;
00057         SG_ASSERT(n == NumEmptyNeighbors(p));
00058         n = 0;
00059         for (SgNb4Iterator it(p); it; ++it)
00060             if (m_color[*it] == SG_BLACK)
00061                 ++n;
00062         SG_ASSERT(n == NumNeighbors(p, SG_BLACK));
00063         n = 0;
00064         for (SgNb4Iterator it(p); it; ++it)
00065             if (m_color[*it] == SG_WHITE)
00066                 ++n;
00067         SG_ASSERT(n == NumNeighbors(p, SG_WHITE));
00068         if (c == SG_BLACK || c == SG_WHITE)
00069             CheckConsistencyBlock(p);
00070         if (c == SG_EMPTY)
00071             SG_ASSERT(m_block[p] == 0);
00072     }
00073 }
00074 
00075 void GoUctBoard::CheckConsistencyBlock(SgPoint point) const
00076 {
00077     SG_ASSERT(Occupied(point));
00078     SgBlackWhite color = GetColor(point);
00079     GoPointList stones;
00080     Block::LibertyList liberties;
00081     SgMarker mark;
00082     SgStack<SgPoint,SG_MAXPOINT> stack;
00083     stack.Push(point);
00084     bool anchorFound = false;
00085     const Block* block = m_block[point];
00086     while (! stack.IsEmpty())
00087     {
00088         SgPoint p = stack.Pop();
00089         if (IsBorder(p) || ! mark.NewMark(p))
00090             continue;
00091         if (GetColor(p) == color)
00092         {
00093             stones.PushBack(p);
00094             if (p == block->m_anchor)
00095                 anchorFound = true;
00096             stack.Push(p - SG_NS);
00097             stack.Push(p - SG_WE);
00098             stack.Push(p + SG_WE);
00099             stack.Push(p + SG_NS);
00100         }
00101         else if (GetColor(p) == SG_EMPTY)
00102             liberties.PushBack(p);
00103     }
00104     SG_ASSERT(anchorFound);
00105     SG_ASSERT(color == block->m_color);
00106     SG_ASSERT(stones.SameElements(block->m_stones));
00107     SG_ASSERT(liberties.SameElements(block->m_liberties));
00108     SG_ASSERT(stones.Length() == NumStones(point));
00109 }
00110 
00111 void GoUctBoard::AddLibToAdjBlocks(SgPoint p, SgBlackWhite c)
00112 {
00113     if (NumNeighbors(p, c) == 0)
00114         return;
00115     SgReserveMarker reserve(m_marker2);
00116     m_marker2.Clear();
00117     Block* b;
00118     if (m_color[p - SG_NS] == c && (b = m_block[p - SG_NS]) != 0)
00119     {
00120         m_marker2.Include(b->m_anchor);
00121         b->m_liberties.PushBack(p);
00122     }
00123     if (m_color[p + SG_NS] == c && (b = m_block[p + SG_NS]) != 0
00124         && m_marker2.NewMark(b->m_anchor))
00125         b->m_liberties.PushBack(p);
00126     if (m_color[p - SG_WE] == c && (b = m_block[p - SG_WE]) != 0
00127         && m_marker2.NewMark(b->m_anchor))
00128         b->m_liberties.PushBack(p);
00129     if (m_color[p + SG_WE] == c && (b = m_block[p + SG_WE]) != 0
00130         && ! m_marker2.Contains(b->m_anchor))
00131         b->m_liberties.PushBack(p);
00132 }
00133 
00134 void GoUctBoard::AddStoneToBlock(SgPoint p, Block* block)
00135 {
00136     // Stone already placed
00137     SG_ASSERT(IsColor(p, block->m_color));
00138     block->m_stones.PushBack(p);
00139     if (IsEmpty(p - SG_NS) && ! IsAdjacentTo(p - SG_NS, block))
00140         block->m_liberties.PushBack(p - SG_NS);
00141     if (IsEmpty(p - SG_WE) && ! IsAdjacentTo(p - SG_WE, block))
00142         block->m_liberties.PushBack(p - SG_WE);
00143     if (IsEmpty(p + SG_WE) && ! IsAdjacentTo(p + SG_WE, block))
00144         block->m_liberties.PushBack(p + SG_WE);
00145     if (IsEmpty(p + SG_NS) && ! IsAdjacentTo(p + SG_NS, block))
00146         block->m_liberties.PushBack(p + SG_NS);
00147     m_block[p] = block;
00148 }
00149 
00150 void GoUctBoard::CreateSingleStoneBlock(SgPoint p, SgBlackWhite c)
00151 {
00152     // Stone already placed
00153     SG_ASSERT(IsColor(p, c));
00154     SG_ASSERT(NumNeighbors(p, c) == 0);
00155     Block& block = m_blockArray[p];
00156     block.InitSingleStoneBlock(c, p);
00157     if (IsEmpty(p - SG_NS))
00158         block.m_liberties.PushBack(p - SG_NS);
00159     if (IsEmpty(p - SG_WE))
00160         block.m_liberties.PushBack(p - SG_WE);
00161     if (IsEmpty(p + SG_WE))
00162         block.m_liberties.PushBack(p + SG_WE);
00163     if (IsEmpty(p + SG_NS))
00164         block.m_liberties.PushBack(p + SG_NS);
00165     m_block[p] = &block;
00166 }
00167 
00168 bool GoUctBoard::IsAdjacentTo(SgPoint p,
00169                               const GoUctBoard::Block* block) const
00170 {
00171     return   m_block[p - SG_NS] == block
00172           || m_block[p - SG_WE] == block
00173           || m_block[p + SG_WE] == block
00174           || m_block[p + SG_NS] == block;
00175 }
00176 
00177 void GoUctBoard::MergeBlocks(SgPoint p, const SgArrayList<Block*,4>& adjBlocks)
00178 {
00179     // Stone already placed
00180     SG_ASSERT(IsColor(p, adjBlocks[0]->m_color));
00181     SG_ASSERT(NumNeighbors(p, adjBlocks[0]->m_color) > 1);
00182     Block* largestBlock = 0;
00183     int largestBlockStones = 0;
00184     for (SgArrayList<Block*,4>::Iterator it(adjBlocks); it; ++it)
00185     {
00186         Block* adjBlock = *it;
00187         int numStones = adjBlock->m_stones.Length();
00188         if (numStones > largestBlockStones)
00189         {
00190             largestBlockStones = numStones;
00191             largestBlock = adjBlock;
00192         }
00193     }
00194     largestBlock->m_stones.PushBack(p);
00195     SgReserveMarker reserve(m_marker);
00196     m_marker.Clear();
00197     for (Block::LibertyIterator lib(largestBlock->m_liberties); lib; ++lib)
00198         m_marker.Include(*lib);
00199     for (SgArrayList<Block*,4>::Iterator it(adjBlocks); it; ++it)
00200     {
00201         Block* adjBlock = *it;
00202         if (adjBlock == largestBlock)
00203             continue;
00204         for (Block::StoneIterator stn(adjBlock->m_stones); stn; ++stn)
00205         {
00206             largestBlock->m_stones.PushBack(*stn);
00207             m_block[*stn] = largestBlock;
00208         }
00209         for (Block::LibertyIterator lib(adjBlock->m_liberties); lib; ++lib)
00210             if (m_marker.NewMark(*lib))
00211                 largestBlock->m_liberties.PushBack(*lib);
00212     }
00213     m_block[p] = largestBlock;
00214     if (IsEmpty(p - SG_NS) && m_marker.NewMark(p - SG_NS))
00215         largestBlock->m_liberties.PushBack(p - SG_NS);
00216     if (IsEmpty(p - SG_WE) && m_marker.NewMark(p - SG_WE))
00217         largestBlock->m_liberties.PushBack(p - SG_WE);
00218     if (IsEmpty(p + SG_WE) && m_marker.NewMark(p + SG_WE))
00219         largestBlock->m_liberties.PushBack(p + SG_WE);
00220     if (IsEmpty(p + SG_NS) && m_marker.NewMark(p + SG_NS))
00221         largestBlock->m_liberties.PushBack(p + SG_NS);
00222 }
00223 
00224 void GoUctBoard::UpdateBlocksAfterAddStone(SgPoint p, SgBlackWhite c,
00225                                         const SgArrayList<Block*,4>& adjBlocks)
00226 {
00227     // Stone already placed
00228     SG_ASSERT(IsColor(p, c));
00229     int n = adjBlocks.Length();
00230     if (n == 0)
00231         CreateSingleStoneBlock(p, c);
00232     else
00233     {
00234         if (n == 1)
00235             AddStoneToBlock(p, adjBlocks[0]);
00236         else
00237             MergeBlocks(p, adjBlocks);
00238     }
00239 }
00240 
00241 void GoUctBoard::Init(const GoBoard& bd)
00242 {
00243     if (bd.Size() != m_size)
00244         InitSize(bd);
00245     m_prisoners[SG_BLACK] = bd.NumPrisoners(SG_BLACK);
00246     m_prisoners[SG_WHITE] = bd.NumPrisoners(SG_WHITE);
00247     m_koPoint = bd.KoPoint();
00248     m_lastMove = bd.GetLastMove();
00249     m_secondLastMove = bd.Get2ndLastMove();
00250     m_toPlay = bd.ToPlay();
00251     for (GoBoard::Iterator it(bd); it; ++it)
00252     {
00253         SgPoint p = *it;
00254         SgBoardColor c = bd.GetColor(p);
00255         m_color[p] = c;
00256         m_nuNeighbors[SG_BLACK][p] = bd.NumNeighbors(p, SG_BLACK);
00257         m_nuNeighbors[SG_WHITE][p] = bd.NumNeighbors(p, SG_WHITE);
00258         m_nuNeighborsEmpty[p] = bd.NumEmptyNeighbors(p);
00259         if (bd.IsEmpty(p))
00260             m_block[p] = 0;
00261         else if (bd.Anchor(p) == p)
00262         {
00263             SgBoardColor c = m_color[p];
00264             Block& block = m_blockArray[p];
00265             block.InitNewBlock(c, p);
00266             for (GoBoard::StoneIterator it2(bd, p); it2; ++it2)
00267             {
00268                 block.m_stones.PushBack(*it2);
00269                 m_block[*it2] = &block;
00270             }
00271             for (GoBoard::LibertyIterator it2(bd, p); it2; ++it2)
00272                 block.m_liberties.PushBack(*it2);
00273         }
00274     }
00275     CheckConsistency();
00276 }
00277 
00278 void GoUctBoard::InitSize(const GoBoard& bd)
00279 {
00280     m_size = bd.Size();
00281     m_nuNeighbors[SG_BLACK].Fill(0);
00282     m_nuNeighbors[SG_WHITE].Fill(0);
00283     m_nuNeighborsEmpty.Fill(0);
00284     m_block.Fill(0);
00285     for (SgPoint p = 0; p < SG_MAXPOINT; ++p)
00286     {
00287         if (bd.IsBorder(p))
00288         {
00289             m_color[p] = SG_BORDER;
00290             m_isBorder[p] = true;
00291         }
00292         else
00293             m_isBorder[p] = false;
00294     }
00295     m_const.ChangeSize(m_size);
00296 }
00297 
00298 void GoUctBoard::NeighborBlocks(SgPoint p, SgBlackWhite c,
00299                                 SgPoint anchors[]) const
00300 {
00301     SG_ASSERT(IsEmpty(p));
00302     SgReserveMarker reserve(m_marker);
00303     SG_UNUSED(reserve);
00304     m_marker.Clear();
00305     int i = 0;
00306     if (NumNeighbors(p, c) > 0)
00307     {
00308         if (IsColor(p - SG_NS, c) && m_marker.NewMark(Anchor(p - SG_NS)))
00309             anchors[i++] = Anchor(p - SG_NS);
00310         if (IsColor(p - SG_WE, c) && m_marker.NewMark(Anchor(p - SG_WE)))
00311             anchors[i++] = Anchor(p - SG_WE);
00312         if (IsColor(p + SG_WE, c) && m_marker.NewMark(Anchor(p + SG_WE)))
00313             anchors[i++] = Anchor(p + SG_WE);
00314         if (IsColor(p + SG_NS, c) && m_marker.NewMark(Anchor(p + SG_NS)))
00315             anchors[i++] = Anchor(p + SG_NS);
00316     }
00317     anchors[i] = SG_ENDPOINT;
00318 }
00319 
00320 void GoUctBoard::AddStone(SgPoint p, SgBlackWhite c)
00321 {
00322     SG_ASSERT(IsEmpty(p));
00323     SG_ASSERT_BW(c);
00324     m_color[p] = c;
00325     --m_nuNeighborsEmpty[p - SG_NS];
00326     --m_nuNeighborsEmpty[p - SG_WE];
00327     --m_nuNeighborsEmpty[p + SG_WE];
00328     --m_nuNeighborsEmpty[p + SG_NS];
00329     SgArray<int,SG_MAXPOINT>& nuNeighbors = m_nuNeighbors[c];
00330     ++nuNeighbors[p - SG_NS];
00331     ++nuNeighbors[p - SG_WE];
00332     ++nuNeighbors[p + SG_WE];
00333     ++nuNeighbors[p + SG_NS];
00334 }
00335 
00336 /** Remove liberty from adjacent blocks and kill opponent blocks without
00337     liberties.
00338     As a side effect, computes adjacent blocks of own color to avoid a
00339     second call to GetAdjacentBlocks() in UpdateBlocksAfterAddStone(). */
00340 void GoUctBoard::RemoveLibAndKill(SgPoint p, SgBlackWhite opp,
00341                                   SgArrayList<Block*,4>& ownAdjBlocks)
00342 {
00343     SgReserveMarker reserve(m_marker);
00344     m_marker.Clear();
00345     Block* b;
00346     if ((b = m_block[p - SG_NS]) != 0)
00347     {
00348         m_marker.Include(b->m_anchor);
00349         b->m_liberties.Exclude(p);
00350         if (b->m_color == opp)
00351         {
00352             if (b->m_liberties.Length() == 0)
00353                 KillBlock(b);
00354         }
00355         else
00356             ownAdjBlocks.PushBack(b);
00357     }
00358     if ((b = m_block[p - SG_WE]) != 0 && m_marker.NewMark(b->m_anchor))
00359     {
00360         b->m_liberties.Exclude(p);
00361         if (b->m_color == opp)
00362         {
00363             if (b->m_liberties.Length() == 0)
00364                 KillBlock(b);
00365         }
00366         else
00367             ownAdjBlocks.PushBack(b);
00368     }
00369     if ((b = m_block[p + SG_WE]) != 0 && m_marker.NewMark(b->m_anchor))
00370     {
00371         b->m_liberties.Exclude(p);
00372         if (b->m_color == opp)
00373         {
00374             if (b->m_liberties.Length() == 0)
00375                 KillBlock(b);
00376         }
00377         else
00378             ownAdjBlocks.PushBack(b);
00379     }
00380     if ((b = m_block[p + SG_NS]) != 0 && ! m_marker.Contains(b->m_anchor))
00381     {
00382         b->m_liberties.Exclude(p);
00383         if (b->m_color == opp)
00384         {
00385             if (b->m_liberties.Length() == 0)
00386                 KillBlock(b);
00387         }
00388         else
00389             ownAdjBlocks.PushBack(b);
00390     }
00391 }
00392 
00393 void GoUctBoard::KillBlock(const Block* block)
00394 {
00395     SgBlackWhite c = block->m_color;
00396     SgBlackWhite opp = SgOppBW(c);
00397     SgArray<int,SG_MAXPOINT>& nuNeighbors = m_nuNeighbors[c];
00398     for (Block::StoneIterator it(block->m_stones); it; ++it)
00399     {
00400         SgPoint p = *it;
00401         AddLibToAdjBlocks(p, opp);
00402         m_color[p] = SG_EMPTY;
00403         ++m_nuNeighborsEmpty[p - SG_NS];
00404         ++m_nuNeighborsEmpty[p - SG_WE];
00405         ++m_nuNeighborsEmpty[p + SG_WE];
00406         ++m_nuNeighborsEmpty[p + SG_NS];
00407         --nuNeighbors[p - SG_NS];
00408         --nuNeighbors[p - SG_WE];
00409         --nuNeighbors[p + SG_WE];
00410         --nuNeighbors[p + SG_NS];
00411         m_capturedStones.PushBack(p);
00412         m_block[p] = 0;
00413     }
00414     int nuStones = block->m_stones.Length();
00415     m_prisoners[c] += nuStones;
00416     if (nuStones == 1)
00417         // Remember that single stone was captured, check conditions on
00418         // capturing block later
00419         m_koPoint = block->m_anchor;
00420 }
00421 
00422 void GoUctBoard::Play(SgPoint p)
00423 {
00424     SG_ASSERT(p >= 0); // No special move, see SgMove
00425     SG_ASSERT(p == SG_PASS || (IsValidPoint(p) && IsEmpty(p)));
00426     CheckConsistency();
00427     m_koPoint = SG_NULLPOINT;
00428     m_capturedStones.Clear();
00429     SgBlackWhite opp = SgOppBW(m_toPlay);
00430     if (p != SG_PASS)
00431     {
00432         AddStone(p, m_toPlay);
00433         SgArrayList<Block*,4> adjBlocks;
00434         if (NumNeighbors(p, SG_BLACK) > 0 || NumNeighbors(p, SG_WHITE) > 0)
00435             RemoveLibAndKill(p, opp, adjBlocks);
00436         UpdateBlocksAfterAddStone(p, m_toPlay, adjBlocks);
00437         if (m_koPoint != SG_NULLPOINT)
00438             if (NumStones(p) > 1 || NumLiberties(p) > 1)
00439                 m_koPoint = SG_NULLPOINT;
00440         SG_ASSERT(HasLiberties(p)); // Suicide not supported by GoUctBoard
00441     }
00442     m_secondLastMove = m_lastMove;
00443     m_lastMove = p;
00444     m_toPlay = opp;
00445     CheckConsistency();
00446 }
00447 
00448 //----------------------------------------------------------------------------


Sun Mar 13 2011 Doxygen 1.7.1