简单五子棋,没有电脑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 } 棋手类: