• 5721阅读
  • 7回复

《Qt实战小项目》2,五子棋游戏 [复制链接]

上一主题 下一主题
离线逆风微光
 

图酷模式  只看楼主 倒序阅读 楼主  发表于: 2018-05-20
这是我的CSDN博客专栏《Qt实战小项目》的系列文章第2篇。
专栏地址:https://blog.csdn.net/dpsying/category_9267660.html

目前专栏内有这些文章:
QT项目一:俄罗斯方块游戏
QT项目二:五子棋游戏
QT项目三:中国象棋
QT项目四:扫雷游戏
QT项目五--计算器
QT项目六:简易客户信息管理系统

1,简介

QT5.5.1 开发的五子棋单机版,花了一个晚上+熬夜完成。
(2020-8-27:源码已改为QT5.11.1编译过)


2,效果

window.open('http://www.qtcn.org/bbs/attachment/Mon_2008/44_188170_00fd9df3f596173.gif?132');" style="max-width:700px;max-height:700px;" onload="if(is_ie6&&this.offsetWidth>700)this.width=700;" >

3,思路



棋盘为15*15矩阵
棋子Item 存1个坐标点、一个颜色类型(黑棋还是白棋)
绘制顺序依次为 棋盘、棋子、鼠标(也是一个棋子)

核心算法(判断五子连):
对所下的棋子,向 8个方向分别统计相邻的同色棋子个数
8个方向为:左、左上、上、右上、右、右下、下、左下
然后在一条直线的2个方向的棋子个数加起来,即得到该直线上与所下棋子相邻的同色棋子个数

棋子类Item.h:
包含一个QPoint圆心坐标,和一个bool变量,代表是黑方还是白方

  1. #pragma once
  2. #include <QPoint>
  3. class Item
  4. {
  5. public:
  6.     Item(void);
  7.     Item(QPoint pt,bool bBlack);
  8.     ~Item(void);
  9.     bool operator==(const Item &t1)const
  10.     {
  11.         return ((mPt == t1.mPt) && (mBlack == t1.mBlack));
  12.     }  
  13.     QPoint mPt;
  14.     bool mBlack;
  15. private:
  16. };


MainWindow.h:QVector<Item> mItems 保存所有棋子
  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include "Item.h"
  5. namespace Ui {
  6. class MainWindow;
  7. }
  8. #define CHESS_ROWS        15
  9. #define CHESS_COLUMES    15
  10. #define RECT_WIDTH        50
  11. #define RECT_HEIGHT        50
  12. class MainWindow : public QMainWindow
  13. {
  14.     Q_OBJECT
  15. public:
  16.     explicit MainWindow(QWidget *parent = 0);
  17.     ~MainWindow();
  18. protected:
  19.     void paintEvent(QPaintEvent *);
  20.     void mousePressEvent(QMouseEvent *);
  21. private:
  22.     void DrawChessboard();      //画棋盘
  23.     void DrawItems();           //画棋子
  24.     void DrawItemWithMouse();   //画跟随鼠标的棋子
  25.     void DrawChessAtPoint(QPainter& painter,QPoint& pt);
  26.     
  27.     //统计某个方向(共8个方向)上的相连个数,用QPoint表示统计方向,如(1,1)表示右下方,(-1,0)表示向左
  28.     int CountNearItem(Item item,QPoint ptDirection);    
  29. private:
  30.     Ui::MainWindow *ui;
  31.     QVector<Item> mItems;   //所有棋子
  32.     bool mBlack;            //当前是否该黑棋下
  33. };
  34. #endif // MAINWINDOW_H

MainWindow.cpp:
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include "qpainter.h"
  4. #include "qevent.h"
  5. #include "qpoint.h"
  6. #include "qmessagebox.h"
  7. MainWindow::MainWindow(QWidget *parent) :
  8.     QMainWindow(parent),
  9.     ui(new Ui::MainWindow)
  10. {
  11.     ui->setupUi(this);
  12.     ui->mainToolBar->hide();
  13.     ui->menuBar->hide();
  14.     resize((CHESS_COLUMES + 1)*RECT_WIDTH  ,(CHESS_ROWS + 1)*RECT_HEIGHT);
  15.     mBlack = true;
  16. }
  17. MainWindow::~MainWindow()
  18. {
  19.     delete ui;
  20. }
  21. void MainWindow::paintEvent(QPaintEvent *e)
  22. {
  23.     DrawChessboard();        //画棋盘
  24.     DrawItems();            //画棋子
  25.     DrawItemWithMouse();    //画鼠标(当前方的棋子形状)
  26.     update();
  27. }
  28. void MainWindow::DrawChessboard()
  29. {
  30.     QPainter painter(this);
  31.     painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
  32.     painter.setBrush(Qt::darkYellow);
  33.     painter.setPen(QPen(QColor(Qt::black),2));
  34.     for(int i = 0;i<CHESS_COLUMES; i++)
  35.     {
  36.         for (int j = 0; j<CHESS_ROWS; j++)
  37.         {
  38.             painter.drawRect( (i+0.5)*RECT_WIDTH,(j+0.5)*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT);
  39.         }
  40.     }
  41. }
  42. void MainWindow::DrawItems()
  43. {
  44.     QPainter painter(this);
  45.     painter.setPen(QPen(QColor(Qt::transparent)));
  46.     for (int i = 0; i<mItems.size(); i++)
  47.     {
  48.         Item item = mItems[i];
  49.         if (item.mBlack)
  50.         {
  51.             painter.setBrush(Qt::black);
  52.         }
  53.         else
  54.         {
  55.             painter.setBrush(Qt::white);
  56.         }
  57.         DrawChessAtPoint(painter,item.mPt);
  58.     }
  59. }
  60. void MainWindow::DrawChessAtPoint(QPainter& painter,QPoint& pt)
  61. {
  62.     QPoint ptCenter((pt.x()+0.5)*RECT_WIDTH,(pt.y()+0.5)*RECT_HEIGHT);
  63.     painter.drawEllipse(ptCenter,RECT_WIDTH / 2,RECT_HEIGHT / 2);
  64. }
  65. void MainWindow::DrawItemWithMouse()
  66. {
  67.     QPainter painter(this);
  68.     painter.setPen(QPen(QColor(Qt::transparent)));
  69.     if (mBlack)
  70.     {
  71.         painter.setBrush(Qt::black);
  72.     }
  73.     else
  74.     {
  75.         painter.setBrush(Qt::white);
  76.     }
  77.     painter.drawEllipse(mapFromGlobal(QCursor::pos()),RECT_WIDTH / 2,RECT_HEIGHT / 2);
  78.     
  79. }
  80. void MainWindow::mousePressEvent(QMouseEvent * e)
  81. {
  82.     //求鼠标点击处的棋子点pt
  83.     QPoint pt;
  84.     pt.setX( (e->pos().x() ) / RECT_WIDTH);
  85.     pt.setY( (e->pos().y() ) / RECT_HEIGHT);
  86.     //如果已存在棋子,就什么也不做
  87.     for (int i = 0; i<mItems.size(); i++)
  88.     {
  89.         Item item = mItems[i];
  90.         if (item.mPt == pt)
  91.         {
  92.             //已有棋子
  93.             return;
  94.         }
  95.     }
  96.     //不存在棋子,就下一个
  97.     Item item(pt,mBlack);
  98.     mItems.append(item);
  99.     //统计4个方向是否五子连
  100.     int nLeft =            CountNearItem(item,QPoint(-1,0));
  101.     int nLeftUp =        CountNearItem(item,QPoint(-1,-1));
  102.     int nUp =            CountNearItem(item,QPoint(0,-1));
  103.     int nRightUp =        CountNearItem(item,QPoint(1,-1));
  104.     int nRight =        CountNearItem(item,QPoint(1,0));
  105.     int nRightDown =    CountNearItem(item,QPoint(1,1));
  106.     int nDown =            CountNearItem(item,QPoint(0,1));
  107.     int nLeftDown =        CountNearItem(item,QPoint(-1,1));
  108.     if ( (nLeft + nRight) >= 4 ||
  109.          (nLeftUp + nRightDown) >= 4 ||
  110.          (nUp + nDown) >= 4 ||
  111.          (nRightUp + nLeftDown) >= 4 )
  112.     {
  113.         QString str = mBlack? QStringLiteral("黑棋胜利!") : QStringLiteral("白棋胜利!");
  114.         QMessageBox::information(NULL,  QStringLiteral("游戏结束"),str, QMessageBox::Ok , QMessageBox::Ok);
  115.         mItems.clear();
  116.         //NewGame();
  117.         return;
  118.     }
  119.     //该另一方下棋了
  120.     mBlack = !mBlack;
  121. }
  122. int MainWindow::CountNearItem(Item item,QPoint ptDirection)
  123. {
  124.     int nCount = 0;
  125.     item.mPt += ptDirection;
  126.     while (mItems.contains(item))
  127.     {
  128.         nCount++;
  129.         item.mPt += ptDirection;
  130.     }
  131.     return nCount;
  132. }



4,源码


源码可在学习群免费下载
群号码:1149411109
群名称:Qt实战派学习群




离线liuchangyin

只看该作者 1楼 发表于: 2018-05-21
离线shasidaran

只看该作者 2楼 发表于: 2018-05-22
  
离线逆风微光

只看该作者 3楼 发表于: 2018-05-25
回 liuchangyin 的帖子
liuchangyin:[表情]  (2018-05-21 09:41) 

谢谢支持!
离线逆风微光

只看该作者 4楼 发表于: 2018-05-25
回 shasidaran 的帖子
shasidaran:[表情]  [表情]  (2018-05-22 09:49) 

谢谢支持!
离线chrisv

只看该作者 5楼 发表于: 2018-08-15
     好厉害,楼主辛苦了,学习学习。
离线逆风微光

只看该作者 6楼 发表于: 2018-08-22
回 chrisv 的帖子
chrisv:[表情]  [表情]  [表情] 好厉害,楼主辛苦了,学习学习。 (2018-08-15 09:12) 

加油啦
离线unitcode

只看该作者 7楼 发表于: 2018-11-22
挺不错的!
快速回复
限100 字节
 
上一个 下一个