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