Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoBoardUtil.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoBoardUtil.cpp
00003     See GoBoardUtil.h */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "SgSystem.h"
00007 #include "GoBoardUtil.h"
00008 
00009 #include <iomanip>
00010 #include <sstream>
00011 #include <string>
00012 #include "GoBoard.h"
00013 #include "GoModBoard.h"
00014 #include "GoMoveExecutor.h"
00015 #include "GoSafetySolver.h"
00016 #include "SgDebug.h"
00017 #include "SgException.h"
00018 #include "SgNbIterator.h"
00019 #include "SgProp.h"
00020 
00021 using namespace std;
00022 using SgPropUtil::PointToSgfString;
00023 
00024 //----------------------------------------------------------------------------
00025 
00026 namespace {
00027 
00028 /** Function used in GoBoardUtil::CfgDistance() */
00029 void CfgDistanceCheck(const GoBoard& bd, SgPointArray<int>& array,
00030                       GoPointList& pointList, int d, SgPoint p)
00031 {
00032     if (! bd.IsBorder(p))
00033     {
00034         if (bd.Occupied(p))
00035             p = bd.Anchor(p);
00036         if (array[p] == numeric_limits<int>::max())
00037         {
00038             array[p] = d;
00039             pointList.PushBack(p);
00040         }
00041     }
00042 }
00043 
00044 /** Function used in GoBoardUtil::ScorePosition() */
00045 void ScorePositionRecurse(const GoBoard& bd, SgPoint p,
00046                           const SgPointSet& deadStones, SgMarker& marker,
00047                           bool& isBlackAdjacent, bool& isWhiteAdjacent,
00048                           int& nuPoints, int& nuDeadWhite, int& nuDeadBlack)
00049 {
00050     if (bd.IsBorder(p))
00051         return;
00052     SgEmptyBlackWhite c = bd.GetColor(p);
00053     if (c != SG_EMPTY && ! deadStones.Contains(p))
00054     {
00055         if (c == SG_BLACK)
00056             ++isBlackAdjacent;
00057         else
00058             ++isWhiteAdjacent;
00059         return;
00060     }
00061     if (! marker.NewMark(p))
00062         return;
00063     ++nuPoints;
00064     if (c == SG_BLACK)
00065         ++nuDeadBlack;
00066     if (c == SG_WHITE)
00067         ++nuDeadWhite;
00068     ScorePositionRecurse(bd, p + SG_NS, deadStones, marker, isBlackAdjacent,
00069                          isWhiteAdjacent, nuPoints, nuDeadWhite, nuDeadBlack);
00070     ScorePositionRecurse(bd, p - SG_NS, deadStones, marker, isBlackAdjacent,
00071                          isWhiteAdjacent, nuPoints, nuDeadWhite, nuDeadBlack);
00072     ScorePositionRecurse(bd, p + SG_WE, deadStones, marker, isBlackAdjacent,
00073                          isWhiteAdjacent, nuPoints, nuDeadWhite, nuDeadBlack);
00074     ScorePositionRecurse(bd, p - SG_WE, deadStones, marker, isBlackAdjacent,
00075                          isWhiteAdjacent, nuPoints, nuDeadWhite, nuDeadBlack);
00076 }
00077 
00078 } // namespace
00079 
00080 //----------------------------------------------------------------------------
00081 
00082 void GoBoardUtil::AddNeighborBlocksOfColor(const GoBoard& bd, SgPoint p,
00083                                            SgBlackWhite c,
00084                                            SgVector<SgPoint>& neighbors)
00085 {
00086     if (bd.IsColor(p - SG_NS, c))
00087         neighbors.Include(bd.Anchor(p - SG_NS));
00088     if (bd.IsColor(p - SG_WE, c))
00089         neighbors.Include(bd.Anchor(p - SG_WE));
00090     if (bd.IsColor(p + SG_WE, c))
00091         neighbors.Include(bd.Anchor(p + SG_WE));
00092     if (bd.IsColor(p + SG_NS, c))
00093         neighbors.Include(bd.Anchor(p + SG_NS));
00094 }
00095 
00096 void GoBoardUtil::AddWall(GoBoard& bd,
00097                           SgBlackWhite color,
00098                           SgPoint start,
00099                           int length,
00100                           int direction)
00101 {
00102     for (SgPoint p = start; length > 0; --length)
00103     {
00104         bd.Play(p, color);
00105         p += direction;
00106     }
00107 }
00108 
00109 GoPointList GoBoardUtil::AdjacentStones(const GoBoard& bd, SgPoint point)
00110 {
00111     SG_ASSERT(bd.IsValidPoint(point));
00112     SG_ASSERT(bd.Occupied(point));
00113     const SgBlackWhite other = SgOppBW(bd.GetStone(point));
00114     GoPointList result;
00115     SgMarker& mark = bd.m_userMarker;
00116     SgReserveMarker reserve(mark);
00117     SG_UNUSED(reserve);
00118     mark.Clear();
00119     for (GoBoard::StoneIterator it(bd, point); it; ++it)
00120     {
00121         if (bd.NumNeighbors(*it, other) > 0)
00122         {
00123             SgPoint p = *it;
00124             if (bd.IsColor(p - SG_NS, other) && mark.NewMark(p - SG_NS))
00125                 result.PushBack(p - SG_NS);
00126             if (bd.IsColor(p - SG_WE, other) && mark.NewMark(p - SG_WE))
00127                 result.PushBack(p - SG_WE);
00128             if (bd.IsColor(p + SG_WE, other) && mark.NewMark(p + SG_WE))
00129                 result.PushBack(p + SG_WE);
00130             if (bd.IsColor(p + SG_NS, other) && mark.NewMark(p + SG_NS))
00131                 result.PushBack(p + SG_NS);
00132         }
00133     };
00134     return result;
00135 }
00136 
00137 void GoBoardUtil::AdjacentBlocks(const GoBoard& bd, SgPoint p, int maxLib,
00138                                  SgVector<SgPoint>* blocks)
00139 {
00140     SG_ASSERT(blocks);
00141     SgPoint a[SG_MAXPOINT];
00142     int n = bd.AdjacentBlocks(p, maxLib, a, SG_MAXPOINT);
00143     blocks->SetTo(a, n);
00144 }
00145 
00146 void GoBoardUtil::BlocksAdjacentToPoints(const GoBoard& bd,
00147                                          const SgVector<SgPoint>& points,
00148                                          SgBlackWhite c,
00149                                          SgVector<SgPoint>* blocks)
00150 {
00151     // Mark all points to avoid n^2 algorithm.
00152     SgMarker& mark = bd.m_userMarker;
00153     SgReserveMarker reserve(mark);
00154     SG_UNUSED(reserve);
00155     mark.Clear();
00156     for (SgVectorIterator<SgPoint> it1(points); it1; ++it1)
00157         mark.Include(*it1);
00158     // Add the anchor of each adjacent block to the list of blocks.
00159     SgPoint a[SG_MAXPOINT];
00160     int n = 0;
00161     for (SgVectorIterator<SgPoint> it2(points); it2; ++it2)
00162     {
00163         SgPoint p = *it2;
00164         if (bd.NumNeighbors(p, c) > 0)
00165         {
00166             if (bd.IsColor(p - SG_NS, c)
00167                 && mark.NewMark(bd.Anchor(p - SG_NS)))
00168                 a[n++] = bd.Anchor(p - SG_NS);
00169             if (bd.IsColor(p - SG_WE, c)
00170                 && mark.NewMark(bd.Anchor(p - SG_WE)))
00171                 a[n++] = bd.Anchor(p - SG_WE);
00172             if (bd.IsColor(p + SG_WE, c)
00173                 && mark.NewMark(bd.Anchor(p + SG_WE)))
00174                 a[n++] = bd.Anchor(p + SG_WE);
00175             if (bd.IsColor(p + SG_NS, c)
00176                 && mark.NewMark(bd.Anchor(p + SG_NS)))
00177                 a[n++] = bd.Anchor(p + SG_NS);
00178         }
00179     }
00180     blocks->SetTo(a, n);
00181 }
00182 
00183 void GoBoardUtil::BlocksAdjacentToPoints(const GoBoard& bd,
00184                                          const SgPointSet& points,
00185                                          SgBlackWhite c,
00186                                          SgVector<SgPoint>* blocks)
00187 {
00188     // exact copy from list version above
00189     SG_ASSERT(blocks);
00190     // Mark all points to avoid n^2 algorithm.
00191     SgMarker& mark = bd.m_userMarker;
00192     SgReserveMarker reserve(mark);
00193     SG_UNUSED(reserve);
00194     mark.Clear();
00195     for (SgSetIterator it1(points); it1; ++it1)
00196         mark.Include(*it1);
00197     // Add the anchor of each adjacent block to the list of blocks.
00198     SgPoint a[SG_MAXPOINT];
00199     int n = 0;
00200     for (SgSetIterator it2(points); it2; ++it2)
00201     {
00202         SgPoint p = *it2;
00203         if (bd.NumNeighbors(p, c) > 0)
00204         {
00205             if (bd.IsColor(p - SG_NS, c)
00206                 && mark.NewMark(bd.Anchor(p - SG_NS)))
00207                 a[n++] = bd.Anchor(p - SG_NS);
00208             if (bd.IsColor(p - SG_WE, c)
00209                 && mark.NewMark(bd.Anchor(p - SG_WE)))
00210                 a[n++] = bd.Anchor(p - SG_WE);
00211             if (bd.IsColor(p + SG_WE, c)
00212                 && mark.NewMark(bd.Anchor(p + SG_WE)))
00213                 a[n++] = bd.Anchor(p + SG_WE);
00214             if (bd.IsColor(p + SG_NS, c)
00215                 && mark.NewMark(bd.Anchor(p + SG_NS)))
00216                 a[n++] = bd.Anchor(p + SG_NS);
00217         }
00218     }
00219     blocks->SetTo(a, n);
00220 }
00221 
00222 bool GoBoardUtil::BlockIsAdjacentTo(const GoBoard& bd, SgPoint block,
00223                                     const SgPointSet& walls)
00224 {
00225     for (GoBoard::StoneIterator it(bd, block); it; ++it)
00226     {
00227         if (  walls.Contains((*it) + SG_NS)
00228            || walls.Contains((*it) - SG_NS)
00229            || walls.Contains((*it) + SG_WE)
00230            || walls.Contains((*it) - SG_WE)
00231            )
00232             return true;
00233     }
00234     return false;
00235 }
00236 
00237 SgPointArray<int> GoBoardUtil::CfgDistance(const GoBoard& bd, SgPoint p,
00238                                            int maxDist)
00239 {
00240     SgPointArray<int> array(numeric_limits<int>::max());
00241     GoPointList pointList;
00242     if (bd.Occupied(p))
00243         p = bd.Anchor(p);
00244     pointList.PushBack(p);
00245     int begin = 0;
00246     int end = 1;
00247     int d = 0;
00248     array[p] = d;
00249     while (begin != end && d < maxDist)
00250     {
00251         ++d;
00252         for (int i = begin; i != end; ++i)
00253         {
00254             p = pointList[i];
00255             if (bd.Occupied(p))
00256             {
00257                 for (GoBoard::StoneIterator it(bd, p); it; ++it)
00258                 {
00259                     CfgDistanceCheck(bd, array, pointList, d, *it + SG_NS);
00260                     CfgDistanceCheck(bd, array, pointList, d, *it - SG_NS);
00261                     CfgDistanceCheck(bd, array, pointList, d, *it + SG_WE);
00262                     CfgDistanceCheck(bd, array, pointList, d, *it - SG_WE);
00263                 }
00264             }
00265             else
00266             {
00267                 CfgDistanceCheck(bd, array, pointList, d, p + SG_NS);
00268                 CfgDistanceCheck(bd, array, pointList, d, p - SG_NS);
00269                 CfgDistanceCheck(bd, array, pointList, d, p + SG_WE);
00270                 CfgDistanceCheck(bd, array, pointList, d, p - SG_WE);
00271             }
00272         }
00273         begin = end;
00274         end = pointList.Length();
00275     }
00276     return array;
00277 }
00278 
00279 void GoBoardUtil::DumpBoard(const GoBoard& bd, std::ostream& out)
00280 {
00281     const int size = bd.Size();
00282     out << bd;
00283     if (bd.MoveNumber() == 0)
00284         return;
00285     out << "(;SZ[" << size << "]\n";
00286     const GoSetup& setup = bd.Setup();
00287     if (! setup.IsEmpty())
00288     {
00289         for (SgBWIterator it; it; ++it)
00290         {
00291             SgBlackWhite c = *it;
00292             int stoneNumber = 0;
00293             out << (c == SG_BLACK ? "AB" : "AW");
00294             for (SgSetIterator it2(setup.m_stones[c]); it2; ++it2)
00295             {
00296                 SgPoint p = *it2;
00297                 ++stoneNumber;
00298                 out << '[' << PointToSgfString(p, size, SG_PROPPOINTFMT_GO)
00299                     << ']';
00300                 if (stoneNumber % 10 == 0)
00301                     out << '\n';
00302             }
00303             out << '\n';
00304         }
00305         out << "PL[" << (setup.m_player == SG_BLACK ? 'B' : 'W') << "]\n";
00306     }
00307     int moveNumber = 0;
00308     for (int i = 0; i < bd.MoveNumber(); ++i)
00309     {
00310         GoPlayerMove move = bd.Move(i);
00311         out << ';';
00312         out << (move.Color() == SG_BLACK ? "B" : "W");
00313         ++moveNumber;
00314         out << '[' << PointToSgfString(move.Point(), size, SG_PROPPOINTFMT_GO)
00315             << ']';
00316         if (moveNumber % 10 == 0)
00317             out << '\n';
00318     }
00319     out << ")\n";
00320 }
00321 
00322 void GoBoardUtil::ExpandToBlocks(const GoBoard& board, SgPointSet& pointSet)
00323 {
00324     // @todo faster to use GoBoard::StoneIterator in GoBoard?
00325     SG_ASSERT(pointSet.SubsetOf(board.Occupied()));
00326     int size = board.Size();
00327     for (SgBlackWhite color = SG_BLACK; color <= SG_WHITE; ++color)
00328     {
00329         SgPointSet set = pointSet & board.All(color);
00330         bool change(true);
00331         while (change)
00332         {
00333             change = false;
00334             SgPointSet next = set | (set.Border(size) & board.All(color));
00335             if (next != set)
00336             {
00337                 change = true;
00338                 set = next;
00339             }
00340         }
00341         pointSet |= set;
00342     }
00343 }
00344 
00345 void GoBoardUtil::DiagonalsOfColor(const GoBoard& bd, SgPoint p, int c,
00346                                    SgVector<SgPoint>* diagonals)
00347 {
00348     diagonals->Clear();
00349     if (bd.IsColor(p - SG_NS - SG_WE, c))
00350         diagonals->PushBack(p - SG_NS - SG_WE);
00351     if (bd.IsColor(p - SG_NS + SG_WE, c))
00352         diagonals->PushBack(p - SG_NS + SG_WE);
00353     if (bd.IsColor(p + SG_NS - SG_WE, c))
00354         diagonals->PushBack(p + SG_NS - SG_WE);
00355     if (bd.IsColor(p + SG_NS + SG_WE, c))
00356         diagonals->PushBack(p + SG_NS + SG_WE);
00357 }
00358 
00359 bool GoBoardUtil::EndOfGame(const GoBoard& bd)
00360 {
00361     SgBlackWhite toPlay = bd.ToPlay();
00362     GoPlayerMove passToPlay(toPlay, SG_PASS);
00363     GoPlayerMove passOpp(SgOppBW(toPlay), SG_PASS);
00364     int moveNumber = bd.MoveNumber();
00365     if (bd.Rules().TwoPassesEndGame())
00366     {
00367         return moveNumber >= 2
00368             && bd.Move(moveNumber - 1) == passOpp
00369             && bd.Move(moveNumber - 2) == passToPlay;
00370     }
00371     else // Three passes in a row end the game.
00372     {
00373         return moveNumber >= 3
00374             && bd.Move(moveNumber - 1) == passOpp
00375             && bd.Move(moveNumber - 2) == passToPlay
00376             && bd.Move(moveNumber - 3) == passOpp;
00377     }
00378 }
00379 
00380 
00381 bool GoBoardUtil::GenerateIfLegal(const GoBoard& bd, SgPoint move,
00382                                   SgVector<SgPoint>* moves)
00383 {
00384     if (bd.IsLegal(move))
00385     {
00386         if (moves)
00387             moves->Include(move);
00388         /* */ return true; /* */
00389     }
00390     return false;
00391 }
00392 
00393 void GoBoardUtil::GetCoordString(SgMove p, std::string* s, int boardSize)
00394 {
00395     SG_ASSERT(s);
00396     SG_ASSERT(p != SG_NULLMOVE);
00397     if (p == SG_PASS)
00398         *s = "Pass";
00399     else if (p == SG_COUPONMOVE)
00400         *s = "Coupon";
00401     else
00402     {
00403         int col = SgPointUtil::Col(p);
00404         int row = SgPointUtil::Row(p);
00405         if (9 <= col)
00406             ++col; // skip 'I'
00407         ostringstream o;
00408         o << static_cast<char>('A' + col - 1) << (boardSize + 1 - row);
00409         *s = o.str();
00410     }
00411 }
00412 
00413 bool GoBoardUtil::HasAdjacentBlocks(const GoBoard& bd, SgPoint p,
00414                                     int maxLib)
00415 {
00416     SG_ASSERT(bd.Occupied(p));
00417     const SgBlackWhite other = SgOppBW(bd.GetStone(p));
00418     for (GoBoard::StoneIterator stone(bd, p); stone; ++stone)
00419         for (SgNb4Iterator nb(*stone); nb; ++nb)
00420             if (bd.IsColor(*nb, other) && bd.AtMostNumLibs(*nb, maxLib))
00421                 return true;
00422     return false;
00423 }
00424 
00425 bool GoBoardUtil::IsHandicapPoint(SgGrid size, SgGrid col, SgGrid row)
00426 {
00427     SgGrid line1;
00428     SgGrid line3;
00429     if (size < 9)
00430         return false;
00431     if (size <= 11)
00432     {
00433         line1 = 3;
00434         line3 = size - 2;
00435     }
00436     else
00437     {
00438         line1 = 4;
00439         line3 = size - 3;
00440     }
00441     if (size > 11 && size % 2 != 0) // mark mid points
00442     {
00443         SgGrid line2 = size / 2 + 1;
00444         return (row == line1 || row == line2 || row == line3)
00445             && (col == line1 || col == line2 || col == line3);
00446     }
00447     else
00448         return (row == line1 || row == line3)
00449             && (col == line1 || col == line3);
00450 }
00451 
00452 bool GoBoardUtil::IsSimpleEyeOfBlock(const GoBoard& bd, SgPoint lib,
00453                                      SgPoint blockAnchor,
00454                                      const SgVector<SgPoint>& eyes)
00455 {
00456     SgBlackWhite color = bd.GetStone(blockAnchor);
00457     // need IsColor test for nbs because might be off board.
00458     if (bd.IsColor(lib - SG_NS, color)
00459         && bd.Anchor(lib - SG_NS) != blockAnchor)
00460         return false;
00461     if (bd.IsColor(lib + SG_NS, color)
00462         && bd.Anchor(lib + SG_NS) != blockAnchor)
00463         return false;
00464     if (bd.IsColor(lib - SG_WE, color)
00465         && bd.Anchor(lib - SG_WE) != blockAnchor)
00466         return false;
00467     if (bd.IsColor(lib + SG_WE, color)
00468         && bd.Anchor(lib + SG_WE) != blockAnchor)
00469         return false;
00470     int nuForFalse = (bd.Line(lib) == 1) ? 1 : 2;
00471     // no need to check diagonals for same block since direct neighbors are.
00472     for (SgNb4DiagIterator it(lib); it; ++it)
00473     {
00474         SgPoint nb(*it);
00475         if (! bd.IsBorder(nb) && ! bd.IsColor(nb, color)
00476             && ! eyes.Contains(nb))
00477             if (--nuForFalse <= 0)
00478                 return false;
00479     }
00480     return true;
00481 }
00482 
00483 bool GoBoardUtil::IsSnapback(const GoBoard& constBd, SgPoint p)
00484 {
00485     SG_ASSERT(constBd.IsValidPoint(p));
00486     SG_ASSERT(constBd.Occupied(p));
00487 
00488     bool snapback = false;
00489     if (constBd.IsSingleStone(p) && constBd.InAtari(p))
00490     {
00491         const SgPoint lib = constBd.TheLiberty(p);
00492         GoModBoard mbd(constBd);
00493         GoBoard& bd = mbd.Board();
00494         const bool isLegal =
00495             GoBoardUtil::PlayIfLegal(bd, lib, SgOppBW(bd.GetStone(p)));
00496         if (  isLegal
00497            && bd.InAtari(lib)
00498            && ! bd.IsSingleStone(lib)
00499            )
00500             snapback = true;
00501         if (isLegal)
00502             bd.Undo();
00503     }
00504     return snapback;
00505 }
00506 
00507 bool GoBoardUtil::ManySecondaryLibs(const GoBoard& bd, SgPoint block)
00508 {
00509     // was always 8, not enough for loose ladder in CAPTURES.SGB, problem 2
00510     // one liberty can have 3 new secondary, total of 4 which are taken by
00511     // opp. move.
00512     // current value is just a guess, experiment.
00513     const int LIBERTY_LIMIT = 9;
00514     static SgMarker m;
00515     m.Clear();
00516     int nu = 0;
00517     for (GoBoard::LibertyIterator it(bd, block); it; ++it)
00518     {
00519         SgPoint p(*it);
00520         if (m.NewMark(p))
00521             if (++nu >= LIBERTY_LIMIT)
00522                 return true;
00523         for (SgNb4Iterator itn(p); itn; ++itn)
00524         {
00525             if (bd.IsEmpty(*itn) && m.NewMark(*itn))
00526                 if (++nu >= LIBERTY_LIMIT)
00527                     return true;
00528         }
00529     }
00530     return (nu >= LIBERTY_LIMIT);
00531 }
00532 
00533 SgArrayList<SgPoint,4> GoBoardUtil::NeighborsOfColor(const GoBoard& bd,
00534                                                      SgPoint p, int c)
00535 {
00536     SgArrayList<SgPoint,4> result;
00537     if (bd.IsColor(p - SG_NS, c))
00538         result.PushBack(p - SG_NS);
00539     if (bd.IsColor(p - SG_WE, c))
00540         result.PushBack(p - SG_WE);
00541     if (bd.IsColor(p + SG_WE, c))
00542         result.PushBack(p + SG_WE);
00543     if (bd.IsColor(p + SG_NS, c))
00544         result.PushBack(p + SG_NS);
00545     return result;
00546 }
00547 
00548 void GoBoardUtil::NeighborsOfColor(const GoBoard& bd, SgPoint p, int c,
00549                                    SgVector<SgPoint>* neighbors)
00550 {
00551     neighbors->Clear();
00552     if (bd.IsColor(p - SG_NS, c))
00553         neighbors->PushBack(p - SG_NS);
00554     if (bd.IsColor(p - SG_WE, c))
00555         neighbors->PushBack(p - SG_WE);
00556     if (bd.IsColor(p + SG_WE, c))
00557         neighbors->PushBack(p + SG_WE);
00558     if (bd.IsColor(p + SG_NS, c))
00559         neighbors->PushBack(p + SG_NS);
00560 }
00561 
00562 bool GoBoardUtil::TrompTaylorPassWins(const GoBoard& bd, SgBlackWhite toPlay)
00563 {
00564     if (toPlay != bd.ToPlay())
00565         // Not defined if non-alternating moves
00566         return false;
00567     if (! bd.Rules().CaptureDead() || bd.Rules().JapaneseScoring())
00568         return false;
00569     if (bd.GetLastMove() != SG_PASS)
00570         return false;
00571     float komi = bd.Rules().Komi().ToFloat();
00572     float score = GoBoardUtil::TrompTaylorScore(bd, komi);
00573     if ((score > 0 && toPlay == SG_BLACK)
00574         || (score < 0 && toPlay == SG_WHITE))
00575         return true;
00576     return false;
00577 }
00578 
00579 bool GoBoardUtil::PlayIfLegal(GoBoard& bd, SgPoint p, SgBlackWhite player)
00580 {
00581     if (p != SG_PASS && p != SG_COUPONMOVE)
00582     {
00583         if (! bd.IsEmpty(p))
00584             return false;
00585         if (! bd.Rules().AllowSuicide() && bd.IsSuicide(p, player))
00586             return false;
00587     }
00588     bd.Play(p, player);
00589     if (bd.LastMoveInfo(GO_MOVEFLAG_ILLEGAL))
00590     {
00591         bd.Undo();
00592         return false;
00593     }
00594     return true;
00595 }
00596 
00597 void GoBoardUtil::ReduceToAnchors(const GoBoard& bd,
00598                                   SgVector<SgPoint>* stones)
00599 {
00600     SG_ASSERT(stones);
00601     SgVector<SgPoint> result;
00602     for (SgVectorIterator<SgPoint> stone(*stones); stone; ++stone)
00603         if (bd.Occupied(*stone))
00604             result.Insert(bd.Anchor(*stone));
00605     stones->SwapWith(&result);
00606 }
00607 
00608 void GoBoardUtil::ReduceToAnchors(const GoBoard& bd,
00609                                   const SgVector<SgPoint>& stones,
00610                                   SgArrayList<SgPoint,SG_MAXPOINT>& anchors)
00611 {
00612     anchors.Clear();
00613     for (SgVectorIterator<SgPoint> it(stones); it; ++it)
00614         if (bd.Occupied(*it))
00615             anchors.Include(bd.Anchor(*it));
00616 }
00617 
00618 void GoBoardUtil::RegionCode(const GoBoard& bd,
00619                              const SgVector<SgPoint>& region,
00620                              SgHashCode* c)
00621 {
00622     BOOST_STATIC_ASSERT(SG_BLACK < 2);
00623     BOOST_STATIC_ASSERT(SG_WHITE < 2);
00624 
00625     c->Clear();
00626     for (SgVectorIterator<SgPoint> it(region); it; ++it)
00627     {
00628         SgPoint p = *it;
00629         if (bd.Occupied(p))
00630             SgHashUtil::XorZobrist(*c, p + bd.GetStone(p) * SG_MAXPOINT);
00631     }
00632 }
00633 
00634 bool GoBoardUtil::RemainingChineseHandicap(const GoBoard& bd)
00635 {
00636     const GoRules& rules = bd.Rules();
00637     return (! rules.JapaneseHandicap()
00638             && rules.Handicap() > bd.TotalNumStones(SG_BLACK));
00639 }
00640 
00641 float GoBoardUtil::ScoreSimpleEndPosition(const GoBoard& bd, float komi,
00642                                           bool noCheck)
00643 {
00644     int score = 0;
00645     for (GoBoard::Iterator it(bd); it; ++it)
00646         score += ScorePoint(bd, *it, noCheck);
00647     return float(score) - komi;
00648 }
00649 
00650 void GoBoardUtil::SharedLiberties(const GoBoard& bd,
00651                                   SgPoint block1,
00652                                   SgPoint block2,
00653                                   SgVector<SgPoint>* sharedLibs)
00654 {
00655     SG_ASSERT(sharedLibs);
00656     SG_ASSERT(bd.Occupied(block1));
00657     SG_ASSERT(bd.Occupied(block2));
00658     block1 = bd.Anchor(block1);
00659     block2 = bd.Anchor(block2);
00660     sharedLibs->Clear();
00661     for (GoBoard::LibertyIterator libIter(bd, block1); libIter; ++libIter)
00662     {
00663         SgPoint lib = *libIter;
00664         if (bd.IsLibertyOfBlock(lib, block2))
00665             sharedLibs->PushBack(lib);
00666     }
00667 }
00668 
00669 void GoBoardUtil::SharedLibertyBlocks(const GoBoard& bd, SgPoint anchor,
00670                                       int maxLib, SgVector<SgPoint>* blocks)
00671 {
00672     SG_ASSERT(blocks);
00673     // Mark all points and previous blocks.
00674     SgMarker& mark = bd.m_userMarker;
00675     SgReserveMarker reserve(mark);
00676     SG_UNUSED(reserve);
00677     mark.Clear();
00678     for (GoBoard::StoneIterator it1(bd, anchor); it1; ++it1)
00679         mark.Include(*it1);
00680     for (SgVectorIterator<SgPoint> it(*blocks); it; ++it)
00681     {
00682         SgPoint a = *it;
00683         for (GoBoard::StoneIterator it(bd, a); it; ++it)
00684             mark.Include(*it);
00685     }
00686     SgBlackWhite c = bd.GetStone(anchor);
00687     // Add the anchor of each adjacent block to the list of blocks.
00688     for (GoBoard::LibertyIterator it2(bd, anchor); it2; ++it2)
00689     {
00690         SgPoint p = *it2;
00691         if (bd.NumNeighbors(p, c) > 0)
00692         {
00693             if (bd.IsColor(p - SG_NS, c) && mark.NewMark(bd.Anchor(p - SG_NS))
00694                 && bd.AtMostNumLibs(p - SG_NS, maxLib))
00695                 blocks->PushBack(bd.Anchor(p - SG_NS));
00696             if (bd.IsColor(p - SG_WE, c) && mark.NewMark(bd.Anchor(p - SG_WE))
00697                 && bd.AtMostNumLibs(p - SG_WE, maxLib))
00698                 blocks->PushBack(bd.Anchor(p - SG_WE));
00699             if (bd.IsColor(p + SG_WE, c) && mark.NewMark(bd.Anchor(p + SG_WE))
00700                 && bd.AtMostNumLibs(p + SG_WE, maxLib))
00701                 blocks->PushBack(bd.Anchor(p + SG_WE));
00702             if (bd.IsColor(p + SG_NS, c) && mark.NewMark(bd.Anchor(p + SG_NS))
00703                 && bd.AtMostNumLibs(p + SG_NS, maxLib))
00704                 blocks->PushBack(bd.Anchor(p + SG_NS));
00705         }
00706     }
00707 }
00708 
00709 void GoBoardUtil::UndoAll(GoBoard& bd)
00710 {
00711     while (bd.CanUndo())
00712         bd.Undo();
00713 }
00714 
00715 bool GoBoardUtil::AtLeastTwoSharedLibs(const GoBoard& bd, SgPoint block1,
00716                                        SgPoint block2)
00717 {
00718     SG_ASSERT(bd.Occupied(block1));
00719     SG_ASSERT(bd.Occupied(block2));
00720     //block1 = bd.Anchor(block1);
00721     block2 = bd.Anchor(block2);
00722     bool fHasOneShared = false;
00723     for (GoBoard::LibertyIterator libIter(bd, block1); libIter; ++libIter)
00724     {
00725         if (bd.IsLibertyOfBlock(*libIter, block2))
00726         {
00727             if (fHasOneShared)
00728                 return true;
00729             fHasOneShared = true;
00730         }
00731     }
00732     return false;
00733 }
00734 
00735 void GoBoardUtil::TestForChain(GoBoard& bd, SgPoint block, SgPoint block2,
00736                                SgPoint lib, SgVector<SgPoint>* extended)
00737 {
00738     if (AtLeastTwoSharedLibs(bd, block, block2))
00739         extended->PushBack(block);
00740     else // protected lib.
00741     {
00742         GoRestoreToPlay r(bd);
00743         bd.SetToPlay(SgOppBW(bd.GetStone(block)));
00744         if (MoveNotLegalOrAtari(bd, lib))
00745             extended->PushBack(block);
00746     }
00747 }
00748 
00749 bool GoBoardUtil::HasStonesOfBothColors(const GoBoard& bd,
00750                                         const SgVector<SgPoint>& stones)
00751 {
00752     SgBWArray<bool> has(false);
00753     for (SgVectorIterator<SgPoint> it(stones); it; ++it)
00754     {
00755         if (bd.Occupied(*it))
00756         {
00757             SgBlackWhite color(bd.GetStone(*it));
00758             has[color] = true;
00759             if (has[SgOppBW(color)])
00760                 return true;
00761         }
00762     }
00763     return false;
00764 }
00765 
00766 bool GoBoardUtil::MoveNotLegalOrAtari(const GoBoard& bd, SgPoint move)
00767 {
00768     GoModBoard modBoard(bd);
00769     GoMoveExecutor execute(modBoard.Board(), move);
00770     return (! execute.IsLegal() || bd.InAtari(move));
00771 }
00772 
00773 bool GoBoardUtil::MoveLegalAndNotAtari(const GoBoard& bd, SgPoint move)
00774 {
00775     GoModBoard modBoard(bd);
00776     GoMoveExecutor execute(modBoard.Board(), move);
00777     return (execute.IsLegal() && ! bd.InAtari(move));
00778 }
00779 
00780 bool GoBoardUtil::ScorePosition(const GoBoard& bd,
00781                                 const SgPointSet& deadStones, float& score)
00782 {
00783     SgMarker marker;
00784     int stones = 0;
00785     int territory = 0;
00786     int dead = 0;
00787     for (GoBoard::Iterator it(bd); it; ++it)
00788     {
00789         SgPoint p = *it;
00790         if (bd.Occupied(p) && ! deadStones.Contains(p))
00791         {
00792             if (bd.GetColor(p) == SG_BLACK)
00793                 ++stones;
00794             else
00795                 --stones;
00796             continue;
00797         }
00798         if (marker.Contains(p))
00799             continue;
00800         int nuPoints = 0;
00801         int nuDeadWhite = 0;
00802         int nuDeadBlack = 0;
00803         bool isBlackAdjacent = false;
00804         bool isWhiteAdjacent = false;
00805         ScorePositionRecurse(bd, p, deadStones, marker, isBlackAdjacent,
00806                              isWhiteAdjacent, nuPoints, nuDeadWhite,
00807                              nuDeadBlack);
00808         if ((nuDeadWhite > 0 && nuDeadBlack > 0)
00809             || (isBlackAdjacent && nuDeadBlack > 0)
00810             || (isWhiteAdjacent && nuDeadWhite > 0))
00811             return false;
00812         dead += nuDeadBlack;
00813         dead -= nuDeadWhite;
00814         if (isBlackAdjacent && ! isWhiteAdjacent)
00815             territory += nuPoints;
00816         else if (isWhiteAdjacent && ! isBlackAdjacent)
00817             territory -= nuPoints;
00818     }
00819     int prisoners = bd.NumPrisoners(SG_BLACK) - bd.NumPrisoners(SG_WHITE);
00820     float komi = bd.Rules().Komi().ToFloat();
00821     if (bd.Rules().JapaneseScoring())
00822         score = float(territory - dead - prisoners) - komi;
00823     else
00824         score = float(territory + stones) - komi;
00825     return true;
00826 }
00827 
00828 int GoBoardUtil::Stones(const GoBoard& bd, SgPoint p, SgPoint stones[])
00829 {
00830     SG_ASSERT(bd.IsValidPoint(p));
00831     SG_ASSERT(bd.Occupied(p));
00832     if (bd.IsSingleStone(p))
00833     {
00834         stones[0] = p;
00835         return 1;
00836     }
00837     else
00838     {
00839         int nm = 0;
00840         for (GoBoard::StoneIterator it(bd, bd.Anchor(p)); it; ++it)
00841             stones[nm++] = p;
00842         return nm;
00843     }
00844 }
00845 
00846 bool GoBoardUtil::TwoPasses(const GoBoard& bd)
00847 {
00848     SgBlackWhite toPlay = bd.ToPlay();
00849     GoPlayerMove passToPlay(toPlay, SG_PASS);
00850     GoPlayerMove passOpp(SgOppBW(toPlay), SG_PASS);
00851     int moveNumber = bd.MoveNumber();
00852     return (  moveNumber >= 2
00853            && bd.Move(moveNumber - 1) == passOpp
00854            && bd.Move(moveNumber - 2) == passToPlay
00855            );
00856 }
00857 
00858 SgPointSet GoBoardUtil::Lines(const GoBoard& bd, SgGrid from, SgGrid to)
00859 {
00860     SG_ASSERT(from >= 1);
00861     SG_ASSERT(from <= to);
00862     SG_ASSERT(to <= (bd.Size() + 1) / 2);
00863     SgPointSet lines;
00864     for (SgGrid i = from; i <= to; ++i)
00865         lines |= bd.LineSet(i);
00866     return lines;
00867 }
00868 
00869 SgRect GoBoardUtil::GetDirtyRegion(const GoBoard& bd, SgMove move,
00870                                    SgBlackWhite colour, bool checklibs,
00871                                    bool premove)
00872 {
00873     SgRect dirty;
00874     if (move == SG_PASS)
00875         return dirty;
00876 
00877     SgBlackWhite opp = SgOppBW(colour);
00878 
00879     // Point played has changed
00880     dirty.Include(move);
00881 
00882     SgPointSet blocks;
00883 
00884     // This move adjusts libs for all adjacent blocks
00885     if (checklibs)
00886     {
00887         for (SgNb4Iterator inb(move); inb; ++inb)
00888             if (bd.Occupied(*inb))
00889                 for (GoBoard::StoneIterator istone(bd, *inb); istone;
00890                      ++istone)
00891                     dirty.Include(*istone);
00892     }
00893 
00894     // Check if this move will make a capture
00895     if (premove)
00896     {
00897         for (SgNb4Iterator inb(move); inb; ++inb)
00898         {
00899             if (bd.IsColor(*inb, opp) && bd.NumLiberties(*inb) == 1)
00900             {
00901                 for (GoBoard::StoneIterator icap(bd, *inb); icap; ++icap)
00902                 {
00903                     dirty.Include(*icap);
00904 
00905                     // Track blocks who gain libs as a result of capture
00906                     if (checklibs)
00907                     {
00908                         for (SgNb4Iterator inb2(*icap); inb2; ++inb2)
00909                             if (bd.IsColor(*inb2, colour))
00910                                 blocks.Include(bd.Anchor(*inb2));
00911                     }
00912                 }
00913             }
00914         }
00915     }
00916 
00917     // Check if this move did make a capture
00918     if (! premove && bd.CapturingMove())
00919     {
00920         for (GoPointList::Iterator icaptures(bd.CapturedStones()); icaptures;
00921              ++icaptures)
00922         {
00923             dirty.Include(*icaptures);
00924 
00925             // Track blocks who gained liberties as a result of a capture
00926             if (checklibs)
00927             {
00928                 for (SgNb4Iterator inb(*icaptures); inb; ++inb)
00929                     if (bd.IsColor(*inb, colour))
00930                         blocks.Include(bd.Anchor(*inb));
00931             }
00932         }
00933     }
00934 
00935     // Now mark all stones of blocks that gained liberties
00936     if (checklibs)
00937     {
00938         for (SgSetIterator iblocks(blocks); iblocks; ++iblocks)
00939             for (GoBoard::StoneIterator istone(bd, *iblocks); istone;
00940                  ++istone)
00941                 dirty.Include(*istone);
00942     }
00943 
00944     return dirty;
00945 }
00946 
00947 int GoBoardUtil::Approx2Libs(const GoBoard& board, SgPoint block,
00948     SgPoint p, SgBlackWhite color)
00949 {
00950     int libs2 = 0;
00951     for (SgNb4Iterator inb(p); inb; ++inb)
00952     {
00953         SgPoint nb = *inb;
00954         if (board.IsEmpty(nb))
00955             libs2++;
00956         else if (board.IsColor(nb, color)
00957             && board.Anchor(nb) != board.Anchor(block))
00958             libs2 += board.NumLiberties(nb); // May double count libs
00959     }
00960 
00961     return libs2;
00962 }
00963 
00964 //----------------------------------------------------------------------------
00965 
00966 std::ostream& operator<<(std::ostream& out, const GoBoardWrite::WriteMap& w)
00967 {
00968     w.Points().Write(out, w.Board().Size());
00969     return out;
00970 }
00971 
00972 //----------------------------------------------------------------------------


Sun Mar 13 2011 Doxygen 1.7.1