void GoInfluence::FindInfluence(const GoBoard& board, int nuExpand, int nuShrink, SgBWSet* influence) { SgBWSet result = SgBWSet(board.All(SG_BLACK), board.All(SG_WHITE)); SgBWSet next; const int size = board.Size(); for (int i = 1; i <= nuExpand; ++i) { for (SgBlackWhite c = SG_BLACK; c <= SG_WHITE; ++c) { SgBlackWhite opp = SgOppBW(c); next[c] = result[c].Border(size) - result[opp]; } result[SG_BLACK] |= (next[SG_BLACK] - next[SG_WHITE]); result[SG_WHITE] |= (next[SG_WHITE] - next[SG_BLACK]); } for (int i = 1; i <= nuShrink; ++i) { result[SG_BLACK] = result[SG_BLACK].Kernel(size); result[SG_WHITE] = result[SG_WHITE].Kernel(size); } *influence = result; }
void Mesh::DrawPieces(GoBoard &board) { glTranslatef(PIECE_OFFSET, BOARD_HEIGHT, PIECE_OFFSET); glScalef(PIECE_X_SCALE, PIECE_Y_SCALE, PIECE_Z_SCALE); //glTranslatef(0.5f, 0.5f, 0.5f); for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { char space = board.getPiece(x, y); if (space != 0) { float color = (space + 1) / 2 + 0.2; glColor3f(color, color, color); DrawMesh(piece, piece_tri_verts_VBO); //glutSolidSphere(0.5, 10, 10); } glTranslatef(0, 0, BOARD_GRID_SPACING); } glTranslatef(0, 0, -BOARD_MAX/PIECE_Z_SCALE); glTranslatef(BOARD_GRID_SPACING, 0, 0); } glTranslatef(-BOARD_MAX/PIECE_X_SCALE, 0, 0); auto sP = board.getSpeculativePiece(); //if (board.legalMove(sP.second, sP.first.first, sP.first.second)) { glTranslatef(BOARD_GRID_SPACING*sP.first.x, 0, BOARD_GRID_SPACING*sP.first.y); float color = (sP.second + 1) / 2 + 0.2; glColor3f(color, 0, color); //glutSolidSphere(0.5, 10, 10); DrawMesh(piece, piece_tri_verts_VBO); //} //endTranslate(); }
void GoBook::Add(const GoBoard& bd, SgPoint move) { if (move != SG_PASS && bd.Occupied(move)) throw SgException("point is not empty"); if (! bd.IsLegal(move)) throw SgException("move is not legal"); const GoBook::MapEntry* mapEntry = LookupEntry(bd); if (mapEntry == 0) { vector<SgPoint> moves; moves.push_back(move); GoBoard tempBoard; InsertEntry(GetSequence(bd), moves, bd.Size(), tempBoard, 0); } else { size_t id = mapEntry->m_id; SG_ASSERT(id < m_entries.size()); Entry& entry = m_entries[id]; int invRotation = SgPointUtil::InvRotation(mapEntry->m_rotation); SgPoint rotMove = SgPointUtil::Rotate(invRotation, move, bd.Size()); if (! Contains(entry.m_moves, rotMove)) entry.m_moves.push_back(rotMove); } }
bool GoRegion::ProtectedCuts(const GoBoard& board) const { if (! GetFlag(GO_REGION_CORRIDOR)) return false; if (m_blocks.IsLength(2)) /* */ return Safe2Cuts(board); /* */ // easy case of only 2 blocks bool prot = true; SgPointSet allCuts; const int size = board.Size(); GoBlock* block1, *block2; for (SgVectorPairIteratorOf<GoBlock> it(m_blocks); it.NextPair(block1, block2);) { SgPointSet lib1(block1->Stones().Border(size)); SgPointSet lib2(block2->Stones().Border(size)); SgPointSet cuts(lib1 & lib2 & Points()); if (! cuts.SubsetOf(board.AllEmpty())) // cut occupied by opponent. Bad for us. return false; else allCuts |= cuts; } // no eye space left ? hard to distinguish false eyes from ok // AR why must this be checked??? Should not matter for flat regions. // Try to take it out. //if (Points().SubsetOf(allCuts | allCuts.Border())) // prot = false; return prot; }
bool GoEyeUtil::IsVitalPt(const SgPointSet& points, SgPoint p, SgBlackWhite opp, const GoBoard& bd) { // in corridors a vital point has 2 nbs, in big ones it may have 3 or 4. // but: 2 in following // example: unsettled nakade, non-flat points are all occupied by opp. // .a a is vital Point. // o. // . int numNb = bd.NumEmptyNeighbors(p) + bd.NumNeighbors(p, opp); if (numNb >= 2) { if (numNb >= 4) /* */ return true; /* */ int nu = IsTreeShape(points) ? 2 : 3; if (numNb >= nu) { if (numNb == 2 && bd.IsEmpty(p)) return IsSplitPt(p, points); else return true; } } return false; }
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; }
SgPointSet SpUtil::GetRelevantMoves(GoBoard& bd, SgBlackWhite toPlay, bool useFilter) { SgPointSet legal; for (SgSetIterator it(bd.AllEmpty()); it; ++it) if (bd.IsLegal(*it)) legal.Include(*it); if (! useFilter) return legal; GoSafetySolver safetySolver(bd); SgBWSet safe; safetySolver.FindSafePoints(&safe); SgBlackWhite opp = SgOppBW(toPlay); SgPointSet moves; const GoRules& rules = bd.Rules(); const bool captureDead = rules.CaptureDead(); //const bool japaneseScoring = rules.JapaneseScoring(); for (SgSetIterator it(legal); it; ++it) { SgPoint p = *it; const bool isSafe = safe[toPlay].Contains(p); const bool isSafeOpp = safe[opp].Contains(p); const bool hasOppNeighbors = bd.HasNeighbors(p, opp); if ( (! isSafe && ! isSafeOpp) || (isSafe && captureDead && hasOppNeighbors) // || (isSafeOpp && ! japaneseScoring) ) moves.Include(p); } return moves; }
GoPlayer::GoPlayer(const GoBoard& bd) : GoBoardSynchronizer(bd), m_currentNode(0), m_bd(bd.Size(), GoSetup(), bd.Rules()), m_variant(0) { SetSubscriber(m_bd); ClearSearchTraces(); }
GoBoard* GoBoard::copyBoard() const { GoBoard* nBoard = new GoBoard(Size()); for(int i = 0; i<movePointer; ++i) { nBoard->Play(moves[i]->Point); } return nBoard; }
int LibertyAveragex10(const GoBoard& board, SgBlackWhite color) { int nuLibs = 0, nuBlocks = 0; const int size = board.Size(); for (SgConnCompIterator it(board.All(color), board.Size()); it; ++it) { ++nuBlocks; nuLibs += ((*it).Border(size) & board.AllEmpty()).Size(); } return (nuBlocks == 0) ? 0 : 10 * nuLibs / nuBlocks; }
void GoBook::Entry::ApplyTo(GoBoard& bd) const { if (bd.Size() != m_size) bd.Init(m_size); GoBoardUtil::UndoAll(bd); for (vector<SgPoint>::const_iterator it = m_sequence.begin(); it != m_sequence.end(); ++it) { SG_ASSERT(bd.IsLegal(*it)); bd.Play(*it); } }
GoSetup GoSetupUtil::CurrentPosSetup(const GoBoard& bd) { GoSetup setup; setup.m_player = bd.ToPlay(); for (GoBoard::Iterator it2(bd); it2; ++it2) { SgPoint p = *it2; if (bd.Occupied(p)) setup.m_stones[bd.GetColor(p)].Include(p); } return setup; }
bool GoRegion::Safe2Cuts(const GoBoard& board) const { SG_ASSERT(m_blocks.IsLength(2)); const int size = board.Size(); GoBlock* block1 = m_blocks.Front(); GoBlock* block2 = m_blocks.Back(); SgPointSet cuts(Points()); cuts -= board.AllEmpty(); if (cuts.IsEmpty()) /* */ return true; /* */ cuts &= block1->Stones().Border(size); cuts &= block2->Stones().Border(size); return cuts.IsEmpty(); }
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; }
int GoEyeUtil::CountSinglePointEyes2(const GoBoard& board, SgPoint p) { if (! board.Occupied(p)) return 0; SgBlackWhite color = board.GetColor(p); int numeyes = 0; for (GoBoard::LibertyIterator lib(board, p); lib; ++lib) { if (IsSinglePointEye2(board, *lib, color)) numeyes++; } return numeyes; }
vector<SgPoint> GoBook::LookupAllMoves(const GoBoard& bd) const { vector<SgPoint> result; const GoBook::MapEntry* mapEntry = LookupEntry(bd); if (mapEntry == 0) return result; size_t id = mapEntry->m_id; SG_ASSERT(id < m_entries.size()); const vector<SgPoint>& moves = m_entries[id].m_moves; const int rotation = mapEntry->m_rotation; const int size = mapEntry->m_size; for (vector<SgPoint>::const_iterator it = moves.begin(); it != moves.end(); ++it) { SgPoint p = SgPointUtil::Rotate(rotation, *it, size); if (! bd.IsLegal(p)) { // Should not happen with 64-bit hashes, but not impossible SgWarning() << "illegal book move (hash code collision?)\n"; result.clear(); break; } result.push_back(p); } return result; }
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; } } }
SgPoint GoGtpCommandUtil::StoneArg(const GtpCommand& cmd, std::size_t number, const GoBoard& board) { SgPoint point = PointArg(cmd, number, board); if (board.GetColor(point) == SG_EMPTY) throw GtpFailure() << "point " << SgWritePoint(point) << " must be occupied"; return point; }
GoLadderStatus GoLadderUtil::LadderStatus(const GoBoard& bd, SgPoint prey, bool twoLibIsEscape, SgPoint* toCapture, SgPoint* toEscape) { SG_ASSERT(bd.IsValidPoint(prey)); SG_ASSERT(bd.Occupied(prey)); #ifndef NDEBUG SgHashCode oldHash = bd.GetHashCode(); #endif // Unsettled only if can capture when hunter plays first, and can escape // if prey plays first. GoLadder ladder; SgBlackWhite preyColor = bd.GetStone(prey); SgVector<SgPoint> captureSequence; GoLadderStatus status = GO_LADDER_ESCAPED; if (ladder.Ladder(bd, prey, SgOppBW(preyColor), &captureSequence, twoLibIsEscape) < 0) { SgVector<SgPoint> escapeSequence; if (ladder.Ladder(bd, prey, preyColor, &escapeSequence, twoLibIsEscape) < 0) status = GO_LADDER_CAPTURED; else { status = GO_LADDER_UNSETTLED; // Unsettled = ladder depends on who plays first, so there must // be a move that can be played. SG_ASSERT(captureSequence.NonEmpty()); // escapeSequence can be empty in 2 libs, prey to play case SG_ASSERT(twoLibIsEscape || escapeSequence.NonEmpty()); if (toCapture) *toCapture = captureSequence.Front(); if (toEscape) *toEscape = escapeSequence.IsEmpty() ? SG_PASS : escapeSequence.Front(); } } #ifndef NDEBUG // Make sure Ladder didn't change the board position. SG_ASSERT(oldHash == bd.GetHashCode()); #endif return status; }
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 GoLadderUtil::IsProtectedLiberty(const GoBoard& bd1, SgPoint liberty, SgBlackWhite col, bool& byLadder, bool& isKoCut, bool tryLadder) { byLadder = false; isKoCut = false; GoModBoard mbd(bd1); GoBoard& bd = mbd.Board(); const SgBlackWhite toPlay = bd1.ToPlay(); bd.SetToPlay(SgOppBW(col)); bool isProtected; if (! PlayIfLegal(bd, liberty)) isProtected = bd.LastMoveInfo(GO_MOVEFLAG_SUICIDE); // opponent cannot play there else { if (bd.LastMoveInfo(GO_MOVEFLAG_SUICIDE)) isProtected = true; else { if (bd.InAtari(liberty)) { if (bd.NumStones(liberty) > 1) isProtected = true; else { SgPoint p = bd.TheLiberty(liberty); if (PlayIfLegal(bd, p)) { isProtected = (bd.NumStones(p) != 1) || (bd.NumLiberties(p) != 1); // yes, can re-capture there bd.Undo(); } else isProtected = false; if (! isProtected) isKoCut = true; } } else if (tryLadder) { isProtected = Ladder(bd, liberty, bd.ToPlay(), true); if (isProtected) byLadder = true; } else // don't try ladder isProtected = false; } bd.Undo(); } bd.SetToPlay(toPlay); return isProtected; }
SgPoint GoUctUtil::GenForcedOpeningMove(const GoBoard& bd) { int sz = bd.Size(); if (sz < 13 || bd.TotalNumStones(SG_BLACK) > 5 || bd.TotalNumStones(SG_WHITE) > 5) return SG_NULLMOVE; SgSList<SgPoint,4> moves; if (IsRectEmpty(bd, 1, 5, 1, 5)) moves.PushBack(Pt(4, 4)); if (IsRectEmpty(bd, 1, 5, sz - 4, sz)) moves.PushBack(Pt(4, sz - 3)); if (IsRectEmpty(bd, sz - 4, sz, 1, 5)) moves.PushBack(Pt(sz - 3, 4)); if (IsRectEmpty(bd, sz - 4, sz, sz - 4, sz)) moves.PushBack(Pt(sz - 3, sz - 3)); if (moves.IsEmpty()) return SG_NULLMOVE; return moves[SgRandom::Global().Int(moves.Length())]; }
void GoGtpCommandUtil::ParseMultiStoneArgument(GtpCommand& cmd, const GoBoard& board, SgBlackWhite& toPlay, SgBlackWhite& defender, SgVector<SgPoint>& crucial) { toPlay = GoGtpCommandUtil::BlackWhiteArg(cmd, 0); SgDebug() << "Set " << SgBW(toPlay) << " to play\n"; SgPoint point = GoGtpCommandUtil::StoneArg(cmd, 1, board); defender = board.GetColor(point); SG_ASSERT(defender == SG_BLACK || defender == SG_WHITE); crucial.PushBack(point); for (size_t i = 2; i < cmd.NuArg(); ++i) { SgPoint p = GoGtpCommandUtil::StoneArg(cmd, i, board); if (board.GetColor(p) != defender) throw GtpFailure("Crucial stones must be same color"); else crucial.PushBack(p); } }
void GoUctFeatures:: FindMoveFeaturesUI(const GoBoard& bd, GoUctPlayoutPolicy<GoBoard>& policy, SgPoint move, FeMoveFeatures& features) { SG_ASSERT(move != SG_PASS); if (! bd.IsLegal(move)) return; FeFullBoardFeatures f(bd); FindAllFeatures(bd, policy, f); features = f.Features()[move]; }
bool GoLadderUtil::Ladder(const GoBoard& bd, SgPoint prey, SgBlackWhite toPlay, bool twoLibIsEscape, SgVector<SgPoint>* sequence) { SG_ASSERT(bd.IsValidPoint(prey)); SG_ASSERT(bd.Occupied(prey)); // @todo for an unsettled block with 2 liberties, it // immediately says it can escape, but does not return a move. // Sequence is empty. Have to special case this and look for // moves that escape from ladder myself. #ifndef NDEBUG SgHashCode oldHash = bd.GetHashCode(); #endif GoLadder ladder; int result = ladder.Ladder(bd, prey, toPlay, sequence, twoLibIsEscape); #ifndef NDEBUG // Make sure Ladder didn't change the board position. SG_ASSERT(oldHash == bd.GetHashCode()); #endif SG_ASSERT(result != 0); return (result < 0); }
void GoBook::Delete(const GoBoard& bd, SgPoint move) { const GoBook::MapEntry* mapEntry = LookupEntry(bd); if (mapEntry == 0) return; size_t id = mapEntry->m_id; SG_ASSERT(id < m_entries.size()); Entry& entry = m_entries[id]; int invRotation = SgPointUtil::InvRotation(mapEntry->m_rotation); SgPoint rotMove = SgPointUtil::Rotate(invRotation, move, bd.Size()); if (! Erase(entry.m_moves, rotMove)) throw SgException("GoBook::Delete: move not found"); }
GoRegionBoard::GoRegionBoard(const GoBoard& board) : m_board(board), m_region(SgPointArray<GoRegion*>(0)), m_block(0), m_invalid(true), m_computedHealthy(false), m_boardSize(board.Size()) { m_code.Invalidate(); m_chainsCode.Invalidate(); GenBlocksRegions(); ++s_alloc; }
bool GoEyeUtil::CheckInterior(const GoBoard& bd, const SgPointSet& area, SgBlackWhite opp, bool checkBlocks) { bool hasSingleNbPoint = false; int nuPoints = 0; for (SgSetIterator it(area); it; ++it) { const SgPoint p(*it); if (bd.IsEmpty(p)) { int nuNbs = 0; if (area.Contains(p + SG_NS)) ++nuNbs; if (area.Contains(p - SG_NS)) ++nuNbs; if (area.Contains(p + SG_WE)) ++nuNbs; if (area.Contains(p - SG_WE)) ++nuNbs; if (nuNbs == 1) hasSingleNbPoint = true; else if (nuNbs > 2) return false; } else if (p == bd.Anchor(p)) { if (bd.GetColor(p) != opp) // if own stones on inside: not a tree shape. return false; int nuLibs = bd.NumLiberties(p); if (nuLibs == 1) hasSingleNbPoint = true; else if (checkBlocks && nuLibs > 2) return false; } ++nuPoints; } return nuPoints == 1 || hasSingleNbPoint; }
void GoLadderUtil::FindLadderEscapeMoves(const GoBoard& bd, SgPoint prey, SgVector<SgPoint>& escapeMoves) { SG_ASSERT(bd.NumLiberties(prey) == 1); SG_ASSERT(escapeMoves.IsEmpty()); SgPoint p = bd.TheLiberty(prey); SgVector<SgPoint> candidates; candidates.PushBack(p); if (IsLadderEscapeMove(bd, prey, p)) escapeMoves.PushBack(p); for (GoAdjBlockIterator<GoBoard> it(bd, prey, 1); it; ++it) { // check if prey can escape by capturing *it on p. SgPoint p = bd.TheLiberty(*it); if (! candidates.Contains(p)) { candidates.PushBack(p); if (IsLadderEscapeMove(bd, prey, p)) escapeMoves.PushBack(p); } } }
SgPoint GoLadderUtil::TryLadder(const GoBoard& bd, SgPoint prey, SgBlackWhite firstPlayer) { SgVector<SgPoint> sequence; bool isCaptured = Ladder(bd, prey, firstPlayer, true, &sequence); // if move is same color as prey, we want to escape // else we want to capture. SgPoint p; if (isCaptured != (firstPlayer == bd.GetStone(prey))) p = sequence.IsEmpty() ? SG_PASS : sequence.Front(); else p = SG_NULLMOVE; return p; }