今天的主要任务就是把单击版的搞定,这是过渡到网络版的必备过程。
如果没有玩过扫雷的,建议先去体验一下;体验完后,自己尝试写出扫雷的算法;经过思考揣摩推敲才能有收获。不建议一上来就下载源码剖析,跟踪代码!
现在我来说下我的思路,如果有更优雅的算法,欢迎大家分享------竞争引发技术进步,分享推动技术进步!
【一】单机版扫雷划为两层
第一层为Button,Button盖在Lable上,Lable被隐藏在Button下面;
第二层为Lable, Lable上的背景图片改成地雷图案表示有雷。
雷区的大家我定为20*20.
private const int Xcount = 20;
private const int Ycount = 20;
添加Lable的代码如下:
代码
1 private Label[] labels2 = new Label[Xcount * Ycount];
2 private Label[,] labels = new Label[Xcount, Ycount];
3 int indexOfLable = 0;
4 private void CreateLable()
5 {
6 int[] ints = new int[400];
7 Random rd = new Random();
8 for (int i = 0; i < 400; i++)
9 {
10
11 ints[i] = rd.Next(1, 400);
12 }
13 for (int i = 0; i < Xcount; i++)
14 {
15 for (int j = 0; j < Ycount; j++)
16 {
17 Label lb = new Label();
18 lb.Location = new Point(i * 30, 30 * j);
19 lb.Size = new Size(30, 30);
20 lb.BorderStyle = BorderStyle.Fixed3D;
21 this.Controls.Add(lb);
22 labels[i, j] = lb;
23 labels2[indexOfLable] = lb;
24 indexOfLable++;
25 }
26 }
27 for (int i = 0; i < ints.Length; i++)
28 {
29 if (ints[i] < 40)
30 {
31 labels2[i].Image = Properties.Resources.标准地雷;
32 }
33 }
34 }
添加Button的代码如下:
代码
1 private Button[,] buttons = new Button[Xcount, Ycount];
2 private void AddButton()
3 {
4 for (int i = 0; i < Xcount; i++)
5 {
6 for (int j = 0; j < Ycount; j++)
7 {
8 Button btn = new Button();
9 btn.Click += new EventHandler(btn_Click);
10 //btn.Click +=new EventHandler(btn_MouseDown);
11 btn.MouseUp += new MouseEventHandler(btn_MouseUp);
12 btn.Location = new Point(i * 30, 30 * j);
13 btn.Size = new Size(30, 30);
14 this.Controls.Add(btn);
15 //利用Tag使按钮和坐标建立联系
16 Point pt = new Point(i, j);
17 btn.Tag = pt;
18 buttons[i, j] = btn;
19 }
20 }
21 }
实现按钮注册的事件,代码如下:
代码
1 void btn_MouseUp(object sender, MouseEventArgs e)
2 {
3 if (e.Button == MouseButtons.Right)
4 {
5 Button btn = (Button)sender;
6 if (btn.BackgroundImage == null)
7 {
8 btn.BackgroundImage = Properties.Resources.挖雷工兵;
9 }
10 else
11 {
12 btn.BackgroundImage = null;
13 }
14 }
15 }
16
17
18 void btn_Click(object sender, EventArgs e)
19 {
20 Button btn = (Button)sender;
21 this.Controls.Remove(btn);
22 Point pt = (Point)btn.Tag;
23 x = pt.X;
24 y = pt.Y;
25 if (labels[x, y].Image != null)
26 {
27 MessageBox.Show("游戏结束,果然是踩雷高手");
28 ReStart();
29 return;
30 }
31 CheckLable(x, y);
32 }
单击Button按钮判断在其下面的Lable上的图像是否为地雷,图像为空------递归寻找,图像不为空------游戏失败!
代码
1 void btn_Click(object sender, EventArgs e)
2 {
3 Button btn = (Button)sender;
4 this.Controls.Remove(btn);
5 Point pt = (Point)btn.Tag;
6 x = pt.X;
7 y = pt.Y;
8 if (labels[x, y].Image != null)
9 {
10 MessageBox.Show("游戏结束,果然是踩雷高手");
11 ReStart();
12 return;
13 }
14 CheckLable(x, y);
15 }
【二】单击的后果
这里是指左键的单击,右键的很简单,仅仅改变一下Button的背景图片而已,表示你任务下面有地雷。
左键单击后------1.移除被单击的按钮(大家都知道!)
1 void btn_Click(object sender, EventArgs e)
2 {
3 Button btn = (Button)sender;
4 this.Controls.Remove(btn);
5 }
------2.判断周围8格有没有雷,如果有---计算出有多少个,显示在lable上,并且自动判断周围的8格中没有地雷的单格的周围8格是否有地雷,一直递归下去!
如果没有---则移除周围8个button,并自动判断周围的8格的周围8格是否有地雷,一直递归下去!
上面两句虽然很绕口,但也是扫雷的核心算法。
【三】遍历周围8格
代码
1 private void CheckLable(int x, int y)
2 {
3 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
4 {
5 num = 0;
6 num = GetCount(x, y);
7 if (num == 8)
8 {
9 num = 0;
10 string tag = buttons[x, y].Tag.ToString();
11 buttons[x, y].Tag = 0;
12 if (labels[x, y].Image == null && tag != "0")
13 {
14 x++;
15 RemoveButton(x, y);
16 y++;
17 RemoveButton(x, y);
18 x--;
19 RemoveButton(x, y);
20 x--;
21 RemoveButton(x, y);
22 y--;
23 RemoveButton(x, y);
24 y--;
25 RemoveButton(x, y);
26 x++;
27 RemoveButton(x, y);
28 x++;
29 RemoveButton(x, y);
30 if (tag != "0")
31 {
32 num = 0;
33 Recursion(x, y);
34 }
35 }
36 }
37 else
38 {
39 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
40 {
41 labels[x, y].Text = (8 - num).ToString();
42
43 num = 0;
44 return;
45 }
46 }
47 }
48 }
【四】计算雷的个数
代码
1 private int GetCount(int x, int y)
2 {
3
4 temp2 = 0;
5 x++;
6 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
7 {
8 if (labels[x, y].Image == null)
9 {
10 temp2++;
11 }
12 }
13 else
14 { temp2++; }
15
16 y++;
17 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
18 {
19 if (labels[x, y].Image == null)
20 {
21 temp2++;
22 }
23 }
24 else
25 { temp2++; }
26
27 x--;
28 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
29 {
30 if (labels[x, y].Image == null)
31 {
32 temp2++;
33 }
34 }
35 else
36 { temp2++; }
37 x--;
38 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
39 {
40 if (labels[x, y].Image == null)
41 {
42 temp2++;
43 }
44 }
45 else
46 { temp2++; }
47 y--;
48 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
49 {
50 if (labels[x, y].Image == null)
51 {
52 temp2++;
53 }
54 }
55 else
56 { temp2++; }
57 y--;
58 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
59 {
60 if (labels[x, y].Image == null)
61 {
62 temp2++;
63 }
64 }
65 else
66 { temp2++; }
67 x++;
68 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
69 {
70 if (labels[x, y].Image == null)
71 {
72 temp2++;
73 }
74 }
75 else
76 { temp2++; }
77 x++;
78 if (x < Xcount && x >= 0 && y >= 0 && y < Ycount)
79 {
80 if (labels[x, y].Image == null)
81 {
82 temp2++;
83 }
84 }
85 else
86 { temp2++; }
87
88 return temp2;
89 }
【五】递归
代码
1 private void Recursion(int x, int y)
2 {
3 CheckLable(x, y);
4 y++;
5 CheckLable(x, y);
6 y++;
7 CheckLable(x, y);
8 x--;
9 CheckLable(x, y);
10 x--;
11 CheckLable(x, y);
12 y--;
13 CheckLable(x, y);
14 y--;
15 CheckLable(x, y);
16 x++;
17 CheckLable(x, y);
18
19 }
【六】重新来一盘
代码
1 public void ReStart()
2 {
3 this.Controls.Clear();
4 InitializeComponent();
5 temp2 = 0;
6 x = 0;
7 y = 0;
8 indexOfLable = 0;
9 num = 0;
10 AddButton();
11 CreateLable();
12 }
留两件事情给大家做,一改成用户控件,二给Lable添加双击事件(左右键一起按)!源码下载 ==> /Files/zhanglei644213943/单机版扫雷.rar