【WPF】用100行C#代码实现扫雷
文章目錄
- 布局
- 生成雷區(qū)
- 左鍵掃雷和右鍵標(biāo)記
- 翻面功能
布局
布局效果如下,下面每個(gè)“網(wǎng)格”都是一個(gè)按鈕,點(diǎn)擊按鈕,就會(huì)有相應(yīng)的事件發(fā)生。
由于UniformGrid中每個(gè)Grid的尺寸相等,所以作為雷區(qū)的容器。
生成雷區(qū)
值得一提的是,由于隨機(jī)數(shù)可能在生成過(guò)程中產(chǎn)生重復(fù)的值,所以這里通過(guò)概率的方式來(lái)生成雷。
假設(shè)按鈕數(shù)為 N N N,雷數(shù)為 n n n,那么在 [ 0 , N ] [0,N] [0,N]之間隨機(jī)生成一個(gè)數(shù) x x x,如果 x < n x<n x<n,則判定當(dāng)前按鈕為雷。按鈕是否為雷的標(biāo)志作為布爾型存放在btn.tag中。
由于通過(guò)遍歷的方法生成雷,所以一旦剩余雷的個(gè)數(shù)和剩余按鈕的個(gè)數(shù)相等,就說(shuō)明剩余的按鈕全都是雷。這種情況發(fā)生,則不必進(jìn)行隨機(jī)數(shù)的判定。
private void newGame() {x = int.Parse(txtNumX.Text);y = int.Parse(txtNumY.Text);var nBtns = x * y;nMark = 0;nRes = int.Parse(txtNumMine.Text);if (nRes > nBtns)nRes = nBtns;pMine = new List<int>();ugMine.Rows = y;ugMine.Columns = x;ugMine.Children.Clear();Random rd = new Random();int numSetMine = 0; //已經(jīng)布置的雷的個(gè)數(shù)for (int i = 0; i < nBtns; i++){var btn = new Button();ugMine.Children.Add(btn);btn.Click += Btn_Click;btn.MouseRightButtonDown += Btn_MouseRightButtonDown;btn.Content = "";btn.Tag = false;if ((nRes - numSetMine) == (nBtns - i) || //如果剩余的雷數(shù)剛好等于剩余的按鈕數(shù),則剩下的按鈕都是雷(numSetMine < nRes && rd.Next(0, nBtns) < nRes)){btn.Tag = true;numSetMine += 1;pMine.Add(i);}} }左鍵掃雷和右鍵標(biāo)記
左鍵點(diǎn)擊,則類似于一個(gè)翻面的動(dòng)作;右鍵點(diǎn)擊,則相當(dāng)于是標(biāo)記,而且在標(biāo)記之后,不能再通過(guò)左鍵進(jìn)行翻面。
//左鍵單擊 private void Btn_Click(object sender, RoutedEventArgs e) {var btn = sender as Button;int index = ugMine.Children.IndexOf(btn);flipButton(index);if(nMark == pMine.Count || nRes == pMine.Count)MessageBox.Show("您贏了!"); } //右鍵單擊 private void Btn_MouseRightButtonDown(object sender, MouseButtonEventArgs e) {var btn = sender as Button;var flag = btn.Content.ToString() != "🚩";if (flag)btn.Click -= Btn_Click; //如果已經(jīng)標(biāo)記,則卸載左鍵的功能elsebtn.Click += Btn_Click; //如果取消標(biāo)記,則重新掛載左鍵的功能btn.Content = flag ? "🚩" : "";btn.Foreground = flag ? Brushes.Red : Brushes.Gray;nMark += flag ? 1 : -1; }右鍵單擊效果如下
翻面功能
在翻面的時(shí)候,如果當(dāng)前按鈕為雷,則雷炸了,游戲結(jié)束。
如果當(dāng)前按鈕不是雷,那么判斷該按鈕周圍是否有雷。如果有雷,則當(dāng)前按鈕顯示周圍雷的個(gè)數(shù);如果沒(méi)雷,則將周圍的雷全部翻面——需要調(diào)用自身。
private void flipButton(int index) {var btn = ugMine.Children[index] as Button;if (!btn.IsEnabled)return;if ((bool)btn.Tag){foreach (var i in pMine){var mine = ugMine.Children[i] as Button;mine.Content = "💥";mine.Foreground = Brushes.Red;}MessageBox.Show("您輸了");return;}nRes -= 1;btn.IsEnabled = false;int numMines = 0;var nears = setNear(index);foreach (var i in nears){var near = ugMine.Children[i] as Button;if ((bool)near.Tag) numMines += 1;}if (numMines != 0)btn.Content = numMines;elseforeach (var i in nears)flipButton(i); }其中setNear是用于獲取當(dāng)前按周圍按鈕的序號(hào),這里分別需要考慮四個(gè)角、四個(gè)邊以及中間區(qū)域。
private int[] setNear(int index) {if (index == 0)return new int[3] { 1, x, x + 1 };if (index == x * y - 1)return new int[3] { index - 1, index - x, index - x - 1 };if (index == x - 1)return new int[3] { x - 2, 2 * x - 1, 2 * x - 2 };if (index == x * y - x)return new int[3] { index + 1, index - x, index - x + 1 };if (index % x == 0)return new int[5] { index - x, index - x + 1, index + 1, index + x, index + x + 1 };if (index % x == (x - 1))return new int[5] { index - x - 1, index - x, index - 1, index + x - 1, index + x };if (index < x)return new int[5] { index - 1, index + 1, index + x - 1, index + x, index + x + 1 };if (index > x * (y - 1))return new int[5] { index - x - 1, index - x, index - x + 1, index - 1, index + 1 };return new int[8] { index - 1, index + 1, index - x, index-x-1,index-x+1,index + x,index+x-1,index+x+1 }; }效果如下
最后把工程附上
C#掃雷小游戲
總結(jié)
以上是生活随笔為你收集整理的【WPF】用100行C#代码实现扫雷的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【tkinter】用不到50行Pytho
- 下一篇: C#输入分数自动成绩评级