1. 程式人生 > 程式設計 >Qt實現簡單五子棋小遊戲

Qt實現簡單五子棋小遊戲

C++程式碼簡單實現五子棋功能,主要是分為視窗繪圖的顯示,橫、縱、斜三個方面計算的功能程式碼實現,即能連續出現5個相同棋子就為贏。在這裡就簡單講解一下這三個方面的功能實現(主要是通過QT實現)。

下圖為遊戲主視窗頁面:

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,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);
 }
 pater->end();
 update();
 
}

第二步:輸贏的計算

Qt實現簡單五子棋小遊戲

上圖列出了計算的關係規律,下面就用程式碼分別實現三個不同方向的計算:

①橫向

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,"紅方斜線贏了!");
     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,"黑方XY贏了!");
     m_ptimer->stop();
     return;
    }
    else
    {
     m_pHerVectorB.clear();//清空
     m_pVerVectorB.clear();//清空
     count = 0;
    }
 
    //其他都是斜向
    if(findSeriesPointF(true,m_VectorBlackPoint) == 5)
    {
     QMessageBox::warning(nullptr,"黑方斜線贏了!");
     m_ptimer->stop();
     return;
    }
   }
 
  }
 
}

以上就是實現簡單的五子棋功能,初步實現一些簡單的計算功能,能正常執行小遊戲,沒花太多時間進行檢查,可能會存在一些bug,還請見諒 ,希望對初學者有所幫助。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。