今天的主要任務就是把單擊版的搞定,這是過渡到網絡版的必備過程。
如果沒有玩過掃雷的,建議先去體驗一下;體驗完後,自己嘗試寫出掃雷的算法;經過思考揣摩推敲才能有收獲。不建議一上來就下載源碼剖析,跟蹤代碼!
現在我來說下我的思路,如果有更優雅的算法,歡迎大家分享------競爭引發技術進步,分享推動技術進步!
【一】單機版掃雷劃為兩層
第一層為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添加雙擊事件(左右鍵一起按)!