Qt implements a simple backgammon game

In this issue, the editor will tell you about using Qt to implement a simple backgammon game. The article is rich in content and analyzed and described for you from a professional perspective. After reading this article, I hope you can gain something.

The following picture shows the main window page of the game:

 

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project actual combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

The first step: the implementation of window drawing (QPaintEvent drawing event and QMouseEvent mouse event)

①Mouse event (here mine is mouseDoubleClickEvent() double-click event)

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;
   }
  }
 
 }
}

Here, the window grid map stores and draws chess pieces by directly drawing and selecting coordinates by double-clicking the mouse, so a setting position function is performed on the point so that it is at the junction between the two lines. The code is as follows:

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;
}

②Drawing events (mainly drawing of grid graph, black chess and red chess)

The storage of chess piece coordinates is mainly realized through the QVector container, and the container is iteratively drawn, and the implementation code is as follows:

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();
 
}

Step 2: Calculation of winning and losing

 

The above figure lists the calculation relationship rules, and the following codes are used to realize calculations in three different directions:

① Horizontal

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;
}

②Vertical (same as horizontal)

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;
}

③ Oblique direction (from the above figure, taking the coordinate system as an example, it is divided into four quadrants for calculation and counting to judge whether the requirements are met)

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;
}

The operations in the above three directions of horizontal, vertical and oblique are realized by the simplest algorithm, which is easy to understand.

④The timer realizes the regular inspection function of red and black flags

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;
    }
   }
 
  }
 
}

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project actual combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/m0_73443478/article/details/131794916