如何计算给定索引周围 bool[] 中的真实值?

How to count true values in a bool[,] around a given index?

我找到了我几年前写的一个简单的扫雷程序,如果您可以优化以下代码,我很感兴趣,因为它看起来一点也不好。

以下方法用于检查索引是否超出范围和returns所请求索引的值:

private static bool IsMineOnCoords(bool[,] field, int posI, int posJ)
{
    if (posI < 0 || posI > field.GetLength(0) - 1 || posJ < 0 || posJ > field.GetLength(1) - 1) return false;
    return field[posI, posJ];
}

我在 8 个 if 语句中为给定索引周围的每个位置调用此方法:

int count = 0;

if (IsMineOnCoords(field, posI + 1, posJ)) count++;
if (IsMineOnCoords(field, posI - 1, posJ)) count++;
if (IsMineOnCoords(field, posI + 1, posJ + 1)) count++;
if (IsMineOnCoords(field, posI + 1, posJ - 1)) count++;
if (IsMineOnCoords(field, posI - 1, posJ + 1)) count++;
if (IsMineOnCoords(field, posI - 1, posJ - 1)) count++;
if (IsMineOnCoords(field, posI, posJ + 1)) count++;
if (IsMineOnCoords(field, posI, posJ - 1)) count++;

有没有更好的方法可以做到这一点?

使用这样的东西:

for (int i = posI - 1; i <= posI + 1; i++)
{
    for (int j = posJ - 1; j <= posJ + 1; j++)
    {
        if (!(i == posI && j == posJ) && IsMineOnCoords(field, i, j))
        {
            count++;
        }
    }
}

我认为它很好,据我所知它应该执行得很快,尤其是因为短路。

条件或运算符 (||) 对其布尔操作数执行逻辑或。如果第一个操作数的计算结果为真,则不会计算第二个操作数。如果第一个操作数的计算结果为假,则第二个运算符会确定整个 OR 表达式的计算结果是真还是假。

https://msdn.microsoft.com/en-us/library/6373h346.aspx

像这样的东西应该适合你。基本上,您只需计算出周围单元格的 ij 坐标的最小值和最大值,然后循环遍历这些单元格,将 true 值相加(但跳过传入的单元格):

private static int GetSurroundingBombCount(bool[,] field, int posI, int posJ)
{
    var surroundingBombCount = 0;

    // Get the minimum and maximum i and j coordinates of the surrounding cells
    var iMin = posI - 1 < 0 ? 0 : posI - 1;
    var iMax = posI + 1 > field.GetUpperBound(0) ? posI : posI + 1;
    var jMin = posJ - 1 < 0 ? 0 : posJ - 1;
    var jMax = posJ + 1 > field.GetUpperBound(1) ? posJ : posJ + 1;

    // Loop through these cells and increment our counter for each true value
    // unless we hit the initial cell, in which case we just continue
    for (int i = iMin; i <= iMax; i++)
    {
        for (int j = jMin; j <= jMax; j++)
        {
            if (i == posI && j == posJ) continue;
            if (field[i, j]) surroundingBombCount++;
        }
    }

    return surroundingBombCount;
}

那么用法将类似于:

int surroundingBombCount = GetSurroundingBombCount(field, posI, posJ);

我用这段代码来测试它,它会生成一个 3x3 的网格(你可以随意调整它),在单元格上放置随机炸弹,然后显示两个网格,以便你可以直观地检查它们:一个网格与炸弹位置,以及另一个带有计数的网格:

private static void Main()
{
    bool[,] field = new bool[3, 3];

    Random rnd = new Random();

    // The lower this number, the more bombs will be placed.
    // Must be greater than one, should be greater than 2. 
    // If set to '2', all cells will contain a bomb, which isn't fun.
    int bombScarcity = 10; 

    // Assign random bombs
    for (int i = 0; i < field.GetLength(0); i++)
    {
        for (int j = 0; j < field.GetLength(1); j++)
        {
            field[i, j] = rnd.Next(1, bombScarcity) % (bombScarcity - 1) == 0;
        }
    }

    // Show bomb locations
    Console.WriteLine("\nBomb Locations:\n");

    for (int i = 0; i < field.GetLength(0); i++)
    {
        for (int j = 0; j < field.GetLength(1); j++)
        {
            Console.Write(field[i, j] ? " T" : " F");
            if ((j + 1) % field.GetLength(1) == 0) Console.WriteLine();
        }
    }

    // Show bomb counts 
    Console.WriteLine("\nBomb Counts:\n");

    for (int i = 0; i < field.GetLength(0); i++)
    {
        for (int j = 0; j < field.GetLength(1); j++)
        {
            Console.Write($" {GetSurroundingBombCount(field, i, j)}");
            if ((j + 1) % field.GetLength(1) == 0) Console.WriteLine();
        }
    }

    Console.Write("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

输出

为了好玩 10 x 10: