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