/** Return true, if point is on edge line and no stone is within a Manhattan distance of 4. */ bool IsEmptyEdge(const GoBoard& bd, SgPoint p) { SG_ASSERT (bd.IsEmpty(p)); SG_ASSERT (bd.Line(p) == 1); if (bd.Num8EmptyNeighbors(p) < 5) return false; const SgPoint pUp = p + bd.Up(p); SG_ASSERT(bd.Line(pUp) == 2); SG_ASSERT(bd.Pos(pUp) >= 2); // (1,1) goes to (2,2) if (bd.Num8EmptyNeighbors(pUp) < 8) return false; switch (bd.Pos(p)) { case 1: // (1,1) point case 2: // (1,2) point case 3: return IsEmptyOrInCorner(bd, p, bd.Left(p)) && IsEmptyOrInCorner(bd, p, bd.Right(p)); // assume in empty corner, 1st line is always // dominated bymove on 2nd line above default: // > 3, can test both sides easily return IsEmpty2x3Box(bd, p + 2*bd.Left(p)) && IsEmpty2x3Box(bd, p + 2*bd.Right(p)) ; } }
bool GoEyeUtil::CanBecomeSinglePointEye (const GoBoard& board, SgPoint p, const SgPointSet& oppSafe) { SG_ASSERT(! oppSafe[p]); for (SgNb4Iterator it(p); it; ++it) { if (oppSafe[*it]) return false; } int nu = 0; for (SgNb4DiagIterator dit(p); dit; ++dit) { if (oppSafe[*dit]) { if (board.Line(p) == 1) return false; ++nu; if (nu > 1) return false; } } return true; }
bool GoEyeUtil::IsSinglePointEye2(const GoBoard& board, SgPoint p, SgBlackWhite color, SgVector<SgPoint>& eyes) { // Must be an empty point if (! board.IsColor(p, SG_EMPTY)) return false; // All adjacent neighbours must be friendly SgBoardColor opp = SgOppBW(color); for (SgNb4Iterator adj(p); adj; ++adj) { SgBoardColor adjColor = board.GetColor(*adj); if (adjColor == opp || adjColor == SG_EMPTY) return false; } // All diagonals (with up to one exception) must be friendly or an eye int baddiags = 0; int maxbaddiags = (board.Line(p) == 1 ? 0 : 1); for (SgNb4DiagIterator it(p); it; ++it) { if (board.IsColor(*it, opp)) ++baddiags; if (board.IsColor(*it, SG_EMPTY) && ! eyes.Contains(*it)) { // Assume this point is an eye and recurse eyes.PushBack(p); if (! IsSinglePointEye2(board, *it, color, eyes)) ++baddiags; eyes.PopBack(); } if (baddiags > maxbaddiags) return false; } return true; }
bool GoEyeUtil::NumberOfMoveToEye(const GoBoard& board, SgBlackWhite color, SgPoint p, int& number) { SG_ASSERT(board.IsEmpty(p)); SgBlackWhite att = SgOppBW(color); // attacker if ( board.Line(p) == 1) // corner or edge { if ( board.Num8Neighbors(p, att) > 0 ) return false; else { number = board.Num8EmptyNeighbors(p); return true; } } else // in center { if ( board.Num8Neighbors(p, att) >= 2 ) return false; else if ( board.NumNeighbors(p, att) > 0 ) return false; else // only 0 or 1 attacker point and not in NB4 { number = board.Num8EmptyNeighbors(p); return true; } } }
bool GoEyeUtil::IsSinglePointEye(const GoBoard& bd, SgPoint p, SgBlackWhite color) { SG_ASSERT(bd.IsEmpty(p)); const SgBlackWhite opp = SgOppBW(color); if (bd.HasEmptyNeighbors(p) || bd.HasNeighbors(p, opp)) return false; if (bd.Line(p) == 1) return ! (bd.HasDiagonals(p, SG_EMPTY) || bd.HasDiagonals(p, opp)); return (bd.NumDiagonals(p, SG_EMPTY) + bd.NumDiagonals(p, opp)) <= 1; }
bool GoEyeUtil::IsPossibleEye(const GoBoard& board, SgBlackWhite color, SgPoint p) { bool isPossibleEye = false; SG_ASSERT(board.GetColor(p) != color); const SgBlackWhite opp = SgOppBW(color); if (board.Line(p) == 1) // corner or edge { const int nuOwn = (board.Pos(p) == 1) ? 2 : 4; if ( board.Num8Neighbors(p, color) == nuOwn && board.Num8EmptyNeighbors(p) == 1 ) { isPossibleEye = true; } } else // in center { // have all neighbors, and 2 diagonals, and can get a third if ( board.NumNeighbors(p, color) == 4 && board.NumDiagonals(p, color) == 2 && board.NumEmptyDiagonals(p) > 0 ) { isPossibleEye = true; } // have 3 of 4 neighbors, can get the 4th, and have enough diagonals else if ( board.NumNeighbors(p, color) == 3 && board.NumNeighbors(p, opp) == 0 && board.NumDiagonals(p, color) >= 3 ) { isPossibleEye = true; } } return isPossibleEye; }
//---------------------------------------------------------------------------- inline bool IsEmpty2x3Box(const GoBoard& bd, SgPoint p) { SG_ASSERT (bd.Line(p) == 1); SG_ASSERT (bd.Pos(p) > 1); return bd.IsEmpty(p) && bd.Num8EmptyNeighbors(p) == 5; }
bool GoEyeUtil::NumberOfMoveToEye2(const GoBoard& board, SgBlackWhite color, SgPoint p, int& nummoves) { nummoves = 0; bool capturing = false; SgVector<SgPoint> usedpoints; usedpoints.PushBack(p); SgPointSet counted; // Can never turn own stone into an eye if (board.IsColor(p, color)) return false; // If opponent stone then it must be captured to make eye if (board.IsColor(p, SgOppBW(color))) { capturing = true; // If it is obviously safe then it can never be an eye if (SinglePointSafe2(board, p)) // Quick, naive safety test return false; for (GoBoard::LibertyIterator libit(board, p); libit; ++libit) counted.Include(*libit); } // Count immediate adjacencies for (SgNb4Iterator nb(p); nb; ++nb) { SgPoint adj = *nb; // Empty points must be filled if (board.IsColor(adj, SG_EMPTY)) { counted.Include(adj); } // If adjacent opponent then can never be an eye else if (board.IsColor(adj, SgOppBW(color))) { if (capturing) counted.Include(adj); // must capture and then fill else return false; } } // Up to one diagonal can be ignored: estimate most costly SgPoint toignore = SG_NULLPOINT; int maxcost = 0; int infcost = 1000; if (board.Line(p) > 1) { for (SgNb4DiagIterator nbd(p); nbd; ++nbd) { SgPoint diag = *nbd; int cost = 0; if ( board.IsColor(diag, SG_EMPTY) && ! IsSinglePointEye2(board, diag, color, usedpoints)) { cost = 1; } else if (board.IsColor(diag, SgOppBW(color))) { // quick safety test if (SinglePointSafe2(board, diag)) cost = infcost; else cost = board.NumLiberties(diag); } if (cost > maxcost) { maxcost = cost; toignore = diag; } } } // Now mark points that must be played to secure diagonals for (SgNb4DiagIterator nbd(p); nbd; ++nbd) { SgPoint diag = *nbd; if (diag == toignore) continue; // Empty points must be filled (unless they are eyes) if ( board.IsColor(diag, SG_EMPTY) && ! IsSinglePointEye2(board, diag, color, usedpoints)) { counted.Include(diag); } // Opponent stones on diagonals must be captured and filled else if (board.IsColor(diag, SgOppBW(color))) { if (SinglePointSafe2(board, diag)) return false; else { counted.Include(diag); for (GoBoard::LibertyIterator libit(board, diag); libit; ++libit) counted.Include(*libit); } } } nummoves = counted.Size(); return true; }