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


17 Jun 2010 Doxygen 1.4.7