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;
}