想必每个人都玩过五子棋,其实对于我而言,五子棋是小时候玩的最多的棋类游戏,当然小时候也爱玩象棋以及国际象棋之类的,不过由于五子棋比较简单,所以就先实现一个简单的人机五子棋。最近我就在想如今学会了一点编程之后是不是应该把以前小时候特备爱玩的游戏实现一下,毕竟那是一种珍贵的回忆!
好了其他的不多说了,进入到我们的正题,首先呢,我准备分两次实现这个五子棋的内容,因为在制作好之后,个人感觉自己对于AI落子的算法的实现写得不够好,也思考了好久,感觉还是没有达到预期的效果,虽说最近放假了,但是学校又有事情,因此这次就简单地先把界面实现,以及把其中的一些游戏逻辑函数,游戏判断函数先贴出来,之后再仔细想一想如何实现AI的算法,使得AI更加智能化,能够提升游戏的乐趣,否则老是玩家赢的话,这样的游戏做出来是很失败的!
首先先简单地介绍一下,主要实现了以下几个函数:
//游戏函数 BOOL IsBlackOrWhite(); //随机生成,判断谁是黑子或者白子 //游戏中的检测函数 void ResetGame(); //重新开始资源清理 BOOL TimeOut(); //判断超时函数 BOOL Change_pos(); //将屏幕上的坐标转化为棋盘上的坐标 BOOL Change_y(); //与上面函数共同组成转化函数 BOOL IsHaveChess(PlayerChess &pCh); //判断要落点位置有无其他棋子(玩家) BOOL IsHaveChess(ComputerChess &cCh); //判断要落点位置有无其他棋子(电脑) void RegretPace(); //悔棋函数(只能悔棋三次) void Computer_play(); //电脑落子 BOOL CheckWin(); //判断玩家赢还是电脑赢
先在这里说明一下,其中电脑落子函数,以及判断输赢的函数这次感觉写的不够好,AI的算法还是很低级的,只要稍微会玩一下的玩家只要不大意根本输不了,因此这样的AI算法还是很失败的,因此准备再想一想一个更好地AI算法,不过哪怕自己再怎么想,终究还是敌不过人脑的!
这里进一步说明一下这几个函数,其中坐标转化函数的作用主要就是将鼠标点击的位置转化为棋盘上的规定位置,否则如果鼠标往哪点就会生成棋子的话,那么画面就一点也不整洁了。
还有一个判断超时的函数,一般来讲在网络上玩的这些棋类游戏都会有时间检测,用来判断其是否超时。在这次我是15秒如果没有落子的话就强制玩家落子,而落子的位置是根据此时你鼠标所在的位置最近的一个坐标点的位置。也不知道这样做好不好,不过个人感觉还是比强制随机落子的效果要好一些!
接下来就看一看内部的实现代码,由于代码全部给出的话太占篇幅了,因此我只给出有关游戏之中几个重要函数的代码,生成窗口这样的代码就不贴出来的,封装在了一个小小的游戏引擎之中!当然如果需要源代码的话,可以在后面留下邮箱或者私信我!
BOOL IsBlackOrWhite() //判断是黑子还是白子 { int result = 0; result = rand() % 2; if (0 == result) { return TRUE; } else { return FALSE; } } void ResetGame() //重新开始资源清理 { g_isinGame = FALSE; g_iBlackNum = 0; g_iWhiteNum = 0; if (IsBlackOrWhite()) { int i = 0; g_PlayerColor = BLACK; for (i = 0; i < CHESS_COUNT; i++) { pChess[i].color = BLACK; pChess[i].isExist = false; cChess[i].color = WHITE; cChess[i].isExist = false; } } else { int i = 0; g_PlayerColor = WHITE; for (i = 0; i < CHESS_COUNT; i++) { pChess[i].color = WHITE; pChess[i].isExist = false; cChess[i].color = BLACK; cChess[i].isExist = false; } } } BOOL TimeOut() //判断超时函数 { g_tNow = GetTickCount(); //判断是否为第一次落子 if (BLACK == g_PlayerColor) { if (g_iBlackNum == 0) { return FALSE; } } else { if (g_iWhiteNum == 0 && g_iBlackNum == 0) { return FALSE; } } if ((g_tNow - g_tPre > 20000)&&(g_isinGame == TRUE)) { return TRUE; } else { return FALSE; } } //判断要落点位置有无其他棋子 BOOL IsHaveChess(PlayerChess &pCh) { BOOL flag = FALSE; if (BLACK == g_PlayerColor) //先判断玩家棋子颜色 { for (int i = 0; i < g_iBlackNum; i++) { if ((pCh.x == pChess[i].x) && (pCh.y == pChess[i].y)) { flag = TRUE; } } for (int i = 0; i < g_iWhiteNum; i++) { if ((pCh.x == cChess[i].x) && (pCh.y == cChess[i].y)) { flag = TRUE; } } } else //玩家为白子的判断 { for (int i = 0; i < g_iWhiteNum; i++) { if ((pCh.x == pChess[i].x) && (pCh.y == pChess[i].y)) { flag = TRUE; } } for (int i = 0; i < g_iBlackNum; i++) { if ((pCh.x == cChess[i].x) && (pCh.y == cChess[i].y)) { flag = TRUE; } } } return flag; } BOOL IsHaveChess(ComputerChess &cCh) { BOOL flag = FALSE; if (BLACK == g_PlayerColor) //先判断玩家棋子颜色 { for (int i = 0; i < g_iBlackNum; i++) { if ((cCh.x == pChess[i].x) && (cCh.y == pChess[i].y)) { flag = TRUE; } } for (int i = 0; i < g_iWhiteNum; i++) { if ((cCh.x == cChess[i].x) && (cCh.y == cChess[i].y)) { flag = TRUE; } } } else //玩家为白子的判断 { for (int i = 0; i < g_iWhiteNum; i++) { if ((cCh.x == pChess[i].x) && (cCh.y == pChess[i].y)) { flag = TRUE; } } for (int i = 0; i < g_iBlackNum; i++) { if ((cCh.x == cChess[i].x) && (cCh.y == cChess[i].y)) { flag = TRUE; } } } return flag; } //悔棋函数(只能悔棋三次) void RegretPace() { if (BLACK == g_PlayerColor) //判断玩家棋子的颜色 { if (0 == g_iBlackNum) //玩家棋子颜色的个数,从而判断玩家是否可以悔棋 { MessageBeep(MB_ICONEXCLAMATION); //棋子数为0,无法悔棋,发出警告声 } else { pChess[g_iBlackNum - 1].isExist = FALSE; //清除该棋子 g_iBlackNum--; //黑棋个数减一 } } else { if (0 == g_iWhiteNum) //玩家棋子颜色的个数,从而判断玩家是否可以悔棋 { MessageBeep(MB_ICONEXCLAMATION); //棋子数为0,无法悔棋,发出警告声 } else { pChess[g_iWhiteNum - 1].isExist = FALSE; //清除该棋子 g_iWhiteNum--; //白棋个数减一 } } g_PaceCount--; }
当然这里面还是有几个函数比较占空间,但是都是一些很简单的操作,就没有给出来。更重要的就是里面还有电脑的算法没有一个更好地方案。在后续的文章之中肯定会对AI的算法有一定地深入了解,当然在这里为了测试的需要,我简单地给出了一个随机落子的方法。
//电脑落子 void Computer_play() { if (BLACK == g_PlayerColor) //通过判断玩家棋子颜色,从而知道电脑棋子的颜色 { for (int i = 0; i < CHESS_COUNT; i++) { if (!cChess[i].isExist) { while (true) { g_iX = rand() % 674; g_iY = rand() % 660 + 40; if (Change_pos()) { cChess[i].x = g_ichessX; cChess[i].y = g_ichessY; if (!IsHaveChess(cChess[i])) //判断新棋子要落子的位置有无其他棋子 { cChess[i].isExist = true; g_iWhiteNum++; break; } } } break; } } } else { for (int i = 0; i < CHESS_COUNT; i++) { if (!cChess[i].isExist) { while (true) { g_iX = rand() % 674; g_iY = rand() % 660 + 40; if (Change_pos()) { cChess[i].x = g_ichessX; cChess[i].y = g_ichessY; if (!IsHaveChess(cChess[i])) //判断新棋子要落子的位置有无其他棋子 { cChess[i].isExist = true; g_iBlackNum++; break; } } } break; } } } }
好了,由于这次没有实现这个游戏最核心的部分,AI的算法实现,因此这次就说到这,之后肯定会针对AI(人工智能)的算法给出实现,当然如果可以的话最好实现一个网络编程用来实现人人对战,当然这个可能实现起来比较难,不过AI的算法之后肯定会实现的!
最后来看一下截图,当然个人美工做的差,请不要见怪哦!
首先是最初的界面,当然这里由于时间原因,没有能够做多级页面,请大家见谅!
接下来来看一下运行过程之中的画面,不过需要点击开始按钮,否则游戏状态切换不过去!
当然这里的AI是自动随机落子的,所以看上去下的很没有规律。同时也可以进行悔棋以及认输功能,不过失败场数会加1。如下图:
最终总结一下,这只是一个最基本的五子棋,由于暂时还没有想到更好的AI算法,因此后续还会继续五子棋的编写,里面的AI算法在下一篇文章之中会给出来,暂时还在测试阶段。