如何确定 C# 数组中同一行的 5 个标签?
How to determine 5 labels in a row of the same backcolor in a C# array?
我创建了一个二维标签数组 [19,19]。单击时,用户根据迭代将标签的颜色更改为黑色或白色。当有五个相同颜色的标签水平排列时,我希望弹出一个消息框。这是在没有递归的情况下完成的。任何帮助将不胜感激。
public partial class Form1 : Form
{
int labelCount = 0;
int iteration = 0;
public Label[,] board = new Label[19,19];
const int WinLength = 5;
const int BoardWidth = 19;
const int BoardHeight = 19;
gamePlay obj = new gamePlay();
public Form1()
{
InitializeComponent();
}
private void labelClick (object sender, EventArgs e)
{
Label x = (Label)sender;
if (x.BackColor == Color.Transparent)
{
if (iteration % 2 == 0)
{
x.BackColor = Color.Black;
}
else
{
x.BackColor = Color.White;
}
iteration++;
}
else
{
}
for (int r = 0; r < BoardHeight; r++)
{
for (int c = 0; c < BoardWidth; c++)
{
if (board[r, c] == x)
{
Color? winner = obj.CheckForWinner(board, r, c);
if (winner == Color.Black)
{
MessageBox.Show("Black is the winner!");
}
else if (winner == Color.White)
{
MessageBox.Show("White is the winner!");
}
// else winner is null, meaning no winner yet.
}
}
}
private int[] FindClickedLabelCoordinates(Label[,] board, Label label)
{
for (int r = 0; r < BoardHeight; r++)
{
for (int c = 0; c < BoardWidth; c++)
{
if (board[r, c] == label)
return new int[] { r, c };
}
}
return null;
}
}
class gamePlay
{
const int WinLength = 5;
const int BoardWidth = 19;
const int BoardHeight = 19;
private Color? CheckForWinner(Label[,] board, int r, int c)
{
Color startColor = board[r, c].BackColor;
for (int c1 = c - WinLength + 1; c1 <= c; c1++)
{
if (c1 >= 0 && c1 < BoardWidth && board[r, c1].BackColor == startColor)
{
MessageBox.Show("you win!");
bool win = true;
for (int c2 = c1 + 1; c2 < c1 + WinLength; c2++)
{
if (c2 < 0 || c2 >= BoardWidth || board[r, c2].BackColor != startColor)
{
win = false;
break;
}
}
if (win)
{
return startColor;
}
}
}
return null;
}
在 19 x 19 时,即使您确实检查了整个电路板,他们也需要点击很多次才能减慢您的程序。需要考虑的事情:除非你能证明它对你的用例来说太慢,否则不要过早优化,因为这是浪费精力。 如果你有点击位置并且可以找出位置,您可以从那里递归,尝试找到具有相同颜色的相邻位置。
基本方法是从一个点开始递归 left/right 或 up/down(或任何您的要求),同时保留一个计数器。一旦达到成功条件,return 一路向上。
你实际上不需要递归来解决这个问题;只是几个嵌套循环。既然你说你想从检查水平胜利开始,我将从这里开始。我将使用术语 "stone" 来表示板上的 space,该 space 已被单击以将其变为黑色或白色。
如果棋盘上没有棋子,我们就知道没有获胜礼物。这是游戏的默认状态。只有在棋盘上放置了 5 颗相同颜色的棋子才能获胜。由于一次只放置一颗棋子,每次放置后我们都会检查是否获胜,因此最后放置的棋子必须是获胜棋步的一部分,获胜颜色必须是该棋子的颜色。这听起来很明显,但这意味着不必每次都检查整个棋盘是否获胜。我们只需要检查可能涉及最后放置的石头的可能胜利。此外,我们不需要单独检查它们是全黑还是全白;我们只需要检查它们是否与最后一步的颜色相同,无论是什么颜色。
那么,如果唯一可能的获胜条件是水平的,我们需要检查哪些方块?好吧,假设最后一块石头放在一排的正中央。我们称该方块为 x
。如果石头是胜利的一部分,并且胜利是连续 5 次,那么石头可能是 5 次胜利的一部分:
{x-4, x-3, x-2, x-1, x}
{x-3, x-2, x-1, x, x+1}
{x-2, x-1, x, x+1, x+2}
{x-1, x, x+1, x+2, x+3}
{x, x+1, x+2, x+3, x+4}
所以,这表明了一种算法:
- 获取棋盘上最后一块棋子所在的行和列。
- 得到那块石头的颜色。
- 对于 5 种可能的获胜顺序中的每一种:
a) 从序列最左边的棋盘 space 开始(例如第一个棋盘是 x-4)
b) 检查它和它右边接下来的 4 个棋盘 spaces 是否包含与步骤 2 中颜色相同的棋子。
c) 如果序列中的任何 space 没有与步骤 2 中的颜色相匹配的棋子,则不算赢;我们可以停止检查并立即进入下一个可能的获胜顺序。
d) 如果我们完成了整个序列并且所有 space 都有正确颜色的棋子,那么它就赢了,我们可以 return 获胜颜色。
- 如果我们遍历所有可能的序列都没有找到胜利,那么游戏将继续。
但是,还有一件事需要考虑。如果最后一块棋子放在棋盘的左边缘或右边缘附近怎么办?例如,如果 x
是 2,那么前两个可能的获胜序列,分别以 x-4
和 x-3
开始,是无效的,因为它们部分离开棋盘!所以我们需要添加一些检查以确保我们想要查看的 spaces 实际上在边界内。
以上算法的代码可能如下所示。 r
和 c
参数是最后放置的石头的行和列:
const int WinLength = 5;
const int BoardWidth = 19;
const int BoardHeight = 19;
private Color? CheckForWinner(Label[,] board, int r, int c)
{
Color startColor = board[r, c].BackColor;
for (int c1 = c - WinLength + 1; c1 <= c; c1++)
{
if (c1 >= 0 && c1 < BoardWidth && board[r, c1].BackColor == startColor)
{
bool win = true;
for (int c2 = c1 + 1; c2 < c1 + WinLength; c2++)
{
if (c2 < 0 || c2 >= BoardWidth || board[r, c2].BackColor != startColor)
{
win = false;
break;
}
}
if (win) return startColor;
}
}
return null;
}
以下是从点击处理程序调用上述方法的方法:
private void labelClick(object sender, EventArgs e)
{
// set background color of clicked label here based on whose turn it is
int[] coords = FindClickedLabelCoordinates(board, (Label)sender);
Color? winner = CheckForWinner(board, coords[0], coords[1]);
if (winner == Color.Black)
{
MessageBox.Show("Black is the winner!");
}
else if (winner == Color.White)
{
MessageBox.Show("White is the winner!");
}
// else winner is null, meaning no winner yet.
}
private int[] FindClickedLabelCoordinates(Label[,] board, Label label)
{
for (int r = 0; r < BoardHeight; r++)
{
for (int c = 0; c < BoardWidth; c++)
{
if (board[r, c] == label)
return new int[] { r, c };
}
}
return null;
}
希望这足以让您入门。
首先定义"horizontally"。假设它的第一个数组边界 [x][y].
那么你只需要一个函数来检查一行。
// Has the player won (5 horizontal ticks)?
public bool HasWinner(Label[,] board, Colour player)
{
for (int y = 0; y < 19; y++)
{
if (RowHasLine(y, board, player)
return true;
}
return false;
}
// Returns true if player has a winner in row y
private bool RowHasLine(int y, Label[,] board, Colour player)
{
for (int x = 0; x < 19; x++)
{
if (Ticked(x + 0, y, board, player) &&
Ticked(x + 1, y, board, player) &&
Ticked(x + 2, y, board, player) &&
Ticked(x + 3, y, board, player) &&
Ticked(x + 4, y, board, player))
{
return true;
}
}
return false;
}
// Has the player ticked this box?
private bool Ticked(int x, int y, Label[,] board, Colour player)
{
if (x >= 19 || y >= 19)
return false;
return (board[x][y].BackgroundColor == player);
}
我创建了一个二维标签数组 [19,19]。单击时,用户根据迭代将标签的颜色更改为黑色或白色。当有五个相同颜色的标签水平排列时,我希望弹出一个消息框。这是在没有递归的情况下完成的。任何帮助将不胜感激。
public partial class Form1 : Form
{
int labelCount = 0;
int iteration = 0;
public Label[,] board = new Label[19,19];
const int WinLength = 5;
const int BoardWidth = 19;
const int BoardHeight = 19;
gamePlay obj = new gamePlay();
public Form1()
{
InitializeComponent();
}
private void labelClick (object sender, EventArgs e)
{
Label x = (Label)sender;
if (x.BackColor == Color.Transparent)
{
if (iteration % 2 == 0)
{
x.BackColor = Color.Black;
}
else
{
x.BackColor = Color.White;
}
iteration++;
}
else
{
}
for (int r = 0; r < BoardHeight; r++)
{
for (int c = 0; c < BoardWidth; c++)
{
if (board[r, c] == x)
{
Color? winner = obj.CheckForWinner(board, r, c);
if (winner == Color.Black)
{
MessageBox.Show("Black is the winner!");
}
else if (winner == Color.White)
{
MessageBox.Show("White is the winner!");
}
// else winner is null, meaning no winner yet.
}
}
}
private int[] FindClickedLabelCoordinates(Label[,] board, Label label)
{
for (int r = 0; r < BoardHeight; r++)
{
for (int c = 0; c < BoardWidth; c++)
{
if (board[r, c] == label)
return new int[] { r, c };
}
}
return null;
}
}
class gamePlay
{
const int WinLength = 5;
const int BoardWidth = 19;
const int BoardHeight = 19;
private Color? CheckForWinner(Label[,] board, int r, int c)
{
Color startColor = board[r, c].BackColor;
for (int c1 = c - WinLength + 1; c1 <= c; c1++)
{
if (c1 >= 0 && c1 < BoardWidth && board[r, c1].BackColor == startColor)
{
MessageBox.Show("you win!");
bool win = true;
for (int c2 = c1 + 1; c2 < c1 + WinLength; c2++)
{
if (c2 < 0 || c2 >= BoardWidth || board[r, c2].BackColor != startColor)
{
win = false;
break;
}
}
if (win)
{
return startColor;
}
}
}
return null;
}
在 19 x 19 时,即使您确实检查了整个电路板,他们也需要点击很多次才能减慢您的程序。需要考虑的事情:除非你能证明它对你的用例来说太慢,否则不要过早优化,因为这是浪费精力。 如果你有点击位置并且可以找出位置,您可以从那里递归,尝试找到具有相同颜色的相邻位置。
基本方法是从一个点开始递归 left/right 或 up/down(或任何您的要求),同时保留一个计数器。一旦达到成功条件,return 一路向上。
你实际上不需要递归来解决这个问题;只是几个嵌套循环。既然你说你想从检查水平胜利开始,我将从这里开始。我将使用术语 "stone" 来表示板上的 space,该 space 已被单击以将其变为黑色或白色。
如果棋盘上没有棋子,我们就知道没有获胜礼物。这是游戏的默认状态。只有在棋盘上放置了 5 颗相同颜色的棋子才能获胜。由于一次只放置一颗棋子,每次放置后我们都会检查是否获胜,因此最后放置的棋子必须是获胜棋步的一部分,获胜颜色必须是该棋子的颜色。这听起来很明显,但这意味着不必每次都检查整个棋盘是否获胜。我们只需要检查可能涉及最后放置的石头的可能胜利。此外,我们不需要单独检查它们是全黑还是全白;我们只需要检查它们是否与最后一步的颜色相同,无论是什么颜色。
那么,如果唯一可能的获胜条件是水平的,我们需要检查哪些方块?好吧,假设最后一块石头放在一排的正中央。我们称该方块为 x
。如果石头是胜利的一部分,并且胜利是连续 5 次,那么石头可能是 5 次胜利的一部分:
{x-4, x-3, x-2, x-1, x}
{x-3, x-2, x-1, x, x+1}
{x-2, x-1, x, x+1, x+2}
{x-1, x, x+1, x+2, x+3}
{x, x+1, x+2, x+3, x+4}
所以,这表明了一种算法:
- 获取棋盘上最后一块棋子所在的行和列。
- 得到那块石头的颜色。
- 对于 5 种可能的获胜顺序中的每一种:
a) 从序列最左边的棋盘 space 开始(例如第一个棋盘是 x-4)
b) 检查它和它右边接下来的 4 个棋盘 spaces 是否包含与步骤 2 中颜色相同的棋子。
c) 如果序列中的任何 space 没有与步骤 2 中的颜色相匹配的棋子,则不算赢;我们可以停止检查并立即进入下一个可能的获胜顺序。
d) 如果我们完成了整个序列并且所有 space 都有正确颜色的棋子,那么它就赢了,我们可以 return 获胜颜色。 - 如果我们遍历所有可能的序列都没有找到胜利,那么游戏将继续。
但是,还有一件事需要考虑。如果最后一块棋子放在棋盘的左边缘或右边缘附近怎么办?例如,如果 x
是 2,那么前两个可能的获胜序列,分别以 x-4
和 x-3
开始,是无效的,因为它们部分离开棋盘!所以我们需要添加一些检查以确保我们想要查看的 spaces 实际上在边界内。
以上算法的代码可能如下所示。 r
和 c
参数是最后放置的石头的行和列:
const int WinLength = 5;
const int BoardWidth = 19;
const int BoardHeight = 19;
private Color? CheckForWinner(Label[,] board, int r, int c)
{
Color startColor = board[r, c].BackColor;
for (int c1 = c - WinLength + 1; c1 <= c; c1++)
{
if (c1 >= 0 && c1 < BoardWidth && board[r, c1].BackColor == startColor)
{
bool win = true;
for (int c2 = c1 + 1; c2 < c1 + WinLength; c2++)
{
if (c2 < 0 || c2 >= BoardWidth || board[r, c2].BackColor != startColor)
{
win = false;
break;
}
}
if (win) return startColor;
}
}
return null;
}
以下是从点击处理程序调用上述方法的方法:
private void labelClick(object sender, EventArgs e)
{
// set background color of clicked label here based on whose turn it is
int[] coords = FindClickedLabelCoordinates(board, (Label)sender);
Color? winner = CheckForWinner(board, coords[0], coords[1]);
if (winner == Color.Black)
{
MessageBox.Show("Black is the winner!");
}
else if (winner == Color.White)
{
MessageBox.Show("White is the winner!");
}
// else winner is null, meaning no winner yet.
}
private int[] FindClickedLabelCoordinates(Label[,] board, Label label)
{
for (int r = 0; r < BoardHeight; r++)
{
for (int c = 0; c < BoardWidth; c++)
{
if (board[r, c] == label)
return new int[] { r, c };
}
}
return null;
}
希望这足以让您入门。
首先定义"horizontally"。假设它的第一个数组边界 [x][y].
那么你只需要一个函数来检查一行。
// Has the player won (5 horizontal ticks)?
public bool HasWinner(Label[,] board, Colour player)
{
for (int y = 0; y < 19; y++)
{
if (RowHasLine(y, board, player)
return true;
}
return false;
}
// Returns true if player has a winner in row y
private bool RowHasLine(int y, Label[,] board, Colour player)
{
for (int x = 0; x < 19; x++)
{
if (Ticked(x + 0, y, board, player) &&
Ticked(x + 1, y, board, player) &&
Ticked(x + 2, y, board, player) &&
Ticked(x + 3, y, board, player) &&
Ticked(x + 4, y, board, player))
{
return true;
}
}
return false;
}
// Has the player ticked this box?
private bool Ticked(int x, int y, Label[,] board, Colour player)
{
if (x >= 19 || y >= 19)
return false;
return (board[x][y].BackgroundColor == player);
}