QT vs2017《五子棋》人机对战项目
Posted cpp_learners
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT vs2017《五子棋》人机对战项目相关的知识,希望对你有一定的参考价值。
一年了。一年前,自己学习qt语言时,顺便写了一个五子棋的小项目,个人感觉,这个五子棋项目还算挺大型的,整个项目代码量加起来可能有1w行,现在分享出来给有需要的朋友,参考借鉴。
项目包括实现功能:背景音乐、悔棋、链接MySQL进行存档和读档操作、删库跑路(也就是删除所有存档)、最小化系统托盘、游戏声音调节、人机对战算法等!
一、游戏截图
下面是游戏截图:
GIF演示:
麻雀虽小五脏俱全!
二、项目代码
这是项目文件:
项目源码代码:
https://download.csdn.net/download/cpp_learner/76123482
需要自己创建一个名为gobang的数据库,并创建表gather_table_name
创建表mysql语句:create table gather_table_name(id int PRIMARY KEY AUTO_INCREMENT, table_name varchar(128) NOT NULL, save_time timestamp NOT NULL);
gather_table_name表存储的是所有存档的档名,通过这些档名就可以获取对应存档的表名,就可以读取里面的数据了。
创建好后,再修改代码中自己的数据库账户和密码即可连接成功,就可以实现存档和读档的功能了!
三、项目大致讲解
1. Qt_Gobang类
这是主窗体类!用于下棋的,判断“五子连珠”也是在这里实现的!
“五子连珠”的判断思路:
我们的棋盘每个下棋点都是有固定的坐标的,且每个点间隔50像素。
所以,当鼠标点击时,获取该点的坐标,从此位置开始向左、向右、向上、向下、向左上、向右下、向右上、向右下进行统计是否有五个相同的棋子,
有即使“五子连珠”,可以结束棋盘了!
例如:
如图2-4,从中间空着这那个点开始统计,假设我们即将要将黑色的棋子下在空这个哪里,首先向上统计,发现只有一个,加上自身也就只有两个,不够,那么先记录已经有两个相同的棋子了,然后开始向下统计,发现有三个,刚好与两个相加为5个,符合“五子连珠”于是乎结束棋盘。
如果竖着的方向统计不够,那么就开始其他方向的统计!
不知道这样讲听懂了没有呢?
下面是判断五子连珠的代码:
这里我是通过switch的方式,然后通过循环进行判断操作的!
// 触发检测“五子连珠”的槽方法
void Qt_Gobang::on_Ninth_Game()
RESULT result = RESULT::No;
result = doDetectionNinth_Game();
if (result == RESULT::Yes)
m_victoryFlags = true;
this->update();
m_startGame = false; // 胜利后,棋盘锁上,防止玩家再次点击棋盘下棋
// 计时全部停止,倒计时清零
m_pBlackChessStepTime->stop();
m_pWhiteChessStepTime->stop();
m_pTotalTime->stop();
emit blackChessSucceed();
emit whiteChessSucceed();
// “五子连珠”执行判断标志
static int caseIndex = 1;
// 黑棋白棋“五子连珠”统计
static int ninth_gameCount = 1;
// 棋子统计辅助(ij)
static int chessCount = 1;
// 判断统计黑白棋子的标志,0统计黑棋,1统计白棋
static int black_white = 1;
RESULT Qt_Gobang::doDetectionNinth_Game()
RESULT result = RESULT::Working;
caseIndex = 1;
ninth_gameCount = 1;
chessCount = 1;
black_white = 1;
// 新下的一个棋子为黑色,则赋值0进行黑色棋子统计
if (m_chessRecords.lastKey() % 2 == 0)
black_white = 0;
do
result = detectionNinth_Game();
while (result == RESULT::Working);
return result;
/*
* case 1: 左
* case 10: 右
* case 2: 上
* case 20: 下
* case 3: 左上
* case 30: 右下
* case 4: 右上
* case 40: 左下
*/
RESULT Qt_Gobang::detectionNinth_Game()
RESULT result = RESULT::Working;
switch (caseIndex)
case 1:
if (m_pointIJ.y() - chessCount >= 0 && Recall(m_pointIJ.x(), m_pointIJ.y() - chessCount, black_white))
ninth_gameCount++; // “五子连珠”统计个数加一
chessCount++; // 辅助统计加一
// “五子连珠”
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 10;
break;
case 10:
if (m_pointIJ.y() + chessCount <= 14 && Recall(m_pointIJ.x(), m_pointIJ.y() + chessCount, black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 2;
ninth_gameCount = 1; // 每开始统计新的方向时,统计“五子连珠”个数赋值1
break;
case 2:
if (m_pointIJ.x() - chessCount >= 0 && Recall(m_pointIJ.x() - chessCount, m_pointIJ.y(), black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 20;
break;
case 20:
if (m_pointIJ.x() + chessCount <= 14 && Recall(m_pointIJ.x() + chessCount, m_pointIJ.y(), black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 3;
ninth_gameCount = 1;
break;
case 3:
if (m_pointIJ.x() - chessCount >= 0 && m_pointIJ.y() - chessCount >= 0 &&
Recall(m_pointIJ.x() - chessCount, m_pointIJ.y() - chessCount, black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 30;
break;
case 30:
if (m_pointIJ.x() + chessCount <= 14 && m_pointIJ.y() + chessCount <= 14 &&
Recall(m_pointIJ.x() + chessCount, m_pointIJ.y() + chessCount, black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 4;
ninth_gameCount = 1;
break;
case 4:
if (m_pointIJ.x() - chessCount >= 0 && m_pointIJ.y() + chessCount <= 14 &&
Recall(m_pointIJ.x() - chessCount, m_pointIJ.y() + chessCount, black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
chessCount = 1;
caseIndex = 40;
break;
case 40:
if (m_pointIJ.x() + chessCount <= 14 && m_pointIJ.y() - chessCount >= 0 &&
Recall(m_pointIJ.x() + chessCount, m_pointIJ.y() - chessCount, black_white))
ninth_gameCount++;
chessCount++;
if (ninth_gameCount == 5)
result = RESULT::Yes;
break;
result = RESULT::No;
break;
return result;
2. MyThread类
这是一个线程类,作用是(循环)播放音乐的,不知为什么,使用QMediaPlayer进行播放音乐,只能单曲循环,不能循环播放。
于是就想到了使用线程,每十秒钟进行播放一次,当音乐还有在播放时,再每十秒的播放一次是没有任何反应的,当音乐停止后再进行播放就会重新开始播放音乐。
然后就到了循环播放的效果,方便发很笨,但有效…
3. GameTime类
这是一个计时类,下棋计时用的!
4. ReadData类
这是一个读档的操作类。
从数据库中读取表gather_table_name中的所有数据,显示在QTableWidget中!
这样就可以显示当前有多少存档了,选择其中一项,点击读档,就会读取对应表的数据初始化棋盘!
5. SaveData类
这是一个存档的操作类。
简而言之就是存档,数据存档名字后,单击确定就会将档名存入gather_table_name表中,创建一个与档名相同的表,将当前棋盘的数据存进入。
6. Systray类
这是一个系统托盘类。
就是最小化,会显示在系统托盘哪里,然后会提示一下!
7. Ai_Chess类
这是一个人机算法类。
里面的代码和五子连珠类似。
算法思想:
通过遍历全盘坐标,找到符合对应机制的模块,进行加分统计,得到最高分的一个坐标,就将棋子下载哪里。
机制是什么?就是那些活四、冲四、活三、眠三等…具体自己上网看一下,如下图,我写一个简单的文档用于统计分的,在项目中页包含了此文档。
根据不同的分数机制,就可以控制ai的智能程度。
另外,调节音量大小也是在这个类中实现的。
四、总结
到此就讲解完了。
其实这个项目是在一年前写的,我也一年没有碰过了,都忘记的差不多了,只能讲个大概,代码已经上传,需要的自提回去慢慢研究吧!
以上是关于QT vs2017《五子棋》人机对战项目的主要内容,如果未能解决你的问题,请参考以下文章