Qt实现简单五子棋小游戏

 更新时间:2020年08月28日 13:35:34   作者:Tjmies  
这篇文章主要为大家详细介绍了Qt实现简单五子棋小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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经典小游戏汇总

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • c++连接mysql5.6的出错问题总结

    c++连接mysql5.6的出错问题总结

    下面小编就为大家带来一篇c++连接mysql5.6的出错问题总结。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,祝大家游戏愉快哦
    2016-12-12
  • C++编程之CString、string与、char数组的转换

    C++编程之CString、string与、char数组的转换

    这篇文章主要介绍了C++编程之CString、string与、char数组的转换的相关资料,希望通过本文能帮助到大家,让大家学习理解这部分内容,需要的朋友可以参考下
    2017-10-10
  • C++超详细讲解贪心策略的设计及解决会场安排问题

    C++超详细讲解贪心策略的设计及解决会场安排问题

    为了更好的应对《算法设计与分析》这门课程,我把书上以及老师讲过的案例都详细的做一个重现及解剖,让你熟记每一个潜在的考点,希望能给大家帮助
    2022-05-05
  • C++编写高性能服务器实例教程

    C++编写高性能服务器实例教程

    这篇文章主要介绍了如何用C++编写高性能服务器,文中通过示例代码介绍的非常详细,对大家学习C++有一定的参考价值,需要的朋友们可以了解下
    2020-06-06
  • c++ 深入理解归并排序的用法

    c++ 深入理解归并排序的用法

    归并排序是典型分治思想的代表——首先把原问题分解为两个或多个子问题,然后求解子问题的解,最后使用子问题的解来构造出原问题的解
    2022-03-03
  • C语言实现随机抽取纸牌程序

    C语言实现随机抽取纸牌程序

    这篇文章主要为大家详细介绍了C语言实现随机抽取纸牌程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C++排序算法之插入排序解析

    C++排序算法之插入排序解析

    这篇文章主要介绍了C++排序算法之插入排序解析,将数组分为有序表和无序表,每次从有序表中取出一个元素,插入到有序表的适当位置,每遍历一次,有序表中元素增加一个,无序表中元素个数减少一个,重复n-1次,完成排序,需要的朋友可以参考下
    2023-10-10
  • C语言实现扫雷小游戏详细代码

    C语言实现扫雷小游戏详细代码

    这篇文章主要为大家详细介绍了C语言实现扫雷小游戏的代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C语言之数组名与数组起始地址的关系解析

    C语言之数组名与数组起始地址的关系解析

    这篇文章主要介绍了C语言之数组名与数组起始地址的关系,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C和MFC巧妙获取外网IP的两种实现方法

    C和MFC巧妙获取外网IP的两种实现方法

    这篇文章主要介绍了C和MFC巧妙获取外网IP的两种实现方法,功能非常的实用,需要的朋友可以参考下
    2014-07-07

最新评论