簡單五子棋,沒有電腦AI

  • 2019 年 10 月 10 日
  • 筆記

  剛學了C#委託,做了個五子棋練習,把前台繪製和後台邏輯分開,前台繪製方法用委託傳給後台邏輯。

介面好簡單。。。

先看類圖

控制類控制整個遊戲的邏輯,包括調用棋盤類的屬性初始化棋盤、初始化兩個棋手、輪流落子。棋盤裡有一個二維數組保存整個棋盤的落子情況,棋手裡也有一個二維數組保存自己的落子情況。方向類是為了方便判斷輸贏的。

下面是程式碼:注釋很詳細就不說明了:

主要控制類:

  1 using System;    2 using System.Collections.Generic;    3 using System.Drawing;    4 using 五子棋.Properties;    5    6 namespace 五子棋.Control    7 {    8     class Controler    9     {   10         #region 欄位   11         ///// <summary>   12         ///// 畫家對象   13         ///// </summary>   14         //Graphics g;   15         /// <summary>   16         /// 棋盤對象   17         /// </summary>   18         QiPan qipan;   19         /// <summary>   20         /// 棋手列表   21         /// </summary>   22         List<QiShou> qishou;   23         /// <summary>   24         /// 遊戲是否結束   25         /// </summary>   26         bool Gameover = false;   27         /// <summary>   28         /// 繪製直線委託   29         /// </summary>   30         Action<Point, Point> actionDrawLine;   31         /// <summary>   32         /// 繪製棋子影像委託   33         /// </summary>   34         Action<Image, int, int, float> actionDrawimage;   35         /// <summary>   36         /// 取得勝利事件,返回勝利選手的名稱   37         /// </summary>   38         Action<string> actionWin;   39         #endregion   40   41         #region 構造函數   42   43         /// <summary>   44         /// 構造函數   45         /// </summary>   46         /// <param name="actionDrawLine">繪製直線委託</param>   47         /// <param name="actionDrawimage">繪製棋子影像委託</param>   48         public Controler(Action< Point, Point> actionDrawLine, Action<Image, int, int, float> actionDrawimage,Action<string> actionWin)   49         {   50             //開始遊戲   51             this.actionDrawLine = actionDrawLine;   52             this.actionDrawimage = actionDrawimage;   53             this.actionWin = actionWin;   54             StartGame();   55         }   56         #endregion   57   58         #region 方法   59   60         /// <summary>   61         /// 棋手輪流下棋   62         /// </summary>   63         /// <param name="x">棋子X坐標</param>   64         /// <param name="y">棋子Y坐標</param>   65         public void LuoZi(int x, int y)   66         {   67             if (Gameover)   68             {   69                 return;   70             }   71             //把不在棋盤交點上的坐標換算到最接近的棋盤交點上   72   73             //x = (int)Math.Round((double)(x - qipan.start.X) / qipan.Grid)   74             //    * qipan.Grid + qipan.start.X;   75             //y = (int)Math.Round((double)(y - qipan.start.Y) / qipan.Grid)   76             //    * qipan.Grid + qipan.start.Y;   77             //換算到棋盤第幾條線   78             int qipanX = (int)Math.Round((double)(x - qipan.start.X) / qipan.Grid);   79             int qipanY = (int)Math.Round((double)(y - qipan.start.Y) / qipan.Grid);   80             if (qipan[qipanX, qipanY] == 0)   81             {   82                 for (int i = 0; i < qishou.Count; i++)   83                 {   84                     if (qishou[i].IsZouqi)   85                     {   86                         qipan[qipanX, qipanY] = 1;   87                         qishou[i].LuoZi(qipanX, qipanY);   88                         //換算到棋盤控制項坐標並繪製棋子   89                         qishou[i].Render(qipanX * qipan.Grid + qipan.start.X,   90                             qipanY * qipan.Grid + qipan.start.Y, actionDrawimage);   91   92                         //判斷當前玩家是否獲勝,獲勝則遊戲結束   93                         Gameover = IsWin(qishou[i], new Point(qipanX, qipanY));   94                         if (Gameover)   95                         {   96                             //if (actionWin!=null)   97                             //{   98                             //    actionWin.Invoke(qishou[i].PlayerName);   99                             //}  100                             actionWin?.Invoke(qishou[i].PlayerName);  101                         }  102  103                         //走棋後設置棋手不可走棋  104                         //qishou[i].LuoZi(x, y, g);  105                     }  106                     qishou[i].IsZouqi = !qishou[i].IsZouqi;  107                 }  108             }  109         }  110         /// <summary>  111         /// 刷新介面  112         /// </summary>  113         public void Render()  114         {  115             qipan.Render(actionDrawLine);  116             for (int i = 0; i < qishou.Count; i++)  117             {  118                 qishou[i].Render(qipan.start, qipan.Grid, actionDrawimage);  119             }  120         }  121         /// <summary>  122         /// 判斷是否獲勝  123         /// </summary>  124         /// <param name="qishou">棋手</param>  125         /// <param name="p">當前棋子坐標</param>  126         /// <returns></returns>  127         public bool IsWin(QiShou qishou, Point p)  128         {  129  130             //如果點在連續直線上就累加,當sum=5時,表示連續5個棋子在一條直線上  131             int sum = 1;  132             for (int i = 0; i < 8; i++)  133             {  134                 Console.WriteLine(i);  135                 //下一個要檢查的點  136                 Point nextP = p;  137                 Direction dr = (Direction)i;  138                 if (i % 2 == 0)  139                 {  140                     sum = 1;  141                 }  142                 for (int j = 0; j < 5; j++)  143                 {  144                     //根據當前方向判斷設置下一個點  145                     #region switch  146                     switch (dr)  147                     {  148                         case Direction.Top:  149                             nextP.X = nextP.X;  150                             nextP.Y = nextP.Y - 1;  151                             break;  152                         case Direction.RightTop:  153                             nextP.X = nextP.X + 1;  154                             nextP.Y = nextP.Y - 1;  155                             break;  156                         case Direction.Rigth:  157                             nextP.X = nextP.X + 1;  158                             nextP.Y = nextP.Y;  159                             break;  160                         case Direction.RigthBotton:  161                             nextP.X = nextP.X + 1;  162                             nextP.Y = nextP.Y + 1;  163                             break;  164                         case Direction.Botton:  165                             nextP.X = nextP.X;  166                             nextP.Y = nextP.Y + 1;  167                             break;  168                         case Direction.LeftBotton:  169                             nextP.X = nextP.X - 1;  170                             nextP.Y = nextP.Y + 1;  171                             break;  172                         case Direction.Left:  173                             nextP.X = nextP.X - 1;  174                             nextP.Y = nextP.Y;  175                             break;  176                         case Direction.LeftTop:  177                             nextP.X = nextP.X - 1;  178                             nextP.Y = nextP.Y - 1;  179                             break;  180                         default:  181                             break;  182                     }  183                     #endregion  184  185                     if (nextP.X >= 0 && nextP.X < qishou.ZouQiQiPan.GetLength(0)  186                         && nextP.Y >= 0 && nextP.Y < qishou.ZouQiQiPan.GetLength(1))  187                     {  188                         if (qishou.ZouQiQiPan[nextP.X, nextP.Y] == 0)  189                         {  190                             break;  191                         }  192                         else  193                         {  194                             sum += qishou.ZouQiQiPan[nextP.X, nextP.Y];  195                         }  196                     }  197                     else  198                     {  199                         break;  200                     }  201                 }  202                 if (sum == 5)  203                 {  204                     return true;  205                 }  206  207             }  208  209             return false;  210         }  211         /// <summary>  212         /// 開始遊戲  213         /// </summary>  214         public void StartGame()  215         {  216             Gameover = false;  217             //初始化棋盤  218             qipan = new QiPan();  219             //初始化兩種棋手:白棋和黑棋  220             qishou = new List<QiShou>()  221             {  222                 new QiShou(Resources.白棋,0.08f,new byte[qipan.Heigth/qipan.Grid+1,qipan.Width/qipan.Grid+1]) {IsZouqi=true,PlayerName="Bai" },  223  224                 new QiShou(Resources.黑棋,0.08f,new byte[qipan.Heigth/qipan.Grid+1,qipan.Width/qipan.Grid+1]) { IsZouqi=false,PlayerName="Hei" }  225             };  226             Render();  227         }  228         #endregion  229  230     }  231 }    棋手類: