二(游戏主代码))
我这里没用数据绑定直接操作控件看起来直观些。有些代码看着长循环多其实程序反应还是很灵敏的。public class MineGame { private readonly GameBtn[,] gameBtns;//按钮坐标指针 private readonly int[,] gameData; // 0-8: 数字, 9: 雷 private bool firstClick;//保证第一次点击不是雷 private bool gameOver; //本次游戏结束按钮无效 private readonly int rows, cols, mines;//行、列、雷数 private int openCount;//判断胜利把所有非雷点开就胜利判断是否等于非雷总数。 private int seconds;//记录用时 private int mineCount;//标记后剩余雷数 private Point? rightDown;//记录右键按下的坐标 //直接操作控件 public UniformGrid GameGrid { get; set; } new() { HorizontalAlignment HorizontalAlignment.Center, VerticalAlignment VerticalAlignment.Center }; public TextBlock LblTimer { get; set; } new() { VerticalAlignment VerticalAlignment.Center, Text 0 }; public TextBlock LblMines { get; set; } new() { VerticalAlignment VerticalAlignment.Center, Text 10 }; private readonly DispatcherTimer timer new() { Interval TimeSpan.FromSeconds(1) }; public MineGame(int rs, int cs, int ms) { rows rs; cols cs; mines ms; openCount 0; mineCount ms; LblMines.Text mineCount.ToString(); LblTimer.Text 0; gameBtns new GameBtn[rows, cols]; gameData new int[rows, cols]; firstClick true; gameOver false; timer.Tick Timer_Tick; GameGrid.Rows rows; GameGrid.Columns cols; GameGrid.Children.Clear(); for (int r 0; r rows; r) { for (int c 0; c cols; c) { GameBtn btn new() { Width 35, Height 35, FontSize 14, FontWeight FontWeights.Bold, Foreground Brushes.LightGray, Background Brushes.LightGray, Tag new Point(c, r) // 存储坐标 }; // 绑定事件 btn.Click Button_Click; btn.PreviewMouseRightButtonDown Button_RightDown; btn.PreviewMouseRightButtonUp Button_RightUp; gameBtns[r, c] btn; GameGrid.Children.Add(btn); } } } private void Timer_Tick(object? sender, EventArgs e) { seconds; LblTimer.Text seconds.ToString().PadLeft(3, 0); } private void Button_Click(object sender, RoutedEventArgs e) { if (gameOver) return; if (sender is GameBtn btn) { Point pos (Point)btn.Tag; int r (int)pos.Y; int c (int)pos.X; if (firstClick) { firstClick false; GameStart(r, c); } if (!btn.Opened !btn.Signed) { RevealBtn(r, c); } } } private void Button_RightDown(object sender, MouseButtonEventArgs e) { if (gameOver)return; if (sender is GameBtn btn) { if (btn.Opened) { //对周围标记雷数与显示雷数多余的显示按钮按下状态 Point pos (Point)btn.Tag; int r (int)pos.Y; int c (int)pos.X; if (gameData[r, c] 0) { rightDown pos;//记录右键按下时的坐标 int signs 0; for (int i -1; i 1; i) { for (int j -1; j 1; j) { if (r i 0 r i rows c j 0 c j cols) { if (gameBtns[r i, c j].Signed) { signs; } } } } if (signs gameData[r, c]) { for (int i -1; i 1; i) { for (int j -1; j 1; j) { if (r i 0 r i rows c j 0 c j cols) { if (!gameBtns[r i, c j].Opened !gameBtns[r i, c j].Signed) { gameBtns[r i, c j].Background Brushes.Gray; } } } } } } } } } private void Button_RightUp(object sender, MouseButtonEventArgs e) { if (gameOver)return; if (sender is GameBtn btn) { Point pos (Point)btn.Tag; if (rightDown.HasValue rightDown ! pos)//如果右键抬起时不在原位则恢复按钮背景色 { int r (int)rightDown.Value.Y; int c (int)rightDown.Value.X; for (int i -1; i 1; i) { for (int j -1; j 1; j) { if (r i 0 r i rows c j 0 c j cols) { if (!gameBtns[r i, c j].Opened !gameBtns[r i, c j].Signed) { gameBtns[r i, c j].Background Brushes.LightGray; } } } } rightDown null; return; } rightDown null;//一次性用完就丢掉 int rb (int)pos.Y; int cb (int)pos.X; if (btn.Opened) { //对周围标记雷数与显示雷数多余的按钮予以打开 if (gameData[rb, cb] 0) { int signs 0; for (int i -1; i 1; i) { for (int j -1; j 1; j) { if (rb i 0 rb i rows cb j 0 cb j cols) { if (gameBtns[rb i, cb j].Signed)signs; } } } if (signs gameData[rb, cb]) { for (int i -1; i 1; i) { for (int j -1; j 1; j) { RevealBtn(rb i, cb j); } } } } } else { btn.Signed !btn.Signed; if (btn.Signed) { mineCount--; } else { mineCount; } LblMines.Text mineCount.ToString(); } } } private void RevealBtn(int r, int c)//打开按钮 { if (r 0 || r rows || c 0 || c cols) return;//超出范围无效 if (gameBtns[r, c].Opened || gameBtns[r, c].Signed) return;//已经打开和已标记的不用理它 var btn gameBtns[r, c]; int val gameData[r, c]; if (val 0 val 9) { btn.Content val.ToString(); // 根据数字设置颜色 btn.Foreground val switch { 1 Brushes.Blue, 2 Brushes.Green, 3 Brushes.Red, 4 Brushes.DarkBlue, 5 Brushes.Brown, 6 Brushes.Cyan, 7 Brushes.Black, 8 Brushes.Gray, _ Brushes.Black }; } if (gameData[r, c] 9)//碰到雷了失败 { GameOver(false); return; } btn.Opened true;//新按钮类里自动变换背景色 openCount; if (openCount rows * cols - mines)//每打开一个非雷按钮就要判断是否获胜 { GameOver(true); return; } if (val 0) // 如果是0递归打开周围 { btn.Content null; for (int i -1; i 1; i) { for (int j -1; j 1; j) { RevealBtn(r i, c j); } } } } private void GameStart(int rp, int cp) { timer.Start(); Random rand new(); int minesPlaced 0; while (minesPlaced mines)//布雷操作 { int r rand.Next(rows); int c rand.Next(cols); if (r rp c cp)//布雷到了第一次点击的按钮上了放过 { continue; } if (gameData[r, c] ! 9) { gameData[r, c] 9; minesPlaced; } } // 计算周围雷数 for (int r 0; r rows; r) { for (int c 0; c cols; c) { if (gameData[r, c] 9) continue; int count 0; for (int i -1; i 1; i) { for (int j -1; j 1; j) { int nr r i; int nc c j; if (nr 0 nr rows nc 0 nc cols) { if (gameData[nr, nc] 9) count; } } } gameData[r, c] count; } } } private void GameOver(bool v) { timer.Stop(); gameOver true; if (v) { MessageBox.Show($恭喜 {LoginWindow.CurrentUser}你赢了\n用时: {seconds} 秒, 胜利, MessageBoxButton.OK, MessageBoxImage.Information); } else { // 显示所有雷 for (int r 0; r rows; r) { for (int c 0; c cols; c) { if (gameData[r, c] 9) { gameBtns[r, c].Content ; gameBtns[r, c].Background Brushes.LightPink; gameBtns[r, c].Foreground Brushes.Black; } else if (gameBtns[r, c].Signed) { // 标错雷了 gameBtns[r, c].Content ❌; gameBtns[r, c].Background Brushes.LightPink; } } } MessageBox.Show(游戏结束你踩到雷了。, 失败, MessageBoxButton.OK, MessageBoxImage.Error); } } public void GameReset()//重置游戏 { if (firstClick) return; timer.Stop(); firstClick true; gameOver false; openCount 0; seconds 0; LblTimer.Text 0; mineCount mines; LblMines.Text mines.ToString(); // 清空数据,恢复状态 for (int r 0; r rows; r) for (int c 0; c cols; c) { gameData[r, c] 0; gameBtns[r, c].Opened false; gameBtns[r, c].Signed false; gameBtns[r, c].Content null; gameBtns[r, c].Background Brushes.LightGray; } } }