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,还请见谅 ,希望对初学者有所帮助。

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

(0)

相关推荐

  • QT实现五子棋游戏

    本文实例为大家分享了QT实现五子棋游戏的具体代码,供大家参考,具体内容如下 有点bug 但是能运行 每次点击右边会出现提示图标,表示是黑方落子还是白方并计时,不过不知道为什么点的次数多了 就不出现提示了 然后过一会又有了![Alt] 代码片: #include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QBrush> #include <QMouseE

  • PyQt5实现五子棋游戏(人机对弈)

    这篇博客主要是为了学习Python和PyQt,因为对棋类游戏比较热衷,所以从规则较简单的五子棋入手,利用PyQt5实现图形界面,做一个可以进行人机对弈的脚本,最后打包成应用程序.AI的算法打算用神经网络来完成,正在苦学TensorFlow中. 本来我以为五子棋规则很简单,不就像小学时候玩的那样,五个棋子连在一起就赢了嘛,但是后来发现事情并没有那么简单,现在的五子棋有禁手这个规则 ,"三三禁手" ."四四禁手"."长连禁手"等等,都是为了限制现行一

  • Qt实现简单五子棋小游戏

    C++代码简单实现五子棋功能,主要是分为窗口绘图的显示,横.纵.斜三个方面计算的功能代码实现,即能连续出现5个相同棋子就为赢.在这里就简单讲解一下这三个方面的功能实现(主要是通过QT实现). 下图为游戏主窗口页面: 第一步:窗口绘图的实现(QPaintEvent绘图事件 和 QMouseEvent鼠标事件) ①鼠标事件(这里我的是mouseDoubleClickEvent()双击事件) void GamePage::mouseDoubleClickEvent(QMouseEvent *event

  • 用C语言实现简单五子棋小游戏

    本文实例为大家分享了C语言实现简单五子棋小游戏的具体代码,供大家参考,具体内容如下 在vs2019创建新项目,然后添加两个源文件test.c和game.c,接着创建一个头文件game.h. test.c: #include "game.h" void game() { char board[ROW][COL]; InitBoard(board, ROW, COL); DisplayBoard(board, ROW, COL); char ret = 0; while (1) { Pla

  • java实现简单五子棋小游戏(2)

    本文实例为大家分享了java实现简单五子棋小游戏游戏的具体代码,供大家参考,具体内容如下 讲解 在第一步实现的基础上,添加游戏结束条件.五子棋游戏中的相同棋子如果同时有五个连接成一条线就说明游戏结束. 代码实现如下: if(count!=0){                 //判断每一行                 for(int j=0;j<11;j++){                     for(int i=0;i<7;i++){                      

  • java实现简单五子棋小游戏(1)

    本文实例为大家分享了java实现简单五子棋小游戏的具体代码,供大家参考,具体内容如下 讲解 五子棋,实际上就是用一个数组来实现的.没有其他很复杂的结构.首先我们制作五子棋,先要有一个棋盘. public void setGraphics(Graphics g){         this.g=g;         for(int i=0;i<11;i++){             g.drawLine(100+Size*i, 100, 100+Size*i, 500);           

  • C语言实现简单五子棋小游戏

    五子棋简单功能实现,供大家参考,具体内容如下 游戏功能演示 代码如下: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <getch.h> // 棋盘 char board[15][15]; // 棋子坐标 char kx = 7 , ky = 7; // 角色 char role = '@'; // 显示棋盘 void show_board(void) { syste

  • python实现简单五子棋小游戏

    用python实现五子棋简单人机模式的练习过程,供大家参考,具体内容如下 最近在初学python,今天就用自己的一些粗浅理解,来记录一下这几天的python简单人机五子棋游戏的练习,下面是实现过程的理解(是在cmd中运行的): 主要流程:*重点内容* - 首先是模块及类的划分- 棋子类和棋盘类的方法- 对策略类里的功能进行细分,调用棋子类和棋盘类- 写出判断输赢的方法- 用main函数进行整个游戏进度的控制 模块及类的划分 类的划分涉及到了面向对象的内容,根据五子棋游戏的设定,人和机器依次在一个

  • C语言实现简易五子棋小游戏

    本文实例为大家分享了C语言实现简单五子棋小游戏的具体代码,供大家参考,具体内容如下 效果图如下: 设计思路: 棋盘设计为15×15格,初始状态光标在棋盘的中央,白棋先走,轮流落子,当一方连成五子或下满棋盘时,游戏结束(连成五子的一方获胜,下满棋盘为和棋).当游戏一方胜利后显示胜利信息,提示信息利用汉字点阵输出.程序游戏是一个二维平面图,可用二维数组来实现,数组两个下标可以表示棋盘上的位置,数组元素的值代表棋格上的状态,共有三种情况,分别是0代表空格,1代表白棋,2代表黑棋.程序的主要工作是接收棋

  • QT实现简单五子棋游戏

    本文实例为大家分享了QT实现简单五子棋游戏的具体代码,供大家参考,具体内容如下 FIR.pro #------------------------------------------------- # # Project created by QtCreator 2012-09-01T15:09:11 # #------------------------------------------------- QT += core gui TARGET = FIR TEMPLATE = app SO

  • 教你用Js写一个简单的五子棋小游戏

    目录 棋盘绘制 棋子的绘制 在点击 canvas 的时候获取相对于棋盘数据的坐标点 是否结束 悔棋功能 总结 这里的五子棋只做一些基础的功能,对于相对专业的规则不做处理. 那么该五子棋实现的规则和功能如下: 整体功能采用canvas实现 行列都规定 20 个数量,那么棋子的行列数量是 20 + 1 棋盘数据采用稀疏数组格式 棋子:0 为黑色,1 为白色 可以悔棋 胜负结束判断 棋盘绘制 <template> <div class="gobang"> <ca

  • C语言实现简单的五子棋小游戏

    本文实例为大家分享了C语言实现五子棋小游戏的具体代码,供大家参考,具体内容如下 我们需要一个二维数组去储存当前的棋盘状态,然后打印出来. 我们游戏的逻辑是初始化棋盘,打印棋盘,人下棋,打印棋盘,判断是否游戏结束,电脑下棋,打印棋盘,判断是否游戏结束,然后回到人下棋过程,结束游戏后,判断谁赢谁输还是平局. 判断输赢的逻辑是遍历行,遍历列,遍历主对角线,遍历反对角线,如果都判断不出输赢,那么就继续游戏. game.h #include <stdio.h> #include <stdlib.h

随机推荐