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

时间:2017-04-18 16:33:20

标签: c# arrays logic minesweeper

我发现了几年前我写的一个简单的MineSweeper程序,如果你可以优化下面的代码就会产生兴趣,因为它看起来并不好看。

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

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

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

3 个答案:

答案 0 :(得分:2)

这样的事情对你有用。基本上,您只需计算周围单元格的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();
}

<强>输出

enter image description here

为了好玩10 x 10:

enter image description here

答案 1 :(得分:1)

我认为它很好,据我所知它应该快速执行,特别是因为短路。

条件OR运算符(||)执行其bool操作数的逻辑或。如果第一个操作数的计算结果为true,则不计算第二个操作数。如果第一个操作数的计算结果为false,则第二个操作符将确定整个OR表达式的计算结果为true或false。

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

答案 2 :(得分:0)

使用类似的东西:

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