时间:2021-05-20
C++代码简单实现五子棋功能,主要是分为窗口绘图的显示,横、纵、斜三个方面计算的功能代码实现,即能连续出现5个相同棋子就为赢。在这里就简单讲解一下这三个方面的功能实现(主要是通过QT实现)。
下图为游戏主窗口页面:
第一步:窗口绘图的实现(QPaintEvent绘图事件 和 QMouseEvent鼠标事件)
①鼠标事件(这里我的是mouseDoubleClickEvent()双击事件)
void GamePage::mouseDoubleClickEvent(QMouseEvent *event)//鼠标双击事件{ m_dx = event->x(); m_dy = event->y(); //避免乱点时存入坐标 需添加:标志符--》game状态 坐标的界限(点) if(m_dx < POINT_X_MAX && m_dy < POINT_Y_MAX && m_bRunState == true) { //如果点在交叉点周围则设置点在交叉点上(判断点位置) QPointF newPoint(gainPointPosition(QPointF(m_dx,m_dy))); if(!m_VectorRedPoint.contains(newPoint) && !m_VectorBlackPoint.contains(newPoint))//判断点是否已经存在 { if(m_iFlagWho == 0)//红棋 { m_VectorRedPoint.append(newPoint); m_iFlagWho = 1; } else//黑棋 { m_VectorBlackPoint.append(newPoint); m_iFlagWho = 0; } } }}在这里窗口网格图是通过直接绘画以及鼠标双击选择坐标来存储棋子和绘画棋子,因此对点进行了一个设置位置函数以便处于两线之间的交接处,代码如下:
QPointF GamePage::gainPointPosition(QPointF srcPoint)//返回一个处于格子两线交接处的坐标点{ QPointF tmp; for(int i = 0;i < 12;i++) { if(srcPoint.x() >= 50*i && srcPoint.x() <= (50*i+25))//X判断 { tmp.setX(50*i);//如果处于50*i ~ 50*i+25)之间则设置点坐标点为50*i } else if (srcPoint.x() >= (50*i + 25) && srcPoint.x() <= 50*(i+1)) { tmp.setX(50*(i+1));//如果处于50*i+25 ~ 50*(i+1)之间则设置点坐标点为50*(i+1) } if(srcPoint.y() >= 50*i && srcPoint.y() <= (50*i+25))//Y判断 { tmp.setY(50*i);//同上 } else if (srcPoint.y() >= (50*i + 25) && srcPoint.y() <= 50*(i+1)) { tmp.setY(50*(i+1));//同上 } } return tmp;}②绘图事件( 主要是网格图、黑棋、红棋的绘画 )
棋子坐标的存储主要是通过QVector容器来实现,并对容器进行迭代循环绘图,实现代码如下:
void GamePage::paintEvent(QPaintEvent *event)//绘画事件{ QPainter *pater = new QPainter(this); pater->begin(this); //网格图 pater->setPen(Qt::black); for(int i = 0;i <= 12;i++) { pater->drawLine(0,50*i,600,50*i); pater->drawLine(50*i,0,50*i,600); } //红色棋绘画 QVector<QPointF>::iterator iter; for(iter = m_VectorRedPoint.begin();iter != m_VectorRedPoint.end();iter++) { pater->setBrush(QBrush(Qt::red, Qt::SolidPattern)); pater->setPen(Qt::red); pater->drawEllipse(*iter,15,15); } //黑色棋绘画 QVector<QPointF>::iterator iter1; for(iter1 = m_VectorBlackPoint.begin();iter1 != m_VectorBlackPoint.end();iter1++) { pater->setBrush(QBrush(Qt::black, Qt::SolidPattern)); pater->setPen(Qt::black); pater->drawEllipse(*iter1,15,15); } pater->end(); update(); }第二步:输赢的计算
上图列出了计算的关系规律,下面就用代码分别实现三个不同方向的计算:
①横向
bool GamePage::checkXPointF(QVector<QPointF> vector) //检查X轴方向的{ int num_L= 1; int num_R = 1; QVector<QPointF>::iterator iter; QVector<QPointF>::iterator itertmp; for(iter = vector.begin();iter != vector.end();iter++) { QPointF tmp = *iter; for(int k = 1;k < 5;k++)//左方向的查找 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"X compare"<<tmp; if((*itertmp).x() - tmp.x() == k*50) { num_L ++; } } //qDebug()<<"count:"<<num; if(num_L == k+1)//寻找过程中找到几个点相连 { if(num_L == 5) { return true; } } else { break; } } for(int k = 1;k < 5;k++)//右方向的查找 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"X compare"<<tmp; if((*itertmp).x() - tmp.x() == -k*50) { num_R ++; } } //qDebug()<<"count:"<<num; if(num_R == k+1)//寻找过程中找到几个点相连 { if(num_R == 5) { return true; } } else { break; } } if(num_R + num_L == 5+1)//5+1 因为左右方向都是从1开始计算 重复了原点tmp坐标 { return true; } else { num_R = 1; num_L = 1; } } return false;}②纵向(与横向同理)
bool GamePage::checkYPointF(QVector<QPointF> vector){ qDebug()<<"enter Y***************"; int num_U = 1; int num_D = 1; QVector<QPointF>::iterator iter; QVector<QPointF>::iterator itertmp; for(iter = vector.begin();iter != vector.end();iter++) { QPointF tmp = *iter; for(int k = 1;k < 5;k++)//上 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"Y compare"<<tmp; if((*itertmp).y() - tmp.y() == k*50) { num_U ++; } } qDebug()<<"num_U:"<<num_U; if(num_U == k+1)//寻找过程中找到几个点相连 { if(num_U == 5) { return true; } }else{break;} } for(int k = 1;k < 5;k++)//下 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"Y compare"<<tmp; if((*itertmp).y() - tmp.y() == -k*50) { num_D ++; } } qDebug()<<"num_D:"<<num_D; if(num_D == k+1)//寻找过程中找到几个点相连 { if(num_D == 5) { return true; } }else{break;} } if(num_D + num_U == 5 + 1)//减去一个 { return true; } else { num_D = 1; num_U= 1; } } return false;}③斜向(从上图可知,以坐标系为例,分为四个象限的计算和计数来判断是否达到要求)
int GamePage::findSeriesPointF(bool flag, QPointF tmp, QVector<QPointF> vector){ bool flag_iter = false; int forward_count = 1;//一象限的数量 int reverse_count = 1; int forward_count2 = 1; int reverse_count2 = 1; QVector<QPointF>::iterator iter= vector.begin(); while(iter != vector.end()) { qDebug()<<*iter<<"compare"<<tmp; switch(forward_count)//一象限 { case 1: if((*iter).x() - tmp.x() == 50 && (*iter).y() - tmp.y() == -50) { forward_count ++; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == 50*forward_count && (*iter).y() - tmp.y() == -50*forward_count) { forward_count++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == 50*forward_count && (*iter).y() - tmp.y() == -50*forward_count) { forward_count++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == 50*forward_count && (*iter).y() - tmp.y() == -50*forward_count) { forward_count++; flag_iter = true; } break; } switch(reverse_count)//三象限 { case 1: if((*iter).x() - tmp.x() == -50 && (*iter).y() - tmp.y() == 50) { reverse_count=2; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == -50*reverse_count && (*iter).y() - tmp.y() == 50*reverse_count) { reverse_count++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == -50*reverse_count && (*iter).y() - tmp.y() == 50*reverse_count) { reverse_count++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == -50*reverse_count && (*iter).y() - tmp.y() == 50*reverse_count) { reverse_count++; flag_iter = true; } break; } qDebug()<<forward_count<<"+"<<reverse_count; if(forward_count + reverse_count == 6)//未加上点本身 { return 5; } switch(forward_count2)//2象限 { case 1: if((*iter).x() - tmp.x() == -50 && (*iter).y() - tmp.y() == -50) { forward_count2++; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == -50*forward_count2 && (*iter).y() - tmp.y() == -50*forward_count2) { forward_count2++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == -50*forward_count2 && (*iter).y() - tmp.y() == -50*forward_count2) { forward_count2++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == -50*forward_count2 && (*iter).y() - tmp.y() == -50*forward_count2) { forward_count2++; flag_iter = true; } break; } switch(reverse_count2)//4象限 { case 1: if((*iter).x() - tmp.x() == 50 && (*iter).y() - tmp.y() == 50) { reverse_count2++; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == 50*reverse_count2 && (*iter).y() - tmp.y() == 50*reverse_count2) { reverse_count2++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == 50*reverse_count2 && (*iter).y() - tmp.y() == 50*reverse_count2) { reverse_count2++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == 50*reverse_count2 && (*iter).y() - tmp.y() == 50*reverse_count2) { reverse_count2++; flag_iter = true; } break; } qDebug()<<forward_count2<<"+"<<reverse_count2; if(forward_count2 + reverse_count2 == 6)//未加上点本身 { return 5; } if(flag_iter) { iter = vector.begin();//目的是返回首个点,重头存货在后 不错过 flag_iter = false; } else { iter++; } } return 0;}以上横、纵、斜三个方向的运算都是通过最简单的算法是实现,易于理解。
④定时器实现红黑旗的定时检查功能
void GamePage::slotCheckWhetherWin()//定时器检查是否输赢功能{ m_pVerVector.clear(); m_pVerVectorB.clear(); m_pHerVector.clear(); m_pHerVectorB.clear(); QVector<QPointF>::iterator iterRed; for(iterRed = m_VectorRedPoint.begin();iterRed != m_VectorRedPoint.end();iterRed++) { qDebug()<<*iterRed; } QVector<QPointF> tmpRed = m_VectorRedPoint; //红棋判断 if(m_VectorRedPoint.size() >= 5) { for(iterRed = m_VectorRedPoint.begin();iterRed != m_VectorRedPoint.end();iterRed++) { QPointF tmp = *iterRed;//获取第一个点 qDebug()<<"tmp:"<<tmp; QVector<QPointF>::iterator itertmp; for(itertmp = tmpRed.begin();itertmp != tmpRed.end();itertmp++) { qDebug()<<"tmpRed:"<<*itertmp; //横向连续5个点 if((*itertmp).y() - tmp.y() >= -0.000001 && (*itertmp).y() - tmp.y() <= 0.000001)//先判断y是同一坐标 { m_pHerVector.append(*itertmp); } //纵向连续5个点 if((*itertmp).x() - tmp.x() >= -0.000001 && (*itertmp).x() - tmp.x() <= 0.000001)//先判断y是同一坐标 { m_pVerVector.append(*itertmp); } } //对容器进行操作 if(checkXPointF(m_pHerVector) || checkYPointF(m_pVerVector)) { QMessageBox::warning(nullptr,"warning","红方XY赢了!"); m_ptimer->stop(); return; } else { m_pHerVector.clear();//清空 m_pVerVector.clear();//清空 count = 0; } //其他都是斜向 if(findSeriesPointF(true,tmp,m_VectorRedPoint) == 5) { QMessageBox::warning(nullptr,"warning","红方斜线赢了!"); m_ptimer->stop(); return; } } } //黑棋判断 QVector<QPointF>::iterator iterBlack; QVector<QPointF> tmpBlack = m_VectorBlackPoint; if(m_VectorBlackPoint.size() >= 5) { for(iterBlack = m_VectorBlackPoint.begin();iterBlack != m_VectorBlackPoint.end();iterBlack++) { QPointF tmp = *iterBlack;//获取第一个点 qDebug()<<"tmp:"<<tmp; QVector<QPointF>::iterator itertmp; for(itertmp = tmpBlack.begin();itertmp != tmpBlack.end();itertmp++)//正向 { qDebug()<<"tmpRed:"<<*itertmp; //横向连续5个点 if((*itertmp).y() - tmp.y() >= -0.000001 && (*itertmp).y() - tmp.y() <= 0.000001)//先判断y是同一坐标 { m_pHerVectorB.append(*itertmp); } //纵向连续5个点 if((*itertmp).x() - tmp.x() >= -0.000001 && (*itertmp).x() - tmp.x() <= 0.000001)//先判断y是同一坐标 { m_pVerVectorB.append(*itertmp); } } //对容器进行操作 if(checkXPointF(m_pHerVectorB) || checkYPointF(m_pVerVectorB)) { QMessageBox::warning(nullptr,"warning","黑方XY赢了!"); m_ptimer->stop(); return; } else { m_pHerVectorB.clear();//清空 m_pVerVectorB.clear();//清空 count = 0; } //其他都是斜向 if(findSeriesPointF(true,tmp,m_VectorBlackPoint) == 5) { QMessageBox::warning(nullptr,"warning","黑方斜线赢了!"); m_ptimer->stop(); return; } } } }以上就是实现简单的五子棋功能,初步实现一些简单的计算功能,能正常运行小游戏,没花太多时间进行检查,可能会存在一些bug,还请见谅 ,希望对初学者有所帮助。
更多有趣的经典小游戏实现专题,分享给大家:
C++经典小游戏汇总
python经典小游戏汇总
python俄罗斯方块游戏集合
JavaScript经典游戏 玩不停
javascript经典小游戏汇总
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文实例为大家分享了Java实现五子棋小游戏的具体代码,供大家参考,具体内容如下项目名称五子棋小游戏项目描述可以改变获胜棋子数,率先连成棋数的人获胜代码实现测试
本文实例为大家分享了JavaScript实现五子棋小游戏的具体代码,供大家参考,具体内容如下HTML部分五子棋*{padding:0;margin:0;}bod
本文实例为大家分享了js+canvas实现五子棋小游戏的具体代码,供大家参考,具体内容如下效果展示:源码展示:五子棋*{margin:0;padding:0;}
本文实例为大家分享了js实现AI五子棋人机大战的具体代码,供大家参考,具体内容如下实现原理就是计算五子棋所有赢的种类,利用canvas实现五子棋排版落子。五子棋
控制台实现五子棋游戏,供大家参考,具体内容如下控制台打印棋盘编写两人对弈的五子棋游戏,游戏规则:黑白双方有一方首先实现五子连续,则获胜,游戏结束。代码:impo