簡單五子棋,沒有電腦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 } 棋手類: