亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#實現五子棋游戲

2019-10-29 21:06:36
字體:
來源:轉載
供稿:網友

曾經自學C#做計算機圖形學的作業,GDI+畫圖確實好用,目前在找.NET的實習,嘗試做了一個最基本的五子棋,復習一下C#的基本語法,目前只能當跟基友一起玩的單機小游戲,之后再加入AI和聯網對戰功能。目前我還是小菜鳥,過程設計和代碼有不合理或者能優化的地方歡迎各位大神指正。

首先是界面設計,最后就是這樣,控件一共有一個PictureBox;一個開始Button,命名為btnStart;一個重置Button,命名為btnReset;一個Label,用于顯示游戲狀態。

五子棋界面

C#,五子棋

然后是各基本類。新建一個MainSize類用于存放界面上的可能用到的參數,主框體大小520*460,棋盤是一個PictureBox控件,大小401*401,棋盤20行20列,每個格子邊長20,棋子直徑16。新建一個ChessBoard類表示棋盤,有一個靜態函數DrawBoard。之前做計算機圖形學作業畫函數時用到的畫坐標系方法在這里同樣適用,函數代碼如下。

class ChessBoard  {    static readonly Color color = Color.Black;    static readonly float penWid = 1.0f;    static readonly Pen pen = new Pen(color, penWid);        public static void DrawCB(Graphics gra,PictureBox pic)    {      //每排數量      int horC = MainSize.CBWid / MainSize.CBGap;      //間隔      int gap = MainSize.CBGap;      Image img = new Bitmap(MainSize.CBWid, MainSize.CBHei);      gra = Graphics.FromImage(img);      gra.Clear(Color.White);      gra.DrawRectangle(pen, 0, 0, MainSize.CBWid, MainSize.CBHei);      //畫棋盤      for (int i = 0; i < horC; i++)      {        gra.DrawLine(pen, 0, i * gap, MainSize.CBWid, i * gap);        gra.DrawLine(pen, i * gap, 0, i * gap, MainSize.CBHei);      }      gra.DrawLine(pen, 0, horC * gap, MainSize.CBWid, horC * gap - 1);      gra.DrawLine(pen, horC * gap - 1, 0, horC * gap, MainSize.CBHei);      pic.Image = img;    }  }

還有一個基本類Chess,用來表示棋子,有一個靜態函數DrawChess,代碼如下。這里代碼有點亂,寫的時候沒加注釋。bool型變量用于表示下棋的雙方,pen1和pen2用于繪制雙方的棋子,顏色設置為紅藍,因為自古紅藍出CP【其實是本來想用黑白的但picturebox背景白色再畫白色棋子就看不出來】。整型變量nexX和newY用于表示棋子在棋盤上的坐標,根據四舍五入就近原則落點。這里的四舍五入我花了很長時間,寫了很長的一段判斷代碼但都會出錯,最后借鑒了github上Xu Pu同學的數據結構假期作業中的方法才完成了這個函數,在此感謝這位同學~

 

class Chess  {    public static void DrawChess(bool type,PictureBox pic,Graphics graphic,MouseEventArgs e)    {      graphic = pic.CreateGraphics();      Pen pen1 = new Pen(Color.Red, 1);      Brush bru1 = new SolidBrush(Color.Red);      Pen pen2 = new Pen(Color.Blue, 1);      Brush bru2 = new SolidBrush(Color.Blue);      int newX = (int)((e.X + MainSize.CBGap / 2) / MainSize.CBGap) * MainSize.CBGap - MainSize.ChessRadious / 2;      int newY = (int)((e.Y + MainSize.CBGap / 2) / MainSize.CBGap) * MainSize.CBGap - MainSize.ChessRadious / 2;      if (type)      {        graphic.DrawEllipse(pen1, newX, newY, MainSize.ChessRadious, MainSize.ChessRadious);        graphic.FillEllipse(bru1, newX, newY, MainSize.ChessRadious, MainSize.ChessRadious);      }      if (!type)      {        graphic.DrawEllipse(pen2, newX, newY, MainSize.ChessRadious, MainSize.ChessRadious);        graphic.FillEllipse(bru2, newX, newY, MainSize.ChessRadious, MainSize.ChessRadious);      }      graphic.Dispose();    }  }

最后是主程序,一共設置了四個全局變量,Graphics graphic用于畫圖,bool type用于表示下棋雙方,bool start表示游戲是否開始,二維數組ChessBack用于模擬下棋場景并進行計算。

主程序的構造函數對主框體和PictureBox的大小進行初始化,在Form1_Load函數中添加函數InitializeThis()對游戲進行初始化,包括將ChessBack數組全部置0,type設為true,start設為false,繪制棋盤,按鍵開始的enabled屬性設為true,按鍵重置設為false。

按鍵開始和重置的功能較為簡單,代碼如下。

private void btnStart_Click(object sender, EventArgs e)    {      start = true;      label1.Text = "游戲開始!";      btnStart.Enabled = false;      btnReset.Enabled = true;    }    private void btnReset_Click(object sender, EventArgs e)    {      if (MessageBox.Show("確定要重新開始?", "提示", MessageBoxButtons.YesNo) == DialogResult.Yes)      {                      InitializeThis();      }    }

最重要的部分是點擊picturebox的函數,先判斷游戲是否開始,否則不會有反應。游戲開始后點擊即可落子,并修改ChessBack矩陣,紅色為1,藍色為2,如果已經有棋子則返回,即落子失敗。如果棋盤已滿但沒有分出勝負則彈出平局的提示框并給出提示。之后判斷是否分出勝負,添加函數bool Victory(int bx,int by),分出勝負后提示勝利,如果沒有則返回。最后換人,type=!type即可,然后修改label的文字表面到哪一方落子了。代碼如下。

 

private void pictureBox1_MouseClick(object sender, MouseEventArgs e)    {      if (start)      {        //在計算矩陣中的位置        int bX = (int)((e.X + MainSize.CBGap / 2) / MainSize.CBGap);        int bY = (int)((e.Y + MainSize.CBGap / 2) / MainSize.CBGap);        //防止在同一個位置落子        if (ChessBack[bX, bY] != 0)          return;        Chess.DrawChess(type, pictureBox1, graphic, e);        ChessBack[bX,bY] = type?1:2;        //判斷棋盤是否滿了        if (IsFull() && !Victory(bX,bY))        {          if (MessageBox.Show("游戲結束,平局") == DialogResult.OK)            InitializeThis();          return;        }        //判斷勝利        if (Victory(bX,bY))        {          string Vic = type ? "紅" : "藍";          if (MessageBox.Show(Vic + "方勝利!") == DialogResult.OK)            InitializeThis();          return;         }        //換人        type = !type;        label1.Text = type ? "紅方's trun!" : "藍方's turn!";      }      else        return;    }

判斷勝負的函數有點復雜,我自己是用遞歸的方式判斷,先寫了一個橫向的進行測試,如果橫向兩端的值與當前值相同則變量count++,最后返回count的值,如果>4則表示勝利。但是這個函數運行出錯,顯示為stackoverflow,但我不知道錯誤在哪,只好換一種判斷方法。后來才想明白兩端的值都是0則會溢出,應該判斷兩端的值是否為1或2而不是當前值。此處借鑒了實驗樓網站上的C語言版五子棋的判斷勝負方式,從當前落子的矩陣中,橫豎斜4個方向任意一個方向有連續5個數的值與當前的值相同則勝利,實現也不復雜,細分為三個函數實現。代碼如下。

 

#region 判斷勝利    private bool Victory(int bx,int by)    {      if (HorVic(bx, by))        return true;      if (VerVic(bx, by))        return true;      if (Vic45(bx, by))        return true;      else        return false;    }    private bool Vic45(int bx, int by)    {      int b1 = (bx - 4) > 0 ? bx - 4 : 0;      int b2 = (by - 4) > 0 ? by - 4 : 0;      //int buttom = b1 > b2 ? b2 : b1;      int val = ChessBack[bx, by];      for (int i = b1,j=b2; i < 16&&j<16; i++,j++)      {        if (ChessBack[i, j] == val && ChessBack[i + 1, j + 1] == val &&          ChessBack[i + 2, j + 2] == val && ChessBack[i + 3, j + 3] == val          && ChessBack[i + 4, j + 4] == val)          return true;      }      for (int i = b1, j = b2; i < 16 && j < 16; i++, j++)      {        if (ChessBack[i, j] == val && ChessBack[i + 1, j - 1] == val &&          ChessBack[i + 2, j - 2] == val && ChessBack[i + 3, j - 3] == val          && ChessBack[i - 4, j - 4] == val)          return true;      }      return false;    }    private bool VerVic(int bx, int by)    {      int buttom = (by - 4) > 0 ? by - 4 : 0;      int val = ChessBack[bx, by];      for (int i = buttom; i < 16; i++)      {        if (ChessBack[bx, i] == val && ChessBack[bx, i+1] == val &&          ChessBack[bx, i+2] == val && ChessBack[bx ,i+3] == val          && ChessBack[bx, i+4] == val)          return true;      }      return false;    }    private bool HorVic(int bx, int by)    {      int left = (bx-4)>0?bx-4:0;      int val = ChessBack[bx,by];      for (int i = left; i < 16; i++)      {        if (ChessBack[i, by] == val && ChessBack[i + 1, by] == val &&          ChessBack[i + 2, by] == val && ChessBack[i + 3, by] == val          && ChessBack[i + 4, by] == val)          return true;      }      return false;    }    #endregion

完成后進行測試,都沒有問題,即認為大功告成了。總結了一下編寫過程中問題,變量命名不太好,type,start等變量容易與關鍵詞混淆;主函數代碼行數還是太多,不方便閱讀,或許應該把判定勝負和判定棋盤是否已滿也移到棋盤類中;之后添加新游戲模式不方便,比如添加AI和聯機對戰,需要修改的代碼有點多,個人想法是分別新建一個帶AI的框體和聯機的框體,然后修改基本類,在這種情況下最大化的代碼復用。

回想一個這個小程序編寫并不復雜,但我花了很多時間在改錯上,落子的函數和判斷勝利的函數花的時間最多,事前用筆進行一下簡單的演算再寫或許能省一點時間。這是我的第一篇博客,暫時當實驗報告來寫吧,雖然是出于興趣做的,但還是希望各位大神能指出不足,給出建議,我會虛心學習的。最后再次感謝實驗樓網站【不是軟廣】和github上的Xu Pu同學,還有各位看到最后的朋友們~


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产午夜精品美女视频明星a级| 成人黄色免费在线观看| 久久精品成人动漫| 欧美激情网站在线观看| 亚洲精品一区中文字幕乱码| 一区二区国产精品视频| 国产精品久久久久久久久久免费| 日韩在线高清视频| 亚洲欧美激情在线视频| 亚洲乱码av中文一区二区| 国产精品h片在线播放| 欧美日韩第一视频| 久久久久久久久综合| 一本色道久久综合狠狠躁篇怎么玩| 日韩在线视频免费观看高清中文| 日韩视频免费中文字幕| 国产伦精品免费视频| 亚洲成人黄色在线| 成人免费网站在线| 亚洲级视频在线观看免费1级| 国产精品91视频| 亚洲va久久久噜噜噜| 久久精品视频在线播放| 国产精品福利在线观看网址| 久久精品视频在线| 亚洲高清不卡av| 亚洲变态欧美另类捆绑| 国产97在线视频| 国产精品福利网站| 欧洲亚洲免费在线| 午夜精品福利电影| 51色欧美片视频在线观看| 亚洲亚裔videos黑人hd| 国产精品免费看久久久香蕉| 国产69精品久久久久99| 日韩电影在线观看永久视频免费网站| 日韩视频免费在线观看| 国产精品香蕉国产| 国产精品高清免费在线观看| 色婷婷综合成人av| 国产午夜精品全部视频播放| 日本久久久久久久| 成人福利视频网| 精品一区二区亚洲| 一区二区三区美女xx视频| 成人性生交大片免费看视频直播| 久久久久久久国产精品| 欧美日韩在线视频观看| 亚洲综合一区二区不卡| 欧美成人免费观看| 在线亚洲午夜片av大片| 色婷婷亚洲mv天堂mv在影片| 韩国视频理论视频久久| 欧美猛少妇色xxxxx| 一区二区三区四区在线观看视频| 一本色道久久综合亚洲精品小说| 亚洲春色另类小说| 久久天天躁夜夜躁狠狠躁2022| 国产精品一区久久| 91免费综合在线| 日韩动漫免费观看电视剧高清| 国产精品国模在线| 色狠狠久久aa北条麻妃| 亚洲一区久久久| 亚洲韩国日本中文字幕| 久久99热精品这里久久精品| 久热精品在线视频| 国产精品视频专区| 国内偷自视频区视频综合| 91亚洲国产精品| 成人深夜直播免费观看| 欧美日韩国产成人在线观看| 欧美华人在线视频| 亚洲成人激情小说| 国产999在线| 欧美性xxxxxxx| 国产精品一区二区三| 国产欧美精品一区二区| 怡红院精品视频| 91精品久久久久久久久青青| 毛片精品免费在线观看| 亚洲最新视频在线| 国产日本欧美一区二区三区在线| 一区二区三区日韩在线| 日韩在线国产精品| 亚洲精品之草原avav久久| 精品久久香蕉国产线看观看gif| 亚洲影视九九影院在线观看| zzijzzij亚洲日本成熟少妇| 国产美女搞久久| 2019中文字幕在线免费观看| 久久国产色av| 国产色视频一区| 78m国产成人精品视频| xvideos国产精品| 日韩va亚洲va欧洲va国产| x99av成人免费| 久久久久久久亚洲精品| 91精品国产九九九久久久亚洲| 久久久久www| 午夜精品一区二区三区在线播放| 欧美成人午夜免费视在线看片| 欧美在线影院在线视频| 欧美日韩亚洲精品内裤| 2020久久国产精品| 亚洲电影在线看| 日韩一区二区三区国产| 91视频国产精品| 亚洲大胆美女视频| 日韩欧中文字幕| 日韩av在线播放资源| 日韩欧美成人免费视频| 国内精品久久影院| 久久久久久久久久久成人| 在线一区二区日韩| 日韩成人av网| 美女福利精品视频| 精品久久久久久中文字幕大豆网| 96sao精品视频在线观看| 国产精品美女久久久久av超清| 91精品国产网站| www.久久久久久.com| 亚洲free性xxxx护士hd| 日韩电视剧在线观看免费网站| 欧美日韩一区二区免费视频| 国产精品久久久久一区二区| 久久久久久噜噜噜久久久精品| 亚洲欧美日韩精品久久亚洲区| 亚洲免费av网址| 日韩中文字幕视频| 日本欧美黄网站| 国产久一一精品| 最近2019好看的中文字幕免费| 国产亚洲精品美女| 久久久久久69| 91av在线网站| 日本在线观看天堂男亚洲| 在线看欧美日韩| 欧美性xxxxhd| 亚洲精品视频二区| 亚洲国产精品国自产拍av秋霞| 欧美大片va欧美在线播放| 97国产真实伦对白精彩视频8| 日韩美女免费线视频| 欧美一级淫片videoshd| 国产视频精品久久久| 日韩一区二区久久久| 欧美激情va永久在线播放| 亚洲电影免费观看高清完整版| 欧美极品在线视频| 91精品国产高清久久久久久91| 亚洲97在线观看| 97精品在线观看| 97在线看免费观看视频在线观看| 亚洲视频第一页| 久久精品成人动漫| 欧洲亚洲女同hd| 欧美日韩精品在线播放| 精品国产精品自拍| 97在线观看免费高清| 国产丝袜视频一区| 国产亚洲精品一区二区| 亚洲欧美精品在线| 亚洲一区二区在线|