连续查找5个相同颜色的元素

时间:2015-11-18 06:32:56

标签: c# arrays multidimensional-array

我创建了一个二维数组[19,19]的标签。单击时,用户会根据迭代将标签的颜色更改为黑色或白色。当有五个相同颜色的标签水平,垂直或对角排列时,我想要弹出一个消息框。只有对角线检查不起作用,我不知道为什么。任何帮助将不胜感激。

class gamePlay
{
    const int WinLength = 5;
    const int BoardWidth = 19;
    const int BoardHeight = 19;

    const int kwinningCount = 5;

    public Color? CheckWinner(Label[,] board)
    {
        int columnCount = board.GetLength(1), rowCount = board.GetLength(0);

        for (int row = 0; row < rowCount; row++)
        {
            Color? lineResult = CheckWinnerForLine(board, 0, row, columnCount, 1, 0);

            if (lineResult != null)
            {
                return lineResult;
            }

            if (rowCount - row >= kwinningCount)
            {
                lineResult = CheckWinnerForLine(board, 0, row, rowCount - row, 1, 1);

                if (lineResult != null)
                {
                    return lineResult;
                }
            }
        }

        for (int column = 0; column < columnCount; column++)
        {
            Color? lineResult = CheckWinnerForLine(board, column, 0, rowCount, 0, 1);

            if (lineResult != null)
            {
                return lineResult;
            }

            if (column > 0 && columnCount - column >= kwinningCount)
            {
                lineResult =
                    CheckWinnerForLine(board, column, 0, columnCount - column, 1, 1);

                if (lineResult != null)
                {
                    return lineResult;
                }
            }
        }

        return null;
    }

    Color? CheckWinnerForLine(Label[,] board,
        int column, int row, int count, int columnIncrement, int rowIncrement)
    {
        // Initialize from the first cell
        int colorCount = 1;
        Color currentColor = board[row, column].BackColor;

        while (--count > 0)
        {
            column += columnIncrement;
            row += rowIncrement;

            Color cellColor = board[row, column].BackColor;

            if (currentColor != cellColor)
            {
                // switched colors, so reset for this cell to be the first of the string
                colorCount = 1;
                currentColor = cellColor;
            }
            else if (++colorCount == kwinningCount && cellColor != Color.Transparent)
            {
                return cellColor;
            }
        }

        return null;
    }
public partial class Form1 : Form
{
    int iteration = 0;
    public Label[,] board = new Label[19,19];
    int count;
    int columnIncrement;
    int rowIncrement;
    const int WinLength = 5;
    const int BoardWidth = 19;
    const int BoardHeight = 19;
    gamePlay WinCheck = new gamePlay();

    public Form1()
    {
        InitializeComponent();

        int x = this.Location.X + 10;
        int y = this.Location.Y + 15;

        // create 361 labels, set their properties
        for (int i = 0; i < 19; i++)
        {
            for (int j = 0; j < 19; j++)
            {
                board[i,j] = new Label();
                board[i,j].Parent = this;
                board[i,j].Name = "label" + i;
                //board[i,j].BackColor = System.Drawing.ColorTranslator.FromHtml("#DBB262");
                board[i,j].BackColor = Color.Transparent;
                //board[i, j].StyleChanged = Opacity
                //set size of labels
                board[i,j].Size = new Size(30, 30);
                //initialize click event handler
                this.board[i,j].Click += new System.EventHandler(this.labelClick);
                this.Controls.Add(board[i,j]);
                board[i,j].BringToFront();
            }

        }



        // set the position of the label
        for (int i = 0; i < 19; i++)
        {
            for (int j = 0; j < 19; j++)
            {
                board[i,j].Location = new Point(x, y);
                //set distance between labels
                if (x >= 755)
                {
                    x = this.Location.X + 10;
                    y += 42;
                }

                else
                {
                    x += 43;
                }
            }

        }
    }

        private void labelClick (object sender, EventArgs e)
        {

            Label clickedLabel = (Label)sender;

            if (clickedLabel.BackColor == Color.Transparent)
            {
                if (iteration % 2 == 0)
                {
                    clickedLabel.BackColor = Color.Black;
                }
                else
                {
                    clickedLabel.BackColor = Color.White;
                }
                iteration++;
            }
            else
            {

            }

            for (int row = 0; row < BoardHeight; row++)
            {
                for (int column = 0; column < BoardWidth; column++)
                {
                    if (board[row, column] == clickedLabel)
                    {
                        Color? winner = WinCheck.CheckWinner(board);
                        if (winner == Color.Black)
                        {
                            MessageBox.Show("Black is the winner!");
                        }
                        else if (winner == Color.White)
                        {
                            MessageBox.Show("White is the winner!");
                        }
                    }
                }
            }
        }

        private int[] FindClickedLabelCoordinates(Label[,] board, Label label)
        {
            for (int row = 0; row < BoardHeight; row++)
            {
                for (int column = 0; column < BoardWidth; column++)
                {
                    if (board[row, column] == label)
                        return new int[] { row, column };
                }
            }
            return null;
        }

4 个答案:

答案 0 :(得分:1)

你不需要复述,但有点修改循环:

private static Boolean IsWon(Label[,] board) {
  if (null == board)
    return false;

  // Let code not be that rigid: "5" can be easily updated 
  const int atLeast = 5; 

  // Do not use magic numbers - i.e. "19"
  for (int i = 0; i < board.GetLength(0); ++i) {
    Color current = board[i, 0].BackColor;
    int count = 1;

    for (int j = 1; j < board.GetLength(1); ++j) { // note j = 1
      if (current == board[i, j].BackColor) {
        count += 1;

        if (count >= atLeast)   
          return true;
      }      
      else {
        current = board[i, j].BackColor;
        count = 1;
      } 
    }
  } 

  return false;
}

public void checkWinner(Label[,] board) {
  if (IsWon(board))
    MessageBox.Show("You Win!");
}

作为进一步改进,将模型(即游戏字段 - board [,])及其表示Label s分离在表单上)。

答案 1 :(得分:1)

<强>&LT;编辑&gt;
正如您的后续问题Aligning labels in array of same backcolor diagonally in C#所表明的那样,您无法概括此处提供的解决方案,以便与您对计划感兴趣的其他两个方向一致。

所以我已经编辑了这个问题的答案,以更一般的方式在这里解决你的问题,这样它也可以修复你的对角线和垂直问题。请参阅下面的更新代码。
&LT; /编辑&gt;


当然,不需要递归。我还建议寻找具有扩展if表达式的特定模式是浪费的,并且对于您编写的代码,无论如何都不会工作。事实上,避免像这样的复杂表达的一个原因是它们很容易出错。

这是一种方法,对于每一行,扫描行以查找相同颜色的五个字符串。一旦找到这样的字符串,它就会返回找到的Color值(这样调用者就可以判断它是黑色还是白色)。如果未找到此类字符串,则返回null。换句话说,一个非空值告诉你有人赢了,它也告诉你哪个牌手赢了。

<强>&LT;编辑&gt;
这个新版本以一般方式完成上述操作。即上一段描述了扫描行时实现的工作原理。它将对角线和水平线进行类似的操作。它通过让main方法为您要检查的给定水平线,对角线和垂直线生成适当的起点和单元计数,然后调用实际工作以查找相同字符串的通用方法来实现此目的。颜色依次。
&LT; /编辑&gt;

<强> GamePlay.cs:

class GamePlay
{
    private readonly int _winLength = 5;

    public GamePlay(int winLength)
    {
        _winLength = winLength;
    }

    public Color? CheckWinner(Label[,] board)
    {
        return CheckWinnerIterator(board).FirstOrDefault(color => color != null);
    }

    private IEnumerable<Color?> CheckWinnerIterator(Label[,] board)
    {
        int columnCount = board.GetLength(1), rowCount = board.GetLength(0);

        for (int row = 0; row < rowCount; row++)
        {
            // Horizontal
            yield return CheckWinnerForLine(board, 0, row, columnCount, 1, 0);
            // Diagonals starting in first column, upper-left to lower-right
            yield return CheckWinnerForLine(board, 0, row, rowCount - row, 1, 1);
            // Diagonals starting in first column, lower-left to upper-right
            yield return CheckWinnerForLine(board, 0, row, row + 1, 1, -1);
        }

        for (int column = 0; column < columnCount; column++)
        {
            // Vertical
            yield return CheckWinnerForLine(board, column, 0, rowCount, 0, 1);
            // Diagonals starting in first row, upper-left to lower-right
            yield return CheckWinnerForLine(board, column, 0, columnCount - column, 1, 1);
            // Diagonals starting in last row, lower-left to upper-right
            yield return CheckWinnerForLine(board, column, rowCount - 1, columnCount - column, 1, -1);
        }
    }

    Color? CheckWinnerForLine(Label[,] board,
        int column, int row, int count, int columnIncrement, int rowIncrement)
    {
        if (count < _winLength)
        {
            return null;
        }

        // Initialize from the first cell
        int colorCount = 1;
        Color currentColor = board[row, column].BackColor;

        while (--count > 0)
        {
            column += columnIncrement;
            row += rowIncrement;

            Color cellColor = board[row, column].BackColor;

            if (currentColor != cellColor)
            {
                // switched colors, so reset for this cell to be the first of the string
                colorCount = 1;
                currentColor = cellColor;
            }
            else if (++colorCount == _winLength && cellColor != Color.Transparent)
            {
                return cellColor;
            }
        }

        return null;
    }
}

<强> Form1.cs的

public partial class Form1 : Form
{
    const int WinLength = 5;
    const int BoardWidth = 19;
    const int BoardHeight = 19;

    private bool isBlackTurn = true;
    private Label[,] board = new Label[BoardHeight, BoardWidth];
    private GamePlay WinCheck = new GamePlay(WinLength);

    public Form1()
    {
        InitializeComponent();

        int x = this.Location.X + 10;
        int y = this.Location.Y + 15;

        // create 361 labels, set their properties
        for (int i = 0; i < BoardHeight; i++)
        {
            for (int j = 0; j < BoardWidth; j++)
            {
                Label label = new Label();

                label.Parent = this;
                label.Name = "label" + i;
                label.BackColor = Color.Transparent;
                label.BorderStyle = BorderStyle.FixedSingle;
                label.Size = new Size(30, 30);
                label.Click += new System.EventHandler(this.labelClick);
                this.Controls.Add(board[i, j]);
                label.BringToFront();

                board[i, j] = label;
            }

        }

        // set the position of the label
        for (int i = 0; i < BoardHeight; i++)
        {
            for (int j = 0; j < BoardWidth; j++)
            {
                board[i, j].Location = new Point(x, y);
                //set distance between labels
                if (x >= 755)
                {
                    x = this.Location.X + 10;
                    y += 42;
                }

                else
                {
                    x += 43;
                }
            }

        }
    }

    private void labelClick(object sender, EventArgs e)
    {
        Label clickedLabel = (Label)sender;

        if (clickedLabel.BackColor != Color.Transparent)
        {
            return;
        }

        clickedLabel.BackColor = isBlackTurn ? Color.Black : Color.White;
        isBlackTurn = !isBlackTurn;

        Color? winner = WinCheck.CheckWinner(board);
        if (winner == Color.Black)
        {
            MessageBox.Show("Black is the winner!");
        }
        else if (winner == Color.White)
        {
            MessageBox.Show("White is the winner!");
        }
        else
        {
            return;
        }

        foreach (Label label in board)
        {
            label.BackColor = Color.Transparent;
        }
    }
}

<强>&LT;编辑&gt;

注意:以上代码不仅代表了胜利测试的更正版本,而且代表了代码的重大清理:

  • 首先,我忽略了一半的对角线情况,即从左下角到右上角的情况。我已经解决了这个问题。这可能是您获得代码报告对角线胜利的难度的原因。
  • 我的代码的先前版本已经变得有点冗长我的口味,并且在循环中添加另外两个用于win-testing的案例将它推到了我的边缘。通过将主循环逻辑转换为迭代器方法,然后使用简单的LINQ语句枚举案例并在找到胜利者时提前中断,我“稍微倾听”了代码。
  • 在您的代码中,我完全删除了FindClickedLabelCoordinates()方法以及一些字段,因为它们都未使用过。
  • 同样在您的代码中,我显着降低了labelClick()方法的复杂性。它有相当多的冗余和过于冗长的实施细节;我已经将该方法减少到接近所需的最低代码。
  • 我还在每个Label周围添加了一个边框,以便我更容易看到我应该/可以点击的位置。

最后,在您的评论中,您有以下问题:

  

宣布获胜者后,每增加一次点击白色赢得

后,就会弹出一个消息框

是的,在您的代码版本中,这将会发生,因为代码会在每次点击后检查获胜者,这会改变董事会状态(应该如此),一旦有胜利者,除非您有胜利者重置电路板。因此,每次点击都会导致检测到胜利者。我已经在labelClick()中添加了上面的代码,如果找到了胜利者则继续重置电路板。

&LT; /编辑&gt;


对于笑嘻嘻(因此我可以仔细检查我的工作,因为OP没有提供完整的代码示例,可以通过测试来验证答案),这里是一个快速而肮脏的WPF程序,它包含了上述方法(稍加修改一下):

<强> XAML:

<Window x:Class="TestSO33773260FiveInARow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:TestSO33773260FiveInARow"
        Title="MainWindow" Height="525" Width="525">

  <ItemsControl ItemsSource="{Binding Board}" Background="AliceBlue">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <UniformGrid x:Name="uniformGrid1" Rows="{Binding Rows}" Columns="{Binding Columns}" IsItemsHost="True"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
      <DataTemplate DataType="l:BoardCell">
        <Rectangle Fill="{Binding Color}" MouseUp="Rectangle_MouseUp"/>
      </DataTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</Window>

<强> C#:

public partial class MainWindow : Window
{
    private const int _kwinningCount = 5;
    public int Rows { get; set; }
    public int Columns { get; set; }
    public List<BoardCell> Board { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        Rows = 19;
        Columns = 19;
        Board = new List<BoardCell>(Enumerable.Range(0, Rows * Columns)
            .Select(i => new BoardCell { Color = Brushes.Transparent }));
        DataContext = this;
    }

    private void Rectangle_MouseUp(object sender, MouseButtonEventArgs e)
    {
        BoardCell boardCell = (BoardCell)((FrameworkElement)sender).DataContext;

        boardCell.IncrementColor();

        Color? winningColor = CheckWinner();

        if (winningColor != null)
        {
            MessageBox.Show(winningColor.Value.GetFriendlyName() + " won!");
        }
    }

    private Color _GetColorForBoardCell(int column, int row)
    {
        return Board[column + row * Rows].Color.Color;
    }

    public Color? CheckWinner()
    {
        return CheckWinnerIterator().FirstOrDefault(color => color != null);
    }

    private IEnumerable<Color?> CheckWinnerIterator()
    {
        int columnCount = Columns, rowCount = Rows;

        for (int row = 0; row < rowCount; row++)
        {
            // Horizontal
            yield return CheckWinnerForLine(0, row, columnCount, 1, 0);
            // Diagonals starting in first column, upper-left to lower-right
            yield return CheckWinnerForLine(0, row, rowCount - row, 1, 1);
            // Diagonals starting in first column, lower-left to upper-right
            yield return CheckWinnerForLine(0, row, row + 1, 1, -1);
        }

        for (int column = 0; column < columnCount; column++)
        {
            // Vertical
            yield return CheckWinnerForLine(column, 0, rowCount, 0, 1);
            // Diagonals starting in first row, upper-left to lower-right
            yield return CheckWinnerForLine(column, 0, columnCount - column, 1, 1);
            // Diagonals starting in last row, lower-left to upper-right
            yield return CheckWinnerForLine(column, rowCount - 1, columnCount - column, 1, -1);
        }
    }

    Color? CheckWinnerForLine(int column, int row, int count, int columnIncrement, int rowIncrement)
    {
        // Initialize from the first cell
        int colorCount = 1;
        Color currentColor = _GetColorForBoardCell(column, row);

        while (--count > 0)
        {
            column += columnIncrement;
            row += rowIncrement;

            Color cellColor = _GetColorForBoardCell(column, row);

            if (currentColor != cellColor)
            {
                // switched colors, so reset for this cell to be the first of the string
                colorCount = 1;
                currentColor = cellColor;
            }
            else if (++colorCount == _kwinningCount && cellColor != Colors.Transparent)
            {
                return cellColor;
            }
        }

        return null;
    }
}

public class BoardCell : INotifyPropertyChanged
{
    private static readonly SolidColorBrush[] _colors =
        { Brushes.Transparent, Brushes.White, Brushes.Black };

    private int _colorIndex;

    public SolidColorBrush Color
    {
        get { return _colors[_colorIndex]; }
        set
        {
            if (value != _colors[_colorIndex])
            {
                _SetColorIndex(Array.IndexOf(_colors, value));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void _OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public void IncrementColor()
    {
        _SetColorIndex(_colorIndex < _colors.Length - 1 ? _colorIndex + 1 : 0);
    }

    private void _SetColorIndex(int colorIndex)
    {
        _colorIndex = colorIndex;
        _OnPropertyChanged("Color");
    }
}

static class Extensions
{
    private static readonly Lazy<Dictionary<Color, string>> _colorToName =
        new Lazy<Dictionary<Color, string>>(() => GetColorToNameDictionary());

    private static Dictionary<Color, string> GetColorToNameDictionary()
    {
        Dictionary<Color, string> colorToName = new Dictionary<Color, string>();

        foreach (PropertyInfo pi in
            typeof(Colors).GetProperties(BindingFlags.Static | BindingFlags.Public))
        {
            if (pi.PropertyType == typeof(Color))
            {
                colorToName[(Color)pi.GetValue(null)] = pi.Name;
            }
        }

        return colorToName;
    }

    public static string GetFriendlyName(this Color color)
    {
        string name;

        if (_colorToName.Value.TryGetValue(color, out name))
        {
            return name;
        }

        return color.ToString();
    }
}

答案 2 :(得分:0)

private void Check(Label[,] board)
{
    int Checker = 0;

    for (int i = 0; i < 19; i++)
    {
        for (int j = 0; j < 19; j++)
        {
            if (board[i, j].BackColor == Color.Black)
                Checker++;
            else
                Checker = 0;

            if (Checker == 5)
            {
                MessageBox.Show("You WON....!");
                return;
            }
        }
    }
}

答案 3 :(得分:0)

它不仅仅是for循环可以得到那个结果。您也可以尝试一些linq。我试图连续5次找到“1”..下面的代码工作正常。

int countItemNeed = 5;
string[,] arr = new string[7, 6]
{
    {"0", "1", "1", "1", "0", "1"},
    {"1", "0", "1", "1", "1", "0"},
    {"1", "0", "1", "1", "1", "0"},
    {"1", "0", "1", "1", "1", "0"},
    {"1", "0", "1", "1", "1", "0"},
    {"1", "0", "1", "1", "1", "0"},
    {"1", "0", "1", "1", "1", "1"},
};

//convert the 2d array to list of object - List<new{string,index}>
var oneList = arr.Cast<string>()
    .Select((s,i)=> new {s,i}); 

// convert the List to into sub list. one for each row in 2D array   
var multipleList = new List<List<Tuple<string, int>>>();
//Size of the row - mean column in a row.
int size = arr.GetLength(1);
while (oneList.Any())
{
    multipleList.Add(oneList
                     .Take(size)
                     .Select(c=>Tuple.Create(c.s, c.i%size)).ToList());
    oneList = oneList.Skip(size).ToList();
}

// check each row. then check each item if we have all 5 items as same.
var foundContinueItems = multipleList.Any(list =>
{
    return list.Any(c =>
    {
        if (c.Item2 > size - countItemNeed)
        {
            return false;
        }
        return list.Skip(c.Item2)
                    .Take(countItemNeed)
                    .All(d => d.Item1 == "1");
    });
});

检查小提琴https://dotnetfiddle.net/YSOCJm