00001
00002
00003
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
00022
00023
00024
00025
00026 const bool CONSISTENCY = false;
00027
00028 }
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
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
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] = █
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
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
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] = █
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
00337
00338
00339
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
00418
00419 m_koPoint = block->m_anchor;
00420 }
00421
00422 void GoUctBoard::Play(SgPoint p)
00423 {
00424 SG_ASSERT(p >= 0);
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));
00441 }
00442 m_secondLastMove = m_lastMove;
00443 m_lastMove = p;
00444 m_toPlay = opp;
00445 CheckConsistency();
00446 }
00447
00448