100行C#代碼實(shí)現(xiàn)經(jīng)典掃雷游戲
布局
布局效果如下,下面每個(gè)“網(wǎng)格”都是一個(gè)按鈕,點(diǎn)擊按鈕,就會(huì)有相應(yīng)的事件發(fā)生。

由于UniformGrid中每個(gè)Grid的尺寸相等,所以作為雷區(qū)的容器。
<DockPanel>
<DockPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="5"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="5"/>
<Setter Property="InputMethod.IsInputMethodEnabled" Value="False"/>
</Style>
</DockPanel.Resources>
<ToolBar DockPanel.Dock="Top">
<TextBlock Text="雷區(qū)尺寸"/>
<TextBox Width="40" Text="20" x:Name="txtNumX"/>
<TextBlock Text="×"/>
<TextBox Width="40" Text="20" x:Name="txtNumY"/>
<TextBlock Text="雷數(shù)"/>
<TextBox Width="40" Text="20" x:Name="txtNumMine"/>
<Button Content="??" Click="btnNewGame_Click"/>
</ToolBar>
<UniformGrid Name="ugMine">
</UniformGrid>
生成雷區(qū)
值得一提的是,由于隨機(jī)數(shù)可能在生成過(guò)程中產(chǎn)生重復(fù)的值,所以這里通過(guò)概率的方式來(lái)生成雷。
假設(shè)按鈕數(shù)為N,雷數(shù)為n,那么在][0,N]之間隨機(jī)生成一個(gè)數(shù)x,如果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)記,則卸載左鍵的功能
else
btn.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;
else
foreach (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 };
}效果如下

以上就是100行C#代碼實(shí)現(xiàn)經(jīng)典掃雷游戲的詳細(xì)內(nèi)容,更多關(guān)于C#掃雷游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#檢查指定對(duì)象是否存在于ArrayList集合中的方法
這篇文章主要介紹了C#檢查指定對(duì)象是否存在于ArrayList集合中的方法,涉及C#中Contains方法的使用技巧,需要的朋友可以參考下2015-04-04
C#/VB.NET實(shí)現(xiàn)在Word文檔中添加頁(yè)眉和頁(yè)腳
頁(yè)眉位于文檔中每個(gè)頁(yè)面的頂部區(qū)域,常用于顯示文檔的附加信息;頁(yè)腳位于文檔中每個(gè)頁(yè)面的底部的區(qū)域,常用于顯示文檔的附加信息。今天這篇文章就將為大家展示如何以編程的方式在在?Word?文檔中添加頁(yè)眉和頁(yè)腳2023-03-03
C# MJPEG 客戶端簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要介紹了C# MJPEG 客戶端簡(jiǎn)單實(shí)現(xiàn)的方法,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03
C# ping網(wǎng)絡(luò)IP 實(shí)現(xiàn)網(wǎng)絡(luò)狀態(tài)檢測(cè)的方法
下面小編就為大家?guī)?lái)一篇C# ping網(wǎng)絡(luò)IP 實(shí)現(xiàn)網(wǎng)絡(luò)狀態(tài)檢測(cè)的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
C# winform編程中響應(yīng)回車鍵的實(shí)現(xiàn)代碼
這篇文章主要介紹了C# winform編程中響應(yīng)回車鍵的實(shí)現(xiàn)代碼,既在窗口上響應(yīng)回車鍵事件的方法,需要的朋友可以參考下2014-08-08

