00001
00002
00003
00004
00005
00006 #include "SgSystem.h"
00007 #include "GoEyeUtil.h"
00008
00009 #include "GoBoardUtil.h"
00010 #include "GoEyeCount.h"
00011 #include "SgNbIterator.h"
00012
00013
00014 namespace
00015 {
00016
00017
00018 int NuEdgePoints(const GoBoard& bd, const SgPointSet& points)
00019 {
00020 return (points & bd.LineSet(1)).Size();
00021 }
00022
00023
00024
00025
00026
00027 bool IsBulkyFour(const SgPointSet& points)
00028 {
00029 SG_ASSERT(points.IsSize(4));
00030 SgSetIterator it(points);
00031 SgPoint p1 = *it;
00032 ++it;
00033 if (*it != p1 + SG_WE)
00034 return false;
00035 ++it;
00036 if (*it != p1 + SG_NS)
00037 return false;
00038 ++it;
00039 if (*it != p1 + SG_WE + SG_NS)
00040 return false;
00041 SG_ASSERT(GoEyeUtil::DegreeCode(points) == 400);
00042 return true;
00043 }
00044
00045 bool IsTShape(const SgPointSet& block)
00046 {
00047 return GoEyeUtil::DegreeCode(block) == 1030;
00048 }
00049
00050 bool IsBulkyFive(const SgPointSet& block)
00051 {
00052 return GoEyeUtil::DegreeCode(block) == 1310;
00053 }
00054
00055 bool IsCross(const SgPointSet& block)
00056 {
00057 return GoEyeUtil::DegreeCode(block) == 10040;
00058 }
00059
00060 bool IsRabbitySix(const SgPointSet& block)
00061 {
00062 return GoEyeUtil::DegreeCode(block) == 10320;
00063 }
00064
00065 bool Is2x3Area(const SgPointSet& area)
00066 {
00067 return GoEyeUtil::DegreeCode(area) == 2400;
00068 }
00069
00070
00071
00072
00073
00074 bool IsAliveBlock(const SgPointSet& block)
00075 {
00076 const int code = GoEyeUtil::DegreeCode(block);
00077
00078 return code == 220
00079 || code == 320
00080 || code == 1130
00081 || code == 2400
00082 || code == 2220
00083 ;
00084 }
00085
00086 bool CheckAlwaysAlive8Code(long code)
00087 {
00088 return code == 11210
00089 || code == 3110
00090 ;
00091 }
00092
00093
00094
00095
00096
00097 bool IsAlwaysAliveBlock(const SgPointSet& block)
00098 {
00099 const int code = GoEyeUtil::DegreeCode(block);
00100
00101 return code == 320
00102 || ( code == 1130
00103 && CheckAlwaysAlive8Code(GoEyeUtil::DegreeCode8(block))
00104 )
00105 ;
00106 }
00107
00108
00109 bool IsNakadeBlock(const GoBoard& bd,
00110 const SgPointSet& block)
00111 {
00112 if (! GoEyeUtil::IsNakadeShape(block))
00113 return false;
00114 return bd.NumStones(block.PointOf()) == block.Size();
00115 }
00116
00117
00118
00119
00120 bool AlmostFilledByLivingShape(const GoBoard& bd,
00121 const SgPointSet& points,
00122 SgBlackWhite stoneColor)
00123 {
00124
00125 SG_ASSERT(points.Border(bd.Size()).SubsetOf(bd.All(SgOppBW(stoneColor))));
00126
00127 return (points & bd.AllEmpty()).IsSize(1)
00128 && IsAliveBlock(points & bd.All(stoneColor));
00129 }
00130
00131
00132
00133 bool ContainsLivingShape(const GoBoard& bd,
00134 const SgPointSet& points,
00135 SgBlackWhite stoneColor)
00136 {
00137
00138 SG_ASSERT(points.Border(bd.Size()).SubsetOf(bd.All(SgOppBW(stoneColor))));
00139
00140 return IsAlwaysAliveBlock(points & bd.All(stoneColor));
00141 }
00142
00143
00144
00145 bool AlmostFilledByNakade(const GoBoard& bd,
00146 const SgPointSet& points,
00147 SgBlackWhite stoneColor)
00148 {
00149
00150 SG_ASSERT(points.Border(bd.Size()).SubsetOf(bd.All(SgOppBW(stoneColor))));
00151
00152 if ((points & bd.AllEmpty()).IsSize(1))
00153 {
00154 return IsNakadeBlock(bd, points & bd.All(stoneColor));
00155 }
00156 return false;
00157 }
00158
00159
00160
00161
00162
00163 GoEyeStatus BulkyFiveNakade(const GoBoard& bd,
00164 const SgPointSet& points,
00165 SgBlackWhite stoneColor)
00166 {
00167 const SgPointSet stones = points & bd.All(stoneColor);
00168 if ( IsBulkyFive(points)
00169 && stones.IsSize(3)
00170 )
00171 {
00172 const SgPoint p = stones.PointOf();
00173 if (bd.NumStones(p) == 3)
00174
00175
00176 {
00177 SG_ASSERT((points & bd.AllEmpty()).IsSize(2));
00178 for (SgSetIterator it(points & bd.AllEmpty()); it; ++it)
00179 {
00180 if (bd.NumNeighbors(*it, stoneColor) == 0)
00181 {
00182 return EYE_ONE_AND_HALF;
00183 }
00184 }
00185 return EYE_ONE;
00186 }
00187 else
00188 {
00189 return GoEyeUtil::DegreeCode(stones) == 3 ?
00190 EYE_ONE_AND_HALF :
00191 EYE_TWO;
00192 }
00193
00194 }
00195 return EYE_UNKNOWN;
00196 }
00197
00198
00199 GoEyeStatus Special2x3Cases(const GoBoard& bd,
00200 const SgPointSet& points,
00201 SgBlackWhite stoneColor)
00202 {
00203 const SgPointSet stones = points & bd.All(stoneColor);
00204 const int nuStones = stones.Size();
00205 if (nuStones > 0)
00206 {
00207 const int code = GoEyeUtil::DegreeCode(stones);
00208 const long code8 = GoEyeUtil::DegreeCode8(stones);
00209
00210
00211 if (code == 220 && code8 == 2200)
00212 return EYE_ONE_AND_HALF;
00213
00214
00215 if (code == 21 && code8 == 120)
00216 return EYE_TWO;
00217 if (NuEdgePoints(bd, points) == 3)
00218 {
00219 const SgPoint p = stones.PointOf();
00220 switch (nuStones)
00221 {
00222 case 1:
00223
00224 if (bd.Line(p) == 1
00225 && bd.HasNeighbors(p, SgOppBW(stoneColor)))
00226 return EYE_ONE_AND_HALF;
00227 break;
00228 case 2:
00229
00230 if ( bd.Line(p) == 1
00231 && code == 2
00232 && NuEdgePoints(bd, stones) == 2
00233 )
00234 return EYE_ONE_AND_HALF;
00235
00236
00237 if ( code == 2
00238 && code8 == 20
00239 )
00240 {
00241 const SgPoint p1 = (stones & bd.LineSet(1)).PointOf();
00242 if (bd.HasNeighbors(p1, SgOppBW(stoneColor)))
00243 return EYE_ONE;
00244 }
00245 break;
00246 case 3 :
00247
00248 if ( code == 3
00249 && code8 == 120
00250 )
00251 {
00252 const SgPoint p1 = (stones & bd.LineSet(1)).PointOf();
00253 if (bd.HasNeighbors(p1, SgOppBW(stoneColor)))
00254 return EYE_ONE;
00255 }
00256 break;
00257 }
00258 }
00259 }
00260 return EYE_UNKNOWN;
00261 }
00262
00263
00264 inline bool TestDiagonal(const SgPointSet& set, SgPoint p, int ns, int we)
00265 {
00266 return ! set[p+ns+we]
00267 && ! ( set[p+ns-we]
00268 && set[p-we]
00269 && set[p-ns-we]
00270 && set[p-ns]
00271 && set[p-ns+we]
00272 );
00273 }
00274
00275
00276 inline bool TestOpposite(const SgPointSet& set, SgPoint p, int ns, int we)
00277 {
00278 return ! (set[p-ns-we] && set[p-we] && set[p+ns-we])
00279 && ! (set[p-ns+we] && set[p+we] && set[p+ns+we]);
00280 }
00281
00282
00283
00284
00285 bool IsBentFour(const SgPointSet& points, int boardSize, SgPoint* vital)
00286 {
00287 SG_ASSERT(points.IsSize(4));
00288
00289 if ( points.Contains(SgPointUtil::Pt(1, 1))
00290 && points.Contains(SgPointUtil::Pt(2, 1))
00291 && points.Contains(SgPointUtil::Pt(1, 2))
00292 )
00293 {
00294 if (points.Contains(SgPointUtil::Pt(3, 1)))
00295 {
00296 *vital = SgPointUtil::Pt(2, 1);
00297 return true;
00298 }
00299 else if (points.Contains(SgPointUtil::Pt(1, 3)))
00300 {
00301 *vital = SgPointUtil::Pt(1, 2);
00302 return true;
00303 }
00304 }
00305 if ( points.Contains(SgPointUtil::Pt(1, boardSize))
00306 && points.Contains(SgPointUtil::Pt(2, boardSize))
00307 && points.Contains(SgPointUtil::Pt(1, boardSize - 1))
00308 )
00309 {
00310 if (points.Contains(SgPointUtil::Pt(3, boardSize)))
00311 {
00312 *vital = SgPointUtil::Pt(2, boardSize);
00313 return true;
00314 }
00315 else if (points.Contains(SgPointUtil::Pt(1, boardSize - 2)))
00316 {
00317 *vital = SgPointUtil::Pt(1, boardSize - 1);
00318 return true;
00319 }
00320 }
00321 if ( points.Contains(SgPointUtil::Pt(boardSize, 1))
00322 && points.Contains(SgPointUtil::Pt(boardSize - 1, 1))
00323 && points.Contains(SgPointUtil::Pt(boardSize, 2))
00324 )
00325 {
00326 if (points.Contains(SgPointUtil::Pt(boardSize - 2, 1)))
00327 {
00328 *vital = SgPointUtil::Pt(boardSize - 1, 1);
00329 return true;
00330 }
00331 else if (points.Contains(SgPointUtil::Pt(boardSize, 3)))
00332 {
00333 *vital = SgPointUtil::Pt(boardSize, 2);
00334 return true;
00335 }
00336 }
00337 if ( points.Contains(SgPointUtil::Pt(boardSize, boardSize))
00338 && points.Contains(SgPointUtil::Pt(boardSize - 1, boardSize))
00339 && points.Contains(SgPointUtil::Pt(boardSize, boardSize - 1))
00340 )
00341 {
00342 if (points.Contains(SgPointUtil::Pt(boardSize - 2, boardSize)))
00343 {
00344 *vital = SgPointUtil::Pt(boardSize - 1, boardSize);
00345 return true;
00346 }
00347 else if (points.Contains(SgPointUtil::Pt(boardSize, boardSize - 2)))
00348 {
00349 *vital = SgPointUtil::Pt(boardSize, boardSize - 1);
00350 return true;
00351 }
00352 }
00353
00354 return false;
00355 }
00356
00357
00358
00359 bool TwoDiagonalStonesInBulkyFour(const GoBoard& bd,
00360 const SgPointSet& points,
00361 SgBlackWhite stoneColor)
00362 {
00363
00364 SG_ASSERT(points.Border(bd.Size()).SubsetOf(bd.All(SgOppBW(stoneColor))));
00365
00366 if ((points & bd.All(stoneColor)).IsSize(2))
00367 {
00368
00369 SG_ASSERT((points & bd.AllEmpty()).IsSize(2));
00370
00371 const SgPoint p = points.PointOf();
00372 if (bd.IsEmpty(p))
00373 return bd.NumNeighbors(p, stoneColor) == 2;
00374 else
00375 return bd.NumEmptyNeighbors(p) == 2;
00376 }
00377 return false;
00378 }
00379
00380 inline bool ProcessStatus(GoEyeStatus status,
00381 bool& isNakade,
00382 bool& makeNakade)
00383 {
00384 if (status == EYE_ONE)
00385 isNakade = true;
00386 else if (status == EYE_ONE_AND_HALF)
00387 makeNakade = true;
00388 return status != EYE_UNKNOWN;
00389 }
00390 }
00391
00392
00393 int GoEyeUtil::DegreeCode(const SgPointSet& points)
00394 {
00395 int degrees[5] = {0,0,0,0,0};
00396
00397 for (SgSetIterator it(points); it; ++it)
00398 {
00399 const SgPoint p(*it);
00400 int nbs = 0;
00401 for (SgNb4Iterator it(p); it; ++it)
00402 {
00403 if (points.Contains(*it))
00404 ++nbs;
00405 }
00406 ++(degrees[nbs]);
00407 }
00408 return degrees[0]
00409 + 10 * degrees[1]
00410 + 100 * degrees[2]
00411 + 1000 * degrees[3]
00412 + 10000 * degrees[4];
00413 }
00414
00415 long GoEyeUtil::DegreeCode8(const SgPointSet& points)
00416 {
00417 int degrees[9] = {0,0,0,0,0};
00418
00419 for (SgSetIterator it(points); it; ++it)
00420 {
00421 const SgPoint p(*it);
00422 int nbs = 0;
00423 for (SgNb8Iterator it(p); it; ++it)
00424 {
00425 if (points.Contains(*it))
00426 ++nbs;
00427 }
00428 ++(degrees[nbs]);
00429 }
00430 return degrees[0]
00431 + 10 * degrees[1]
00432 + 100 * degrees[2]
00433 + 1000 * degrees[3]
00434 + 10000 * degrees[4]
00435 + 100000 * degrees[5]
00436 + 1000000 * degrees[6]
00437 + 10000000 * degrees[7]
00438 + 100000000 * degrees[8];
00439 }
00440
00441 bool GoEyeUtil::IsNakadeShape(const SgPointSet& area)
00442 {
00443 switch (area.Size())
00444 {
00445 case 1:
00446 case 2:
00447 case 3: return true;
00448 case 4: return IsBulkyFour(area) || IsTShape(area);
00449 case 5: return IsBulkyFive(area) || IsCross(area);
00450 case 6: return IsRabbitySix(area);
00451 default:
00452 return false;
00453 }
00454 }
00455
00456 bool GoEyeUtil::IsSinglePointEye(const GoBoard& bd, SgPoint p,
00457 SgBlackWhite color)
00458 {
00459 SG_ASSERT(bd.IsEmpty(p));
00460 const SgBlackWhite opp = SgOppBW(color);
00461 if (bd.HasEmptyNeighbors(p) || bd.HasNeighbors(p, opp))
00462 return false;
00463 if (bd.Line(p) == 1)
00464 return ! (bd.HasDiagonals(p, SG_EMPTY) || bd.HasDiagonals(p, opp));
00465 return (bd.NumDiagonals(p, SG_EMPTY) + bd.NumDiagonals(p, opp)) <= 1;
00466 }
00467
00468 bool GoEyeUtil::IsPossibleEye(const GoBoard& board, SgBlackWhite color,
00469 SgPoint p)
00470 {
00471 bool isPossibleEye = false;
00472 SG_ASSERT(board.GetColor(p) != color);
00473 const SgBlackWhite opp = SgOppBW(color);
00474 if (board.Line(p) == 1)
00475 {
00476 const int nuOwn = (board.Pos(p) == 1) ? 2 : 4;
00477 if ( board.Num8Neighbors(p, color) == nuOwn
00478 && board.Num8EmptyNeighbors(p) == 1
00479 )
00480 {
00481 isPossibleEye = true;
00482 }
00483 }
00484 else
00485 {
00486
00487 if ( board.NumNeighbors(p, color) == 4
00488 && board.NumDiagonals(p, color) == 2
00489 && board.NumEmptyDiagonals(p) > 0
00490 )
00491 {
00492 isPossibleEye = true;
00493 }
00494
00495 else if ( board.NumNeighbors(p, color) == 3
00496 && board.NumNeighbors(p, opp) == 0
00497 && board.NumDiagonals(p, color) >= 3
00498 )
00499 {
00500 isPossibleEye = true;
00501 }
00502 }
00503
00504 return isPossibleEye;
00505 }
00506
00507 bool GoEyeUtil::NumberOfMoveToEye(const GoBoard& board, SgBlackWhite color,
00508 SgPoint p, int& number)
00509 {
00510 SG_ASSERT(board.IsEmpty(p));
00511 SgBlackWhite att = SgOppBW(color);
00512
00513 if ( board.Line(p) == 1)
00514 {
00515 if ( board.Num8Neighbors(p, att) > 0 )
00516 return false;
00517 else
00518 {
00519 number = board.Num8EmptyNeighbors(p);
00520 return true;
00521 }
00522 }
00523 else
00524 {
00525 if ( board.Num8Neighbors(p, att) >= 2 )
00526 return false;
00527 else if ( board.NumNeighbors(p, att) > 0 )
00528 return false;
00529 else
00530 {
00531 number = board.Num8EmptyNeighbors(p);
00532 return true;
00533 }
00534 }
00535
00536 }
00537
00538 bool GoEyeUtil::IsSinglePointEye2(const GoBoard& board, SgPoint p,
00539 SgBlackWhite color, SgVector<SgPoint>& eyes)
00540 {
00541
00542 if (! board.IsColor(p, SG_EMPTY))
00543 return false;
00544
00545 SgBoardColor opp = SgOppBW(color);
00546 for (SgNb4Iterator adj(p); adj; ++adj)
00547 {
00548 SgBoardColor adjColor = board.GetColor(*adj);
00549 if (adjColor == opp || adjColor == SG_EMPTY)
00550 return false;
00551 }
00552
00553 int baddiags = 0;
00554 int maxbaddiags = (board.Line(p) == 1 ? 0 : 1);
00555 for (SgNb4DiagIterator it(p); it; ++it)
00556 {
00557 if (board.IsColor(*it, opp))
00558 ++baddiags;
00559 if (board.IsColor(*it, SG_EMPTY) && ! eyes.Contains(*it))
00560 {
00561
00562 eyes.PushBack(p);
00563 if (! IsSinglePointEye2(board, *it, color, eyes))
00564 ++baddiags;
00565 eyes.PopBack();
00566 }
00567 if (baddiags > maxbaddiags)
00568 return false;
00569 }
00570 return true;
00571 }
00572
00573 bool GoEyeUtil::IsSinglePointEye2(const GoBoard& board, SgPoint p,
00574 SgBlackWhite color)
00575 {
00576 SgVector<SgPoint> emptylist;
00577 return IsSinglePointEye2(board, p, color, emptylist);
00578 }
00579
00580 bool GoEyeUtil::NumberOfMoveToEye2(const GoBoard& board, SgBlackWhite color,
00581 SgPoint p, int& nummoves)
00582 {
00583 nummoves = 0;
00584 bool capturing = false;
00585 SgVector<SgPoint> usedpoints;
00586 usedpoints.PushBack(p);
00587 SgPointSet counted;
00588
00589
00590 if (board.IsColor(p, color))
00591 return false;
00592
00593
00594 if (board.IsColor(p, SgOppBW(color)))
00595 {
00596 capturing = true;
00597
00598
00599 if (SinglePointSafe2(board, p))
00600 return false;
00601
00602 for (GoBoard::LibertyIterator libit(board, p); libit; ++libit)
00603 counted.Include(*libit);
00604 }
00605
00606
00607 for (SgNb4Iterator nb(p); nb; ++nb)
00608 {
00609 SgPoint adj = *nb;
00610
00611
00612 if (board.IsColor(adj, SG_EMPTY))
00613 {
00614 counted.Include(adj);
00615 }
00616
00617
00618 else if (board.IsColor(adj, SgOppBW(color)))
00619 {
00620 if (capturing)
00621 counted.Include(adj);
00622 else
00623 return false;
00624 }
00625 }
00626
00627
00628 SgPoint toignore = SG_NULLPOINT;
00629 int maxcost = 0;
00630 int infcost = 1000;
00631 if (board.Line(p) > 1)
00632 {
00633 for (SgNb4DiagIterator nbd(p); nbd; ++nbd)
00634 {
00635 SgPoint diag = *nbd;
00636 int cost = 0;
00637
00638 if ( board.IsColor(diag, SG_EMPTY)
00639 && ! IsSinglePointEye2(board, diag, color, usedpoints))
00640 {
00641 cost = 1;
00642 }
00643
00644 else if (board.IsColor(diag, SgOppBW(color)))
00645 {
00646
00647 if (SinglePointSafe2(board, diag))
00648 cost = infcost;
00649 else
00650 cost = board.NumLiberties(diag);
00651 }
00652
00653 if (cost > maxcost)
00654 {
00655 maxcost = cost;
00656 toignore = diag;
00657 }
00658 }
00659 }
00660
00661
00662 for (SgNb4DiagIterator nbd(p); nbd; ++nbd)
00663 {
00664 SgPoint diag = *nbd;
00665 if (diag == toignore)
00666 continue;
00667
00668
00669 if ( board.IsColor(diag, SG_EMPTY)
00670 && ! IsSinglePointEye2(board, diag, color, usedpoints))
00671 {
00672 counted.Include(diag);
00673 }
00674
00675
00676 else if (board.IsColor(diag, SgOppBW(color)))
00677 {
00678 if (SinglePointSafe2(board, diag))
00679 return false;
00680 else
00681 {
00682 counted.Include(diag);
00683 for (GoBoard::LibertyIterator libit(board, diag); libit;
00684 ++libit)
00685 counted.Include(*libit);
00686 }
00687 }
00688 }
00689
00690 nummoves = counted.Size();
00691 return true;
00692 }
00693
00694 int GoEyeUtil::CountSinglePointEyes2(const GoBoard& board, SgPoint p)
00695 {
00696 if (! board.Occupied(p))
00697 return 0;
00698
00699 SgBlackWhite color = board.GetColor(p);
00700 int numeyes = 0;
00701
00702 for (GoBoard::LibertyIterator lib(board, p); lib; ++lib)
00703 {
00704 if (IsSinglePointEye2(board, *lib, color))
00705 numeyes++;
00706 }
00707
00708 return numeyes;
00709 }
00710
00711 bool GoEyeUtil::SinglePointSafe2(const GoBoard& board, SgPoint p)
00712 {
00713 int numeyes = CountSinglePointEyes2(board, p);
00714 return numeyes >= 2;
00715 }
00716
00717 bool GoEyeUtil::IsLocalSplitPt(SgPoint p, const SgPointSet& set)
00718 {
00719 int nuNb = 0;
00720 for (SgNb4Iterator it(p); it; ++it)
00721 {
00722 if (set.Contains(*it))
00723 {
00724 ++nuNb;
00725 if (nuNb >= 2)
00726 break;
00727 }
00728 }
00729 if (nuNb >= 2)
00730 {
00731 if (set[p - SG_NS])
00732 {
00733 if (set[p - SG_WE] && TestDiagonal(set, p, -SG_NS, -SG_WE))
00734 return true;
00735 if (set[p + SG_NS] && TestOpposite(set, p, SG_NS, SG_WE))
00736 return true;
00737 if (set[p + SG_WE] && TestDiagonal(set, p, -SG_NS, +SG_WE))
00738 return true;
00739 }
00740 if (set[p + SG_NS])
00741 {
00742 if (set[p - SG_WE] && TestDiagonal(set, p, +SG_NS, -SG_WE))
00743 return true;
00744 if (set[p + SG_WE] && TestDiagonal(set, p, +SG_NS, +SG_WE))
00745 return true;
00746 }
00747 if (set[p - SG_WE] && set[p + SG_WE]
00748 && TestOpposite(set, p, SG_WE, SG_NS))
00749 return true;
00750 }
00751 return false;
00752 }
00753
00754 bool GoEyeUtil::IsSplitPt(SgPoint p, const SgPointSet& points)
00755 {
00756 SG_ASSERT(points[p]);
00757 if (! IsLocalSplitPt(p, points))
00758 return false;
00759 SgPointSet s(points);
00760 s.Exclude(p);
00761 return ! s.IsConnected();
00762 }
00763
00764 bool GoEyeUtil::CanBecomeSinglePointEye (const GoBoard& board, SgPoint p,
00765 const SgPointSet& oppSafe)
00766 {
00767 SG_ASSERT(! oppSafe[p]);
00768
00769 for (SgNb4Iterator it(p); it; ++it)
00770 {
00771 if (oppSafe[*it])
00772 return false;
00773 }
00774
00775 int nu = 0;
00776 for (SgNb4DiagIterator dit(p); dit; ++dit)
00777 {
00778 if (oppSafe[*dit])
00779 {
00780 if (board.Line(p) == 1)
00781 return false;
00782 ++nu;
00783 if (nu > 1)
00784 return false;
00785 }
00786 }
00787
00788 return true;
00789 }
00790
00791
00792 void GoEyeUtil::TestNakade(const SgPointSet& points,
00793 const GoBoard& bd,
00794 SgBlackWhite color,
00795 bool isFullyEnclosed,
00796 bool& isNakade,
00797 bool& makeNakade,
00798 bool& makeFalse,
00799 bool& maybeSeki,
00800 bool& sureSeki,
00801 SgPoint* vital)
00802 {
00803
00804
00805
00806
00807
00808
00809 SG_UNUSED(makeFalse);
00810 isNakade = makeNakade = maybeSeki = sureSeki = false;
00811 SgPoint vitalP(SG_NULLPOINT);
00812 const SgBlackWhite opp = SgOppBW(color);
00813 const int nuPoints = points.Size();
00814
00815 SG_ASSERT(nuPoints >= 3);
00816
00817
00818 if (nuPoints == 4)
00819 {
00820 if (IsBulkyFour(points))
00821 {
00822 if ( isFullyEnclosed
00823 && TwoDiagonalStonesInBulkyFour(bd, points, opp)
00824 )
00825 makeNakade = true;
00826 else
00827 isNakade = true;
00828 return;
00829 }
00830 else if ( isFullyEnclosed
00831 && points.SubsetOf(bd.AllEmpty())
00832 && IsBentFour(points, bd.Size(), vital)
00833 )
00834 {
00835 makeNakade = true;
00836 return;
00837 }
00838 }
00839 else if (isFullyEnclosed && nuPoints == 5)
00840 {
00841 const GoEyeStatus status = BulkyFiveNakade(bd, points, opp);
00842 if (ProcessStatus(status, isNakade, makeNakade))
00843 return;
00844 }
00845 else if (isFullyEnclosed && nuPoints == 6)
00846 {
00847 if (Is2x3Area (points))
00848 {
00849 GoEyeStatus status = Special2x3Cases(bd, points, opp);
00850 if (ProcessStatus(status, isNakade, makeNakade))
00851 return;
00852 }
00853 }
00854 if ( isFullyEnclosed
00855 && AlmostFilledByNakade(bd, points, opp)
00856 )
00857 {
00858 isNakade = true;
00859 return;
00860 }
00861
00862 if ( isFullyEnclosed
00863 && ( AlmostFilledByLivingShape(bd, points, opp)
00864 || ContainsLivingShape(bd, points, opp)
00865 )
00866 )
00867 {
00868 return;
00869 }
00870
00871 int nuMakeNakade = 0;
00872 int nuVitalOccupied = 0;
00873 bool hasDivider = false;
00874
00875
00876
00877
00878 for (SgSetIterator it(points); it; ++it)
00879 {
00880 SgPoint p(*it);
00881 if (IsVitalPt(points, p, opp, bd))
00882 {
00883 if (bd.IsEmpty(p))
00884 {
00885 if (bd.IsLegal(p, opp))
00886 {
00887 ++nuMakeNakade;
00888 vitalP = p;
00889 }
00890 else
00891 hasDivider = true;
00892 }
00893 else
00894 ++nuVitalOccupied;
00895 }
00896 }
00897
00898 if (hasDivider)
00899 {
00900 }
00901 else if (nuMakeNakade == 1)
00902 {
00903 makeNakade = true;
00904 *vital = vitalP;
00905 }
00906 else if (nuMakeNakade > 0)
00907 isNakade = false;
00908 else if (nuVitalOccupied < 3)
00909 isNakade = true;
00910 else
00911 {
00912 maybeSeki = true;
00913
00914 }
00915 }
00916
00917 bool GoEyeUtil::IsVitalPt(const SgPointSet& points, SgPoint p,
00918 SgBlackWhite opp,
00919 const GoBoard& bd)
00920 {
00921
00922
00923
00924
00925
00926
00927 int numNb = bd.NumEmptyNeighbors(p) + bd.NumNeighbors(p, opp);
00928 if (numNb >= 2)
00929 {
00930 if (numNb >= 4)
00931 return true;
00932 int nu = IsTreeShape(points) ? 2 : 3;
00933 if (numNb >= nu)
00934 {
00935 if (numNb == 2 && bd.IsEmpty(p))
00936 return IsSplitPt(p, points);
00937 else
00938 return true;
00939 }
00940 }
00941 return false;
00942 }
00943
00944 bool GoEyeUtil::CheckInterior(const GoBoard& bd, const SgPointSet& area,
00945 SgBlackWhite opp, bool checkBlocks)
00946 {
00947 bool hasSingleNbPoint = false;
00948 int nuPoints = 0;
00949 for (SgSetIterator it(area); it; ++it)
00950 {
00951 const SgPoint p(*it);
00952 if (bd.IsEmpty(p))
00953 {
00954 int nuNbs = 0;
00955 if (area.Contains(p + SG_NS))
00956 ++nuNbs;
00957 if (area.Contains(p - SG_NS))
00958 ++nuNbs;
00959 if (area.Contains(p + SG_WE))
00960 ++nuNbs;
00961 if (area.Contains(p - SG_WE))
00962 ++nuNbs;
00963 if (nuNbs == 1)
00964 hasSingleNbPoint = true;
00965 else if (nuNbs > 2)
00966 return false;
00967 }
00968 else if (p == bd.Anchor(p))
00969 {
00970 if (bd.GetColor(p) != opp)
00971
00972 return false;
00973 int nuLibs = bd.NumLiberties(p);
00974 if (nuLibs == 1)
00975 hasSingleNbPoint = true;
00976 else if (checkBlocks && nuLibs > 2)
00977 return false;
00978 }
00979 ++nuPoints;
00980 }
00981 return nuPoints == 1 || hasSingleNbPoint;
00982 }
00983
00984 bool GoEyeUtil::IsTreeShape(const SgPointSet& area)
00985 {
00986 for (SgSetIterator it(area); it; ++it)
00987 {
00988 const SgPoint p(*it);
00989 if ( area.Contains(p + SG_NS)
00990 && area.Contains(p + SG_WE)
00991 && area.Contains(p + SG_NS + SG_WE)
00992 )
00993 return false;
00994 }
00995 return true;
00996 }