基於C#—WPF的掃雷游戲


  自學教材:《C#入門經典(第六版)》,1月28日購入,1月29日到2月9日學習了前十六章,由於有C語言基礎,在語法階段學習起來比較輕松,不過在接觸到面向對象的時候遇到了一些困難,對於一些概念的理解着實費了一些功夫,不過最后還是成功的理解了。整個程序的設計從2月10日開始,在2月12日程序基本完成。2月13日將已知的BUG都清除完畢。

  掃雷很簡單。一個程序的核心就是數據結構與算法,我選擇的數據結構是二維數組,算法也很簡單,就是很簡單的利用bool屬性做標記以及翻牌的遞歸。

  首先是雷塊類的實現,因為翻開雷塊是利用單擊,所以我在雷塊類中繼承了Button基類,使它具有Button類的所有特性。同時定義了幾個bool屬性,分別表示是不是雷(IsMine),有沒有被翻開(IsOpened),有沒有被標記(IsFlagged)。還有int屬性代表周圍雷數(MineAround),最大的行列數(MaxRow、MaxColumn),不是雷的個數(MaxNoMineNum),以及翻開之后顯示的圖片背景back,代碼如下:

class Pane :Button
    {
        public Image back = new Image();
        public int MaxNoMineNum
        { get; set; }
        public int MaxRow
        { get; set; }
        public int MaxColumn
        { get; set; }
        public bool IsMine
        { get; set; }
        public int MineAround
        { get; set; }
        public bool IsFlagged
        { get; set; }
        public bool IsOpened
        { get; set; }
        public Pane(bool isMine)
        {
            IsMine = isMine;
            
        }
        
    }
Pane Class

  另外一個非常重要的類就是雷區類,為了方便,我將雷區做成了一個窗口,並根據用戶選擇難度的不同,向里面的Canvas控件動態加載我的雷塊“Button”,同時在上面實現了計時器和重新開始按鈕。

  根據難度不同,在初始化函數里定義了int形參Level,傳遞參數0為初級,1為中級,2為高級,分別按不同的雷數以及雷區大小初始化。初始化函數比較簡單故不將代碼列出。

  最重要的是單擊事件,每次單擊至少翻開一個雷塊,如果該雷塊周圍沒有雷(MineAround==0),則翻開他周圍的雷塊。這就要用到遞歸。同時應注意,一旦該雷塊被翻開之后就不應該再次翻開他。否則就會無限遞歸下去直到棧溢出拋出StackOverFlow異常。所以應該在單擊的事件處理程序中加入一個條件判斷,在沒有翻開(IsFlagged==false)的時候才執行。同時應注意邊界上的雷塊遞歸的處理,不能讓數組越界。具體代碼見下:

 

  1 private void PaneField_Click(object sender, RoutedEventArgs e)
  2         {
  3             if(IsTimerStart==false)
  4             {
  5                 IsTimerStart = true;
  6                 myTimer.Start();
  7             }
  8             if(IsWining()&&WiningJudge==true&&IsGameOver==false)
  9             {
 10                 IsGameOver = true;
 11                 WiningJudge = false;
 12                 for (int i = 0; i < paneField[0,0].MaxRow; i++)
 13                     for (int j = 0; j < paneField[0,0].MaxColumn; j++)
 14                     {
 15                         PaneField_Click(paneField[i, j], e);
 16                     }
 17                 System.Threading.Thread.Sleep(2000);
 18                 Wining w = new Wining();
 19                 w.Show();
 20                 System.Threading.Thread.Sleep(3000);
 21                 this.Close();
 22             }
 23              if (!Field.Children.Contains((sender as Pane).back))
 24             {
 25                 int Row, Column;
 26                 Pane t = (sender as Pane);
 27                 (sender as Pane).IsOpened = true;
 28                 Field.Children.Remove((UIElement)sender);
 29                 Field.Children.Add((sender as Pane).back);
 30                 if(t.IsMine==true && LosingJudge==true&&IsGameOver==false)
 31                 {
 32                     IsGameOver = true;
 33                     LosingJudge = false;
 34                     for(int i=0;i<t.MaxRow;i++)
 35                         for(int j=0;j<t.MaxColumn;j++)
 36                         {
 37                             
 38                             PaneField_Click(paneField[i, j], e);
 39                         }
 40                     Losing l = new Losing();
 41                     l.Show();
 42                     Thread.Sleep(3000);
 43                     this.Close();
 44                 }
 45                 //遞歸
 46                 if (t.MineAround == 0)
 47                 {
 48                     GetRowAndColumn(t, out Row, out Column, t.MaxRow, t.MaxColumn);
 49                     #region 四個角
 50                     if (Row == 0 && Column == 0 && t.IsMine == false) //左上角
 51                     {
 52                         PaneField_Click(paneField[0, 1], e);
 53                         PaneField_Click(paneField[1, 0], e);
 54                         PaneField_Click(paneField[1, 1], e);
 55                     }
 56                     else if (Row == 0 && Column == t.MaxColumn - 1 && t.IsMine == false) //右上角
 57                     {
 58                         PaneField_Click(paneField[0, t.MaxColumn - 2], e);
 59                         PaneField_Click(paneField[1, t.MaxColumn - 2], e);
 60                         PaneField_Click(paneField[1, t.MaxColumn - 1], e);
 61                     }
 62                     else if (Row == t.MaxRow - 1 && Column == 0 && t.IsMine == false) //左下角
 63                     {
 64                         PaneField_Click(paneField[t.MaxRow - 2, 0], e);
 65                         PaneField_Click(paneField[t.MaxRow - 2, 1], e);
 66                         PaneField_Click(paneField[t.MaxRow - 1, 1], e);
 67                     }
 68                     else if (Row == t.MaxRow - 1 && Column == t.MaxColumn - 1 && t.IsMine == false) //右下角
 69                     {
 70                         PaneField_Click(paneField[t.MaxRow - 2, t.MaxColumn - 2], e);
 71                         PaneField_Click(paneField[t.MaxRow - 2, t.MaxColumn - 1], e);
 72                         PaneField_Click(paneField[t.MaxRow - 1, t.MaxColumn - 2], e);
 73                     }
 74                     #endregion
 75                     #region 四條邊
 76                     else if (Row == 0 && Column != 0 && Column != t.MaxColumn - 1 && t.IsMine == false) //上邊
 77                     {
 78                         for (int p = Row; p <= Row + 1; p++)
 79                             for (int q = Column - 1; q <= Column + 1; q++)
 80                             {
 81                                 bool b = Field.Children.Contains(paneField[p, q].back);
 82                                 if (!(p == Row && q == Column) && b == false)
 83                                     PaneField_Click(paneField[p, q], e);
 84                             }
 85                     }
 86                     else if (Row == t.MaxRow - 1 && Column != 0 && Column != t.MaxColumn - 1 && t.IsMine == false) //下邊
 87                     {
 88                         for (int p = Row - 1; p <= Row; p++)
 89                             for (int q = Column - 1; q <= Column + 1; q++)
 90                             {
 91                                 bool b = Field.Children.Contains(paneField[p, q].back);
 92                                 if (!(p == Row && q == Column) && b == false)
 93                                     PaneField_Click(paneField[p, q], e);
 94                             }
 95                     }
 96                     else if (Column == 0 && Row != t.MaxRow - 1 && Row != 0 && t.IsMine == false) //左邊
 97                     {
 98                         for (int p = Row - 1; p <= Row + 1; p++)
 99                             for (int q = Column; q <= Column + 1; q++)
100                             {
101                                 bool b = Field.Children.Contains(paneField[p, q].back);
102                                 if (!(p == Row && q == Column) && b == false)
103                                     PaneField_Click(paneField[p, q], e);
104                             }
105                     }
106                     else if (Column == t.MaxColumn - 1 && Row != t.MaxRow - 1 && Row != 0 && t.IsMine == false) //右邊
107                     {
108                         for (int p = Row - 1; p <= Row + 1; p++)
109                             for (int q = Column - 1; q <= Column; q++)
110                             {
111                                 bool b = Field.Children.Contains(paneField[p, q].back);
112                                 if (!(p == Row && q == Column) && b == false)
113                                     PaneField_Click(paneField[p, q], e);
114                             }
115                     }
116                     #endregion
117                     #region 其他位置
118                     else if (t.IsMine == false)
119                         for (int p = Row - 1; p <= Row + 1; p++)
120                             for (int q = Column - 1; q <= Column + 1; q++)
121                             {
122                                 bool b = Field.Children.Contains(paneField[p, q].back);
123                                 if (!(p == Row && q == Column) && b == false)
124                                     PaneField_Click(paneField[p, q], e);
125                             }
126                     #endregion
127                 }
128             }
129         }
PaneField_Click

  其中的GetRowAndColumn方法在PaneField中定義,通過Pane對象的Equals方法來得到該元素在二維數組中的下標並利用out形參返回。IsWining方法也在類中定義為私有方法,通過統計翻開數與不是雷的個數是否相等來判斷是否勝利。
  至此,掃雷中比較復雜和重要的兩個類就介紹完畢了。其他的類or窗口(難度選擇,輸贏提示)都非常簡單,故不再贅述。通過編寫這個程序,讓我很好的應用了這十幾天學習的.Net知識,自己的編程功夫也有了一些長進。希望開學之后能夠繼續進步,取得更大的成就!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM