size_t Board::removeCapturedStones (StoneColor colorToCapture) { LOG_FUNCTION(cout, "Board::removeCapturedStones"); size_t captureCount = 0; // A set of points that we've already examined. This helps prevents some // bad recursion and keeps a chain from being "found" once for each stone // in the chain. // ConstPointSet alreadyVisited; for (size_t row = 0; row < m_points.size(); ++row) { for (size_t column = 0; column < m_points[row].size(); ++column) { const Point & thePoint = m_points.at(row).at(column); // If the point we are considering has already been visited, // then Chain's ctor will throw a PointVisitedAlreadyException // object. We can safely swallow that exception and move on // to the next point. // try { Chain currentChain {thePoint, *this, &alreadyVisited}; gLogger.log(LogLevel::kMedium, cout, "Discovered chain"); // " : ", chain); // If the chain we are looking at is the color we should consider capturing and // the chain has no liberties, then capture it // if (currentChain.color() == colorToCapture && currentChain.libertyCount() == 0) { captureCount += currentChain.size(); // For each point in the chain, remove the stone from the board // at those coordniates // currentChain.forEachPoint([this](const Point & point) { LOG_BUSY_FUNCTION(cout, "Chain::removeCapturedStones::lambda_doStoneRemoval"); m_points[point.coordinates.row][point.coordinates.column].removeStone(); }); } } catch (const Chain::PointVisitedAlreadyException & ex) { gLogger.log(LogLevel::kFirehose, cout, "Skipping ", thePoint); } } } // If we ended up only capturing one stone, the 'Ko' rule might affect // the next move, so remember that fact! // m_koState.first = (captureCount == 1); return captureCount; }