五子棋C++版
当前只完成了单机人人对战 后续会完成联机和AI的实现
定义棋盘
typedef struct { int kind; }Map; //棋盘 0为无子 1为黑子 2为白子 Map maps[line_number + 1][line_number + 1]; //定义棋盘
定义棋子
typedef struct { int x; int y; int kind; }Record; //记录每一步棋的坐标 int point_x, point_y; //落子点的坐标 int kind_chess; //1为黑子 2为白子
1 void Startup() 2 { 3 4 //当前棋盘没有落子 kind全部置为0; 5 for (int i = 1; i <= line_number; i++) 6 { 7 for (int j = 1; j <= line_number; j++) 8 { 9 maps[i][j].kind = 0; 10 } 11 } 12 //各种参数初始化 13 flag_leftmouse = 0; 14 number = 0; 15 kind_chess = 1; 16 step = width / (line_number + 1); 17 radius = step /2 - 1; 18 initgraph(width, heigh); 19 //设置背景颜色 20 setbkcolor(RGB(249, 214, 91)); 21 cleardevice(); 22 23 setlinecolor(BLACK); 24 setlinestyle(PS_SOLID, 1); 25 // 画出棋盘横竖各line_number条交错的直线 26 for (int i = 1; i <= line_number; i++) 27 { 28 line(i*step, 1 * step, i*step, line_number * step); 29 line(1 * step, i*step, line_number * step, i*step); 30 } 31 button_left = step; 32 button_right = step * 4; 33 button_top = (line_number + 1)*step - step / 2; 34 button_bottom = heigh - step / 2; 35 //画出悔棋键 36 settextcolor(BLACK); 37 settextstyle(step*2-step/2, step - step/4, _T("宋体")); 38 outtextxy(button_left, button_top , _T("悔棋")); 39 //画出认输键 40 settextstyle(step * 2 - step / 2, step - step / 4, _T("宋体")); 41 outtextxy(button_left+4*step, button_top, _T("认输")); 42 }
1 //判断落子后是否胜利 即五连子 x,y,kind 分别为行数,列数,棋子的颜色 2 int IsVictory(int x, int y, int kind) 3 { 4 //判断一列上是否有五连子 5 int i = x; 6 int j = y; 7 int count = 0; 8 while (i >= 1 && maps[i][j].kind == kind) 9 { 10 i--; 11 count++; 12 } 13 i = x + 1; 14 while (i <= 19 && maps[i][j].kind == kind) 15 { 16 i++; 17 count++; 18 } 19 if (count == 5) return kind; 20 //判断一行上是否有五连子 21 i = x; 22 count = 0; 23 while (j >= 1 && maps[i][j].kind == kind) 24 { 25 j--; 26 count++; 27 } 28 j = y + 1; 29 while (j <= 19 && maps[i][j].kind == kind) 30 { 31 j++; 32 count++; 33 } 34 if (count == 5) return kind; 35 //判断左斜方向是否有五连子 36 i = x; 37 j = y; 38 count = 0; 39 while (i >= 1 && j >= 1 && maps[i][j].kind == kind) 40 { 41 j--; 42 i--; 43 count++; 44 } 45 i = x + 1; 46 j = y + 1; 47 while (j <= 19 && i <= 19 && maps[i][j].kind == kind) 48 { 49 j++; 50 i++; 51 count++; 52 } 53 if (count == 5) return kind; 54 //判断右斜方向是否有五连子 55 i = x; 56 j = y; 57 count = 0; 58 while (i <= 19 && j >= 1 && maps[i][j].kind == kind) 59 { 60 j--; 61 i++; 62 count++; 63 } 64 i = x - 1; 65 j = y + 1; 66 while (j <= 19 && i >= 1 && maps[i][j].kind == kind) 67 { 68 j++; 69 i--; 70 count++; 71 } 72 if (count == 5) return kind; 73 return 0; 74 }
1 if (kind_chess == 1 && maps[point_y / (step)][point_x / step].kind == 0) //当前落子位置满足条件 2 { 3 //记录落子点 用于悔棋键 4 number++; 5 records[number].x = point_y / step; 6 records[number].y = point_x / step; 7 records[number].kind = 1; 8 9 //绘图 覆盖 10 setfillcolor(BLACK); 11 solidcircle(point_x, point_y, radius); 12 maps[point_y / step][point_x / step].kind = 1; 13 kind_chess = 2; 14 if (IsVictory(point_y / step, point_x / step, 1) == 1) 15 { 16 17 settextcolor(BLACK); 18 settextstyle(48, 0, _T("宋体")); 19 outtextxy(width / 2 - 60, heigh / 2, _T("黑方胜")); 20 system("pause"); 21 goto L1; 22 } 23 }
1 // 五子棋.cpp: 定义控制台应用程序的入口点。 2 3 //头文件区 4 #include "stdafx.h" 5 #include <graphics.h> 6 #include <conio.h> 7 8 //宏定义区 9 #define width 640 10 #define heigh 700 //定义窗口的长和宽 11 #define line_number 15 //定义棋盘的条数 横竖各line_number条线 12 13 //结构体定义区 14 typedef struct 15 { 16 int kind; 17 }Map; //棋盘 0为无子 1为黑子 2为白子 18 typedef struct 19 { 20 int x; 21 int y; 22 int kind; 23 }Record; //记录每一步棋的坐标 24 typedef struct { 25 int x; 26 int y; 27 }Point; //记录最佳点的坐标 28 29 //全局变量区 30 MOUSEMSG m; 31 int flag_leftmouse ; //标志是否按下左键 32 int point_x, point_y; //落子点的坐标 33 Map maps[line_number + 1][line_number + 1]; //定义棋盘 34 Record records[line_number * line_number + 1]; //记录每一步落子的坐标 35 int kind_chess; //1为黑子 2为白子 36 int step ; //棋盘线与线之间的间距 37 int radius; //棋子半径 38 int number; //当前总落子数 39 40 int button_left; //按钮的上下左右界 41 int button_right; 42 int button_top; 43 int button_bottom; 44 45 //初始化 46 void Startup() 47 { 48 49 //当前棋盘没有落子 kind全部置为0; 50 for (int i = 1; i <= line_number; i++) 51 { 52 for (int j = 1; j <= line_number; j++) 53 { 54 maps[i][j].kind = 0; 55 } 56 } 57 //各种参数初始化 58 flag_leftmouse = 0; 59 number = 0; 60 kind_chess = 1; 61 step = width / (line_number + 1); 62 radius = step /2 - 1; 63 initgraph(width, heigh); 64 //设置背景颜色 65 setbkcolor(RGB(249, 214, 91)); 66 cleardevice(); 67 68 setlinecolor(BLACK); 69 setlinestyle(PS_SOLID, 1); 70 // 画出棋盘横竖各line_number条交错的直线 71 for (int i = 1; i <= line_number; i++) 72 { 73 line(i*step, 1 * step, i*step, line_number * step); 74 line(1 * step, i*step, line_number * step, i*step); 75 } 76 button_left = step; 77 button_right = step * 4; 78 button_top = (line_number + 1)*step - step / 2; 79 button_bottom = heigh - step / 2; 80 //画出悔棋键 81 settextcolor(BLACK); 82 settextstyle(step*2-step/2, step - step/4, _T("宋体")); 83 outtextxy(button_left, button_top , _T("悔棋")); 84 //画出认输键 85 settextstyle(step * 2 - step / 2, step - step / 4, _T("宋体")); 86 outtextxy(button_left+4*step, button_top, _T("认输")); 87 } 88 89 //判断落子后是否胜利 即五连子 x,y,kind 分别为行数,列数,棋子的颜色 90 int IsVictory(int x, int y, int kind) 91 { 92 //判断一列上是否有五连子 93 int i = x; 94 int j = y; 95 int count = 0; 96 while (i >= 1 && maps[i][j].kind == kind) 97 { 98 i--; 99 count++; 100 } 101 i = x + 1; 102 while (i <= 19 && maps[i][j].kind == kind) 103 { 104 i++; 105 count++; 106 } 107 if (count == 5) return kind; 108 //判断一行上是否有五连子 109 i = x; 110 count = 0; 111 while (j >= 1 && maps[i][j].kind == kind) 112 { 113 j--; 114 count++; 115 } 116 j = y + 1; 117 while (j <= 19 && maps[i][j].kind == kind) 118 { 119 j++; 120 count++; 121 } 122 if (count == 5) return kind; 123 //判断左斜方向是否有五连子 124 i = x; 125 j = y; 126 count = 0; 127 while (i >= 1 && j >= 1 && maps[i][j].kind == kind) 128 { 129 j--; 130 i--; 131 count++; 132 } 133 i = x + 1; 134 j = y + 1; 135 while (j <= 19 && i <= 19 && maps[i][j].kind == kind) 136 { 137 j++; 138 i++; 139 count++; 140 } 141 if (count == 5) return kind; 142 //判断右斜方向是否有五连子 143 i = x; 144 j = y; 145 count = 0; 146 while (i <= 19 && j >= 1 && maps[i][j].kind == kind) 147 { 148 j--; 149 i++; 150 count++; 151 } 152 i = x - 1; 153 j = y + 1; 154 while (j <= 19 && i >= 1 && maps[i][j].kind == kind) 155 { 156 j++; 157 i--; 158 count++; 159 } 160 if (count == 5) return kind; 161 return 0; 162 } 163 164 //AI落子 165 /*void dropChessAt(Point p) 166 { 167 number++; 168 records[number].x = p.x; 169 records[number].y = p.y; 170 records[number].kind = 2; 171 172 setfillcolor(WHITE); 173 solidcircle(p.y * step, p.x*step, radius); 174 maps[p.x][p.y].kind = 2; 175 kind_chess = 1; 176 if (IsVictory( p.x, p.y, 2) == 2) 177 { 178 settextcolor(WHITE); 179 settextstyle(48, 0, _T("宋体")); 180 outtextxy(width / 2 - 60, heigh / 2, _T("白方胜")); 181 system("pause"); 182 } 183 }*/ 184 185 //其中p为当前点,i为方向,取值为从1到8的整数,对应8个方向, 186 //j为相对于p点的坐标值。在函数体内要依据方向对p的x、y的值进行处理。返回该点的落子 187 //情况,0表示无子,1或2分别表示两个player,-1表示超出棋盘界。 188 /*int getLine(Point p, int i, int j) 189 { 190 int x = p.x, y = p.y; 191 switch (i) 192 { 193 case 1: 194 x = x - j; break; //上 195 case 2: 196 x = x + j; break; //下 197 case 3: 198 y = y - j; break; //左 199 case 4: 200 y = y + j; break; //右 201 case 5: 202 y = y + j; x = x - i; break; //右上 203 case 6: 204 y = y - j; x = x - i; break; //左上 205 case 7: 206 y = y + j; x = x + i; break; //右下 207 case 8: 208 y = y - j; x = x + i; break; //左下 209 default: 210 break; 211 } 212 if (x<1 || y<1 || x>line_number || y>line_number) return -1; 213 return maps[x][y].kind; 214 }*/ 215 216 217 //估值函数(核心) 218 /*int envaluate(Point p, int kind) 219 { 220 Point dir[8]; 221 dir[0].x = -1; dir[0].y = 0; //上 222 //dir[1].x = 1; dir[1].y = 0; //下 223 //dir[2].x = 0; dir[2].y = -1; //左 224 dir[1].x = 0; dir[1].y = 1; //右 225 dir[2].x = -1; dir[2].y = -1; //左上 226 dir[3].x = -1; dir[3].y = 1; //右上 227 //dir[6].x = 1; dir[6].y = -1; //左下 228 //dir[7].x = 1; dir[7].y = 1; //右下 229 int value = 0; 230 //敌对方是谁 231 int opposite; 232 if (kind == 1)opposite = 2; 233 if (kind == 2)opposite = 1; 234 for (int i = 0; i < 4; i++) 235 { 236 237 } 238 239 }*/ 240 241 //轮到AI的回合 242 /*void IsTimeToAI() 243 { 244 Point bestAttack; //最佳进攻点 245 Point bestDefend; //最佳防守点 246 247 int max1 = 0; 248 //循环遍历整个棋盘 249 for (int i = 1; i <= line_number; i++) 250 { 251 for (int j = 1; j <= line_number; j++) 252 { 253 if (maps[i][j].kind != 0) continue; 254 //当前点 255 Point c; 256 c.x = i; 257 c.y = j; 258 int value = envaluate(c, 2); 259 //int value = Evaluate(c); 260 if (max1 < value) 261 { 262 max1 = value; 263 bestAttack = c; 264 } 265 } 266 } 267 int max2 = 0; 268 for (int i = 1; i <= line_number; i++) 269 { 270 for (int j = 1; j <= line_number; j++) 271 { 272 if (maps[i][j].kind != 0) continue; 273 Point c; 274 c.x = i; 275 c.y = j; 276 int value = envaluate(c, 1); 277 //int value = Evaluate(c); 278 if (max2 < value) 279 { 280 max2 = value; 281 bestDefend = c; 282 } 283 } 284 } 285 286 if (max1 >= max2) 287 { 288 dropChessAt(bestAttack); 289 } 290 else { 291 dropChessAt(bestDefend); 292 } 293 }*/ 294 295 //游戏开始 296 void ConsoleGame() 297 { 298 L1: 299 //初始化 300 Startup(); 301 //主循环 302 while (1) 303 { 304 if (MouseHit()) 305 { 306 m = GetMouseMsg(); 307 if (m.mkLButton == true ) //按下鼠标左键时 308 { 309 flag_leftmouse = 1; 310 } 311 if (m.mkLButton == false && flag_leftmouse==1) //当松开鼠标左键后开 312 { 313 //鼠标按键范围在棋盘内时 314 if (m.x >= step - radius && m.x <= (width - (step - radius)) && m.y >= step - radius && m.y <= (width - (step - radius))) 315 { 316 if (m.x % step < step / 2) 317 { 318 point_x = m.x - m.x % step; 319 } 320 if (m.x % step > step / 2) 321 { 322 point_x = m.x + (step - m.x % (step)); 323 } 324 if (m.y % step < step / 2) 325 { 326 point_y = m.y - m.y % step; 327 } 328 if (m.y % step > step / 2) 329 { 330 point_y = m.y + (step - m.y % step); 331 } 332 if (kind_chess == 1 && maps[point_y / (step)][point_x / step].kind == 0) 333 { 334 number++; 335 records[number].x = point_y / step; 336 records[number].y = point_x / step; 337 records[number].kind = 1; 338 339 setfillcolor(BLACK); 340 solidcircle(point_x, point_y, radius); 341 maps[point_y / step][point_x / step].kind = 1; 342 kind_chess = 2; 343 if (IsVictory(point_y / step, point_x / step, 1) == 1) 344 { 345 346 settextcolor(BLACK); 347 settextstyle(48, 0, _T("宋体")); 348 outtextxy(width / 2 - 60, heigh / 2, _T("黑方胜")); 349 system("pause"); 350 goto L1; 351 } 352 } 353 //人人对战时的后手方落子 354 else if (kind_chess == 2 && maps[point_y / step][point_x / step].kind == 0) 355 { 356 357 number++; 358 records[number].x = point_y / step; 359 records[number].y = point_x / step; 360 records[number].kind = 2; 361 362 setfillcolor(WHITE); 363 solidcircle(point_x, point_y, radius); 364 maps[point_y / step][point_x / step].kind = 2; 365 kind_chess = 1; 366 if (IsVictory(point_y / step, point_x / step, 2) == 2) 367 { 368 settextcolor(WHITE); 369 settextstyle(48, 0, _T("宋体")); 370 outtextxy(width / 2 - 60, heigh / 2, _T("白方胜")); 371 system("pause"); 372 goto L1; 373 } 374 } 375 } 376 //鼠标按键范围在悔棋键范围内时 377 if (m.x >= button_left && m.x <=button_right &&m.y >=button_top &&m.y <=button_bottom) 378 { 379 if (number >= 1) 380 { 381 int x = records[number].x; 382 int y = records[number].y; 383 kind_chess = records[number].kind; 384 setfillcolor(RGB(249, 214, 91)); 385 solidcircle(y * step, x * step, radius); 386 setlinecolor(BLACK); 387 if (x == 1 && y ==1) 388 { 389 line(y*step, x*step , y*step, x*step + radius); 390 line(y*step , x*step, y*step + radius, x*step); 391 } 392 else if (y == 1 && (x > 1 && x < line_number)) 393 { 394 line(y*step, x*step-radius, y*step, x*step + radius); 395 line(y*step, x*step, y*step + radius, x*step); 396 } 397 else if (y == 1 && x == line_number) 398 { 399 line(y*step, x*step - radius, y*step, x*step); 400 line(y*step, x*step, y*step + radius, x*step); 401 } 402 else if (x == 1 && y > 1 && y < line_number) 403 { 404 line(y*step, x*step, y*step, x*step+radius); 405 line(y*step-radius, x*step, y*step+radius , x*step); 406 } 407 else if (x == 1 && y == line_number) 408 { 409 line(y*step, x*step , y*step, x*step+radius); 410 line(y*step - radius, x*step , y*step, x*step); 411 } 412 else if (y == line_number && x > 1 && x < line_number) 413 { 414 line(y*step, x*step - radius, y*step, x*step+radius); 415 line(y*step-radius, x*step, y*step , x*step); 416 } 417 else if (y == line_number && x == line_number) 418 { 419 line(y*step, x*step - radius, y*step, x*step); 420 line(y*step - radius, x*step, y*step, x*step); 421 } 422 else if (x == line_number && y > 1 && y < line_number) 423 { 424 line(y*step, x*step - radius, y*step, x*step ); 425 line(y*step - radius, x*step, y*step+radius, x*step); 426 } 427 else 428 { 429 line(y*step, x*step - radius, y*step, x*step + radius); 430 line(y*step - radius, x*step, y*step + radius, x*step); 431 } 432 maps[x][y].kind = 0; 433 number--; 434 } 435 } 436 //鼠标按键范围在认输键范围内时 437 else if (m.x >= button_left + 4 * step && m.x <= button_right + 4 * step && m.y >= button_top && m.y <= button_bottom) 438 { 439 if (kind_chess == 1) 440 { 441 settextcolor(BLACK); 442 settextstyle(48, 0, _T("宋体")); 443 outtextxy(width / 2 - 60, heigh / 2, _T("白方胜")); 444 system("pause"); 445 goto L1; 446 } 447 else 448 { 449 settextcolor(BLACK); 450 settextstyle(48, 0, _T("宋体")); 451 outtextxy(width / 2 - 60, heigh / 2, _T("黑方胜")); 452 system("pause"); 453 goto L1; 454 } 455 } 456 flag_leftmouse = 0; 457 } 458 } 459 /*if (kind_chess == 2) 460 { 461 //Sleep(40); 462 //IsTimeToAI(); 463 }*/ 464 } 465 _getch(); 466 } 467 468 469 int main() 470 { 471 ConsoleGame(); 472 }