【问题标题】:Check if some elements are equal in 2D array c# sharp检查二维数组c#中的某些元素是否相等
【发布时间】:2026-01-31 15:15:01
【问题描述】:

给定数组:

字符串[,] arr = 新字符串[n,n]。 如何检查每行、每列和两条对角线的元素是否相等?

这是一种井字游戏:编写一个控制台应用程序,接收 X 和 0 作为坐标的 N 个移动日期作为输入。 (0, 0) 是左上角, (2, 2) 是右下角。第一行是步数 N,从第二行开始,每行一个步数。第一手是玩家的 X,其次是玩家的手 0,然后是 X,依此类推。应用程序将分析收到的手,并显示获胜者:X,0 或如果没有获胜者则平局. 这是我尝试过的,但没有结果:

static void Main()
    {
        int numberOfMoves = Convert.ToInt32(Console.ReadLine());
        const int size = 3;
        string[,] boardGame = new string[size, size];
        for (int i = 0; i < numberOfMoves; i++)
        {
            string strCoordinates = Console.ReadLine();
            string[] lineCoordinates = strCoordinates.Split(' ');
            int coordinateX = Convert.ToInt32(lineCoordinates[0]);
            int coordinateY = Convert.ToInt32(lineCoordinates[1]);
            const int value = 2;
            boardGame[coordinateX, coordinateY] = i % value == 0 ? "X" : "0";
        }

        // CheckElements(boardGame); in construction
        Console.Read();
    }

    static void CheckRows(int x, int y)
    {
        string[,] boardGame = new string[3, 3];
        int cols = boardGame.GetLength(1);
        const int value = 2;
        for (int i = 0; i < cols; i++)
        {
            if ((boardGame[0, 0] == boardGame[0, 1] && boardGame[0, 1] == boardGame[0, value]) || (boardGame[1, 0] == boardGame[1, 1] && boardGame[1, 1] == boardGame[1, value]))
            {
                Console.WriteLine(boardGame[0, 0]);
            }

            if ((boardGame[1, 0] == boardGame[1, 1] && boardGame[1, 1] == boardGame[1, value]) || (boardGame[value, 0] == boardGame[value, 1] && boardGame[value, 1] == boardGame[value, value]))
            {
                Console.Write(boardGame[0, 0]);
            }
        }

        Console.WriteLine(boardGame[x, y]);
    }

    static void CheckColumns(int x, int y)
    {
        string[,] boardGame = new string[3, 3];
        int rows = boardGame.GetLength(0);
        const int value = 2;
        for (int i = 0; i < rows; i++)
        {
            if ((boardGame[0, 0] == boardGame[1, 0] && boardGame[1, 0] == boardGame[value, 0]) || (boardGame[0, 1] == boardGame[1, 1] && boardGame[1, 1] == boardGame[value, 1]))
            {
                Console.WriteLine(boardGame[0, 0]);
            }

            if ((boardGame[0, 1] == boardGame[1, 1] && boardGame[1, 1] == boardGame[value, 1]) || (boardGame[0, value] == boardGame[1, value] && boardGame[1, value] == boardGame[value, value]))
            {
                Console.WriteLine(boardGame[0, 1]);
            }
        }

        Console.WriteLine(boardGame[x, y]);
    }

    static void CheckDiagonals(int x, int y)
    {
        string[,] boardGame = new string[3, 3];
        int m = boardGame.Length;
        const int value = 2;
        for (int i = 0; i < m; i++)
        {
            m--;
            for (int j = 0; j < m; j++)
            {
                if (boardGame[0, 0] == boardGame[1, 1] && boardGame[1, 1] == boardGame[value, value])
                {
                    Console.WriteLine(boardGame[0, 0]);
                }
            }
        }

        Console.WriteLine(boardGame[x, y]);
    }

【问题讨论】:

  • 您的示例中没有包含CheckElements(string[,] boardGame) 函数。
  • @Creyke,这是真的,我没有写函数 CheckElements 因为我被卡住了。我首先在寻找更好的解决方案来检查行、列和对角线中的相等元素。我更新了我的代码,包括您提到的行的评论。
  • 而不是 X 和 Y 使用 1 和 -1 然后伪代码 int[max] rows, int cols[max] , int diag[2] for(int x &lt;max) { for(int y &lt; max) { cols[x] += board[x,y]; rows[y] += board[x,y]; } diag[0] += board[x,x]; diag[1] += board[max-1-x, x]; } 现在检查任何 cols 行或 diag 是否为 max 或 -max 然后有人获胜

标签: c# arrays string for-loop methods


【解决方案1】:

这显然是家庭作业,所以我不会为你做,但我会仔细检查你的代码,并在我认为有问题的地方以及需要如何更改的地方发表评论:

    //i think this method should take the game board as a parameter, not x and y
    //because your game oard is populated in the main as a variable that is not accessible anywhere
    //outside the main
    static void CheckRows(int x, int y)
    {
        //this should be an input parameter, rather than being declared here
        string[,] boardGame = new string[3, 3];
   
        //ok this gets the number of columns..
        int cols = boardGame.GetLength(1);

        //..but where is the same thing for rows? I know it's a square board but
        //it's easy to code up the rows too, for ultimate flexibility

        //what's this for? looks like you're limiting yourself to 3x3 boards?
        const int value = 2;

        //i'd have probably called this variable col, or c
        //and I'd probably start it at 1...
        for (int i = 0; i < cols; i++)
        {
            //you declared i but you don't use it? You have a loop that increments
            //a number through 0, 1, 2, 3 ... just like you've hard coded here
            //so think about what you hardcoded and how you could do that in a loop
            // - see later for a hint

            if ((boardGame[0, 0] == boardGame[0, 1] && boardGame[0, 1] == boardGame[0, value]) || (boardGame[1, 0] == boardGame[1, 1] && boardGame[1, 1] == boardGame[1, value]))
            {
                Console.WriteLine(boardGame[0, 0]);
            }

            //ok, so now you've moved onto hard coding row number 1, and hard coding
            //a bunch of columns.. think about how you could use the variables you have
            if ((boardGame[1, 0] == boardGame[1, 1] && boardGame[1, 1] == boardGame[1, value]) || (boardGame[value, 0] == boardGame[value, 1] && boardGame[value, 1] == boardGame[value, value]))
            {
                Console.Write(boardGame[0, 0]);
            }
        }

        //what is this for?
        Console.WriteLine(boardGame[x, y]);
    }

好的,所以我在里面谈到了提示。

当您检查单个数组中的每个元素是否相同时,最简单的做法是将每个元素与第一个元素进行比较:

int[] nums = new[]{2, 2, 2, 2, 2};

//get the first number
int first = nums[0]; //it's always at 0

//use a loop to check if all are the same. use a boolean to remember it
bool allSame = true; //be optimistic..

for(int i = 1; i < nums.Length; i++){ //start from second, not first
  if(nums[i] != first){
    allSame = false; 
    break;
  }
}

你能看到我们是如何制作这个变量的吗?它可以检查数组中的一千个条目以查看它们是否相同。一旦任何元素与第一个不同,我们将 allSame 设置为 false 并停止循环(没有意义)

然后我们可以检查 allSame 的值是否相同


如果你只检查一个维度,这里一维数组和二维数组没有区别:

int[,] nums = new int[,]{{2,2,2},{3,4,5},{4,3,2}};

int first = nums[0,0];
for(int c = 1; c < nums.GetLength(1); c++){

  if(nums[0, c] == first) ...

我们所做的只是将维度添加为硬编码...第 0 行。c 列是一个变量。

但是如果我们想让它成为一个变量以便检查所有维度呢?

使用两个循环

for(int r = 0; r < nums.GetLength(0); r++){ //rows start from 0!

  int first = nums[r, 0]; //row is variable, column is first
  for(int c = 1; c < nums.GetLength(1); c++){ //cols start from 1!

    if(nums[r, c] == first) //r will be 0, while c goes 1..3, then r will be 1 while c is 1..3 etc

我们为添加行检查所做的只是在检查单个列的位周围添加另一个环绕,它为r 提供了一个递增值


在计算列时,逻辑是一样的,只是我们对每个 c 重复增加 r(c 为 0,r 从 1..3 开始,c 为 1,r 为 1..3, c 是 2,r 是 1..3)


当检查对角线时,它更简单;我们只需要一个从 1 开始的变量,因为这些是我们想要做的检查:

x[0,0] compared to x[1,1]
x[0,0] compared to x[2,2]
x[0,0] compared to x[3,3]
x[0,0] compared to x[4,4]

..

这意味着您可以只使用一个变量,因为数字重复:

for(int i = 0; i < ... )

  if(x{0,0] == x[i,i])

祝你好运!

【讨论】:

  • 谢谢@Caius Jard 的回答。我正在尝试重写代码。再次感谢!
  • //这是干什么用的?看起来您将自己限制在 3x3 板?常量 int 值 = 2;这个值代表索引 2,我存储这个变量是因为我的 Visual Studio 强制我出错,否则我无法运行程序,这就是原因。
【解决方案2】:

给定一个方阵,有一种方法可以在一个循环中完成所有检查。 但在进行优化之前,让我们清理并简化。

给定下面的方阵,可能很难全部换相来找到赢家。

var input = new [,]{
    {"x","x","x"},
    {"x","x","o"},
    {"x","o","o"},
};

但是,如果我们能够分割成 Rows、Column 和 Diagonals 。 给定{"x","x","x"},{"x","x","o"} 将更容易找到获胜者。

行/列

根据您之前的问题b,您已经知道在二维数组上,我们可以使用 GetLength(1)GetLength(0) 计算列和行的数量。

对于此示例,第一行索引是:
{ (0,0), (0,1), (0,2) }

static string[] GetRow(string[,] source, int rowNumber)
{
    var rows = source.GetLength(0);
    var result = new string[rows];
    for (int i = 0; i < rows; i++)
    {
        result[i] = source[rowNumber, i];
    }
    return result;
}

对于列,我们自然会有相同的代码:

static string[] GetColumn<T>(string[,] source, int columnNumber)
{
    var cols = source.GetLength(1);
    var result = new string[cols];
    for (int i = 0; i < cols; i++)
    {
        result[i] = source[i, columnNumber];
    }
    return result;
}

对角线

让我们使用https://en.wikipedia.org/wiki/Main_diagonal命名对角线。
主对角线索引为{(0,0) , (1,1), (2,2)}
它看起来像同一个循环,但带有 (i,i)

string[] GetSquareMatrixMainDiagonal(string[,] source)
{// {(0,0) , (1,1), (2,2)}

    var cols = source.GetLength(0);
    var rows = source.GetLength(1);
    if (cols != rows) // diagonal will not work on not square matrix.
        throw new ArgumentException($"2D Array [{rows},{cols}], is not a Square matrix");

    var result = new string[rows];
    for (int i = 0; i < rows; i++)
    {
        result[i] = source[i, i];
    }
    return result;
}

对于反对角线索引将是{(0,2) , (1,1), (2,0)}
行数从 0 > 1 > 2 递增。
而列则相反。 2 > 1 > 0

static string[] GetSquareMatrixAntiDiagonal(string[,] source)
{
    var cols = source.GetLength(0);
    var rows = source.GetLength(1);
    if (cols != rows) throw new ArgumentException($"2D Array [{rows},{cols}], is not a Square matrix");

    var result = new string[rows];
    var row = 0;
    var col = rows - 1;
    for (int i = 0; i < rows; i++)
    {
        result[i] = source[row++, col--];
    }
    return result;
}

这里是获取行、列和对角线的简单示例:
https://dotnetfiddle.net/FjPIqY

获胜者?

现在我们有了获取二维数组切片的方法,例如{"x","x","o"}。我们需要比较一个数组的所有元素来判断它们是否相同。 我们将保存第一个元素的值。并检查是否所有其他都等于它。

static string Winner(string[] source)
{
    var val = source.First();
    var isTheSame = source.Skip(1).All(x => x == val);
    return isTheSame ? val : default(string);
}    

小心,这将作为{"","",""} 的获胜者返回空值。 但是我们可以在最后的检查中简单地排除这个。

这是另一个没有 LinQ 的版本。并正确处理空单元格的空字符串和默认值。 免责声明:此方法中使用的有效符号与小提琴输入不匹配。

static bool CheckWinner(string[] source, out string winnerSymbol)
{
    winnerSymbol= "-"; // "-", arbitrary representation of an empty cell. 1 char for simple layout.
    
    var firstVal = source[0];
    for(int i = 1; i < source.Length; i++){ 
        if(source[i] != firstVal){
            return false;
        }
    }
    
    // Will be nice to have valid Symbols in an array.
    if(firstVal!= "0" && firstVal != "X"){      
        return false;
    }
    
    winnerSymbol = firstVal;
    return true;
}

static void ExampleUsageOf_CheckWinner(){
    var winInput= new []{"0","0","0"};  
    var looseInput= new []{"0","0","X"};


    if(CheckWinner(winInput, out string winnerSymbol)){
        Console.WriteLine( winnerSymbol +"is a Winner in winInput")
    }
    else{
        Console.WriteLine( "No winner in winInput!")
    }
    
    
    if(CheckWinner(looseInput, out string winnerSymbol)){
        Console.WriteLine( winnerSymbol +"is a Winner in looseInput")
    }
    else{
        Console.WriteLine( "No winner in looseInput!")
    }
} 

再分解

所有方法都以相同的方式工作:行数或列数的循环。 但是在方阵中的行数和列数是一样的..
为了得到所有的行,我们需要一个循环才能不写:

var r1 = GetRow(input, 0);
var r2 = GetRow(input, 1);
var r3 = GetRow(input, 2);

如果将“行数或列数”重命名为大小。在检查它是一个方阵之后。 每个方法都可以在同一个循环中。让我们尝试合并GetRowGetColumn 来说明:col_row_index = 0; 用于第一行和第一列。

var size = source.GetLength(0);

var currentColumn = new string[size]; // old result variable
var currentRow = new string[size];    // old result variable

for (int i = 0; i < size; i++)
{
    currentColumn[i] = source[i, col_row_index];
    currentRow[i] = source[col_row_index, i];
}

我们现在可以检查其中一个是否是获胜者:

var winnerC = Winner(currentColumn);
var winnerR = Winner(currentColumn);

if(winnerC != ""){
    // Stop everything! We have a winner 
    // Console.WriteLine + Break, if we are in a loop.
    // Set a boolean to true, if we use some State machine.
    // Return if we are in method
}

if(winnerR != ""){ // Same
}

Example.

我让你对对角线进行合并。并且您应该能够通过少量修改进行整个电路板检查。

【讨论】:

  • 谢谢@DragandDrop 的解释。现在我正在尝试重新编写代码。完成后我会告诉你的。再次感谢!
  • 当有人将井字游戏作为控制台程序编写时,我可能不会跳到基于 LINQ 的解决方案,除非您确定 LINQ 在他们的教学大纲中出现在“数组和循环”之前跨度>
  • @SimonaM。重新编写时:现在就一步一步地做。不要专注于用户输入和转向。有一个简单的示例网格,就像这个答案中的小提琴一样。接受重复代码,直到你有一个工作示例。但有明确的目的分离。不要把所有东西混在一起。如果有帮助,请接受范围限制,从 NxN 网格切换到硬代码 3x3。不要没有目标的分层分解:减少网格上的循环或降低性能。
  • 添加了 LinQ 替代方案。用一些绒毛,为了说明空字符串的处理
  • @SimonaM.,但是 tic tac toc 没有 N 大小的网格。对于 3 x 3,最简单的方法是将获胜视为字节数组。例如,赢得第一排的是{{1,1,1}{0,0,0}{0,0,0}} => flatern to {1,1,1,0,0,0,0,0,0}codepen.io/labiej/post/…。不要感谢我的脑筋急转弯。