刚学了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 }
棋手类:
1 using System; 2 using System.Drawing; 3 4 namespace 五子棋.Control 5 { 6 class QiShou 7 { 8 #region 字段 9 /// <summary> 10 /// 棋子图像 11 /// </summary> 12 /// /// <summary> 13 /// 走棋棋盘 14 /// </summary> 15 byte[,] zouqiqipan; 16 #endregion 17 #region 属性 18 public string PlayerName { get; set; } 19 public Image ImagePlayer { get; set; } 20 /// <summary> 21 /// 棋子图像缩放比例 22 /// </summary> 23 public float ImageScale { get; set; } 24 25 /// <summary> 26 /// 走棋棋盘 27 /// </summary> 28 public byte[,] ZouQiQiPan 29 { 30 get 31 { 32 return zouqiqipan; 33 } 34 set 35 { 36 zouqiqipan = value; 37 } 38 } 39 /// <summary> 40 /// 是否可以走棋 41 /// </summary> 42 public bool IsZouqi { get; set; } 43 #endregion 44 /// <summary> 45 /// 构造函数 46 /// </summary> 47 /// <param name="image">棋子图像</param> 48 /// <param name="imagescale">棋子缩放比例</param> 49 /// /// <param name="zouqiqipan">走棋棋盘大小</param> 50 public QiShou(Image image, float imagescale, byte[,] zouqiqipan) 51 { 52 this.zouqiqipan = zouqiqipan; 53 ImagePlayer = image; 54 ImageScale = imagescale; 55 Init(); 56 } 57 /// <summary> 58 /// 初始化棋手 59 /// </summary> 60 private void Init() 61 { 62 for (int i = 0; i < zouqiqipan.GetLength(0); i++) 63 { 64 for (int j = 0; j < zouqiqipan.GetLength(1); j++) 65 { 66 zouqiqipan[i, j] = 0; 67 } 68 } 69 } 70 71 /// <summary> 72 /// 下棋落字 73 /// </summary> 74 /// <param name="x">棋盘X网格</param> 75 /// <param name="y">棋盘Y网格</param> 76 public void LuoZi(int x, int y) 77 { 78 ZouQiQiPan[x, y] = 1; 79 } 80 #region 绘制棋子 81 /// <summary> 82 /// 绘制所有棋子 83 /// </summary> 84 /// <param name="start"></param> 85 /// <param name="grid"></param> 86 public void Render(Point start, int grid,Action<Image, int,int,float> actionDrawImage) 87 { 88 for (int i = 0; i < ZouQiQiPan.GetLength(0); i++) 89 { 90 for (int j = 0; j < ZouQiQiPan.GetLength(1); j++) 91 { 92 if (zouqiqipan[i, j] == 1) 93 { 94 Render(i * grid + start.X, i * grid + start.Y,actionDrawImage); 95 96 } 97 } 98 } 99 } 100 public void Render(int x,int y, Action<Image, int, int, float> actionDrawImage) 101 { 102 actionDrawImage?.Invoke(ImagePlayer, x, y, ImageScale); 103 } 104 ///// <summary> 105 ///// 绘制棋子 106 ///// </summary> 107 ///// <param name="x">棋盘X网格坐标</param> 108 ///// <param name="y">棋盘Y网格坐标</param> 109 ///// <param name="g">画家对象</param> 110 //public void Render(int x, int y) 111 //{ 112 // //actionDrawimage(x, y, ImagePlayer, ImageScale); 113 114 115 // //绘制棋子,绘制的坐标应该换算到中心 116 // g.DrawImage(ImagePlayer, x - ImagePlayer.Width * ImageScale / 2, y - ImagePlayer.Height * ImageScale / 2, 117 // ImagePlayer.Width * ImageScale, ImagePlayer.Height * ImageScale); 118 //} 119 #endregion 120 121 122 } 123 124 }
棋盘类:
1 using System; 2 using System.Drawing; 3 4 namespace 五子棋.Control 5 { 6 class QiPan 7 { 8 9 /// <summary> 10 /// 棋盘绘制起点坐标 11 /// </summary> 12 public readonly Point start; 13 /// <summary> 14 /// X缩放 15 /// </summary> 16 public int ScaleX { get; set; } 17 /// <summary> 18 /// Y缩放 19 /// </summary> 20 public int ScaleY { get; set; } 21 /// <summary> 22 /// 棋盘宽度 23 /// </summary> 24 public int Width { get; set; } 25 /// <summary> 26 /// 棋盘高度 27 /// </summary> 28 public int Heigth { get; set; } 29 /// <summary> 30 /// 网格大小 31 /// </summary> 32 public int Grid { get; set; } 33 /// <summary> 34 /// 棋盘棋子 35 /// </summary> 36 private byte[,] qipanQiZi; 37 public byte this[int x, int y] 38 { 39 get 40 { 41 if (x < qipanQiZi.GetLength(0) && y < qipanQiZi.GetLength(1)) 42 { 43 return qipanQiZi[x, y]; 44 } 45 else 46 { 47 return 0; 48 } 49 } 50 set 51 { 52 if (x < qipanQiZi.GetLength(0) && y < qipanQiZi.GetLength(1)) 53 { 54 qipanQiZi[x, y] = value; 55 } 56 } 57 } 58 59 /// <summary> 60 /// 构造函数 61 /// </summary> 62 /// <param name="width">棋盘宽度</param> 63 /// <param name="height">棋盘高度</param> 64 /// <param name="grid">棋盘网格大小</param> 65 public QiPan(Point start, int width, int height, int grid) 66 { 67 this.start = start; 68 Width = width; 69 Heigth = height; 70 Grid = grid; 71 Init(); 72 73 } 74 75 private void Init() 76 { 77 qipanQiZi = new byte[Width / Grid + 1, Heigth / Grid + 1]; 78 for (int i = 0; i < qipanQiZi.GetLength(0); i++) 79 { 80 for (int j = 0; j < qipanQiZi.GetLength(1); j++) 81 { 82 qipanQiZi[i, j] = 0; 83 } 84 } 85 } 86 87 /// <summary> 88 /// 构造函数 89 /// 默认棋盘大小为400*400,方格大小为40 90 /// </summary> 91 public QiPan() : this(new Point(50, 50), 400, 400, 40) 92 { 93 } 94 #region Graphics绘制棋盘 95 96 97 /// <summary> 98 /// 绘制棋盘 99 /// </summary> 100 /// <param name="g"></param> 101 //public void Render(Graphics g) 102 //{ 103 // for (int i = 0; i <= Width / Grid; i++) 104 // { 105 // g.DrawLine(Pens.Black, start.X + (Grid * i), start.Y, start.X + (Grid * i), start.Y + Heigth); 106 107 // } 108 // for (int i = 0; i <= Heigth / Grid; i++) 109 // { 110 // g.DrawLine(Pens.Black, start.X, start.Y + (Grid * i), start.X + Width, start.Y + (Grid * i)); 111 // } 112 //} 113 #endregion 114 public void Render(Action< Point, Point> actionDrawLine) 115 { 116 int row = Heigth / Grid + 1; 117 int cel = Width / Grid + 1; 118 for (int i = 0; i < row; i++) 119 { 120 actionDrawLine?.Invoke( new Point(start.X, start.Y + Grid * i), new Point(start.X + Width, start.Y + Grid * i)); 121 } 122 for (int i = 0; i < cel; i++) 123 { 124 actionDrawLine?.Invoke( new Point(start.X + Grid * i, start.Y), new Point(start.X + Grid * i, start.Y + Heigth)); 125 } 126 } 127 } 128 }