00001
00002
00003
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
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
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 }
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
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
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
00190 SG_ASSERT(blocks);
00191
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
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
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
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;
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)
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
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
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
00511
00512
00513
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
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
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
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
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
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
00878 dirty.Include(move);
00879
00880 SgPointSet blocks;
00881
00882
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
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
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
00916 if (! premove && bd.CapturingMove())
00917 {
00918 for (GoPointList::Iterator icaptures(bd.CapturedStones()); icaptures;
00919 ++icaptures)
00920 {
00921 dirty.Include(*icaptures);
00922
00923
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
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);
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