【基于.NET平台网络编程入门实战系列二】------让单机版的扫雷跑起来【附源码下载】

1/6/2010来源:ASP技巧人气:3340

今天的主要任务就是把单击版的搞定,这是过渡到网络版的必备过程。

如果没有玩过扫雷的,建议先去体验一下;体验完后,自己尝试写出扫雷的算法;经过思考揣摩推敲才能有收获。不建议一上来就下载源码剖析,跟踪代码!



现在我来说下我的思路,如果有更优雅的算法,欢迎大家分享------竞争引发技术进步,分享推动技术进步!



【一】单机版扫雷划为两层

第一层为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