查看完整版本: [-- 《Qt实战小项目》2,五子棋游戏 --]

QTCN开发网 -> Qt 作品展 -> 《Qt实战小项目》2,五子棋游戏 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

逆风微光 2018-05-20 12:33

《Qt实战小项目》2,五子棋游戏

这是我的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,效果

[attachment=21870]

3,思路



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

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

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

  1. #pragma once
    #include <QPoint>

    class Item
    {
    public:
        Item(void);
        Item(QPoint pt,bool bBlack);
        ~Item(void);

        bool operator==(const Item &t1)const
        {
            return ((mPt == t1.mPt) && (mBlack == t1.mBlack));
        }  

        QPoint mPt;
        bool mBlack;
    private:


    };


MainWindow.h:QVector<Item> mItems 保存所有棋子
  1. #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include "Item.h"


    namespace Ui {
    class MainWindow;
    }


    #define CHESS_ROWS        15
    #define CHESS_COLUMES    15
    #define RECT_WIDTH        50
    #define RECT_HEIGHT        50

    class MainWindow : public QMainWindow
    {
        Q_OBJECT

    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();

    protected:
        void paintEvent(QPaintEvent *);
        void mousePressEvent(QMouseEvent *);

    private:
        void DrawChessboard();      //画棋盘
        void DrawItems();           //画棋子
        void DrawItemWithMouse();   //画跟随鼠标的棋子

        void DrawChessAtPoint(QPainter& painter,QPoint& pt);
        
        //统计某个方向(共8个方向)上的相连个数,用QPoint表示统计方向,如(1,1)表示右下方,(-1,0)表示向左
        int CountNearItem(Item item,QPoint ptDirection);    

    private:
        Ui::MainWindow *ui;

        QVector<Item> mItems;   //所有棋子
        bool mBlack;            //当前是否该黑棋下
    };

    #endif // MAINWINDOW_H

MainWindow.cpp:
  1. #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "qpainter.h"
    #include "qevent.h"
    #include "qpoint.h"
    #include "qmessagebox.h"




    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->mainToolBar->hide();
        ui->menuBar->hide();

        resize((CHESS_COLUMES + 1)*RECT_WIDTH  ,(CHESS_ROWS + 1)*RECT_HEIGHT);

        mBlack = true;

    }

    MainWindow::~MainWindow()
    {
        delete ui;
    }

    void MainWindow::paintEvent(QPaintEvent *e)
    {
        DrawChessboard();        //画棋盘
        DrawItems();            //画棋子
        DrawItemWithMouse();    //画鼠标(当前方的棋子形状)

        update();
    }

    void MainWindow::DrawChessboard()
    {
        QPainter painter(this);
        painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
        painter.setBrush(Qt::darkYellow);
        painter.setPen(QPen(QColor(Qt::black),2));

        for(int i = 0;i<CHESS_COLUMES; i++)
        {
            for (int j = 0; j<CHESS_ROWS; j++)
            {
                painter.drawRect( (i+0.5)*RECT_WIDTH,(j+0.5)*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT);
            }
        }
    }

    void MainWindow::DrawItems()
    {
        QPainter painter(this);
        painter.setPen(QPen(QColor(Qt::transparent)));

        for (int i = 0; i<mItems.size(); i++)
        {
            Item item = mItems[i];
            if (item.mBlack)
            {
                painter.setBrush(Qt::black);
            }
            else
            {
                painter.setBrush(Qt::white);
            }
            DrawChessAtPoint(painter,item.mPt);
        }
    }

    void MainWindow::DrawChessAtPoint(QPainter& painter,QPoint& pt)
    {
        QPoint ptCenter((pt.x()+0.5)*RECT_WIDTH,(pt.y()+0.5)*RECT_HEIGHT);
        painter.drawEllipse(ptCenter,RECT_WIDTH / 2,RECT_HEIGHT / 2);
    }

    void MainWindow::DrawItemWithMouse()
    {
        QPainter painter(this);
        painter.setPen(QPen(QColor(Qt::transparent)));

        if (mBlack)
        {
            painter.setBrush(Qt::black);
        }
        else
        {
            painter.setBrush(Qt::white);
        }
        painter.drawEllipse(mapFromGlobal(QCursor::pos()),RECT_WIDTH / 2,RECT_HEIGHT / 2);
        
    }

    void MainWindow::mousePressEvent(QMouseEvent * e)
    {
        //求鼠标点击处的棋子点pt
        QPoint pt;
        pt.setX( (e->pos().x() ) / RECT_WIDTH);
        pt.setY( (e->pos().y() ) / RECT_HEIGHT);

        //如果已存在棋子,就什么也不做
        for (int i = 0; i<mItems.size(); i++)
        {
            Item item = mItems[i];
            if (item.mPt == pt)
            {
                //已有棋子
                return;
            }
        }
        //不存在棋子,就下一个
        Item item(pt,mBlack);
        mItems.append(item);

        //统计4个方向是否五子连
        int nLeft =            CountNearItem(item,QPoint(-1,0));
        int nLeftUp =        CountNearItem(item,QPoint(-1,-1));
        int nUp =            CountNearItem(item,QPoint(0,-1));
        int nRightUp =        CountNearItem(item,QPoint(1,-1));
        int nRight =        CountNearItem(item,QPoint(1,0));
        int nRightDown =    CountNearItem(item,QPoint(1,1));
        int nDown =            CountNearItem(item,QPoint(0,1));
        int nLeftDown =        CountNearItem(item,QPoint(-1,1));
        if ( (nLeft + nRight) >= 4 ||
             (nLeftUp + nRightDown) >= 4 ||
             (nUp + nDown) >= 4 ||
             (nRightUp + nLeftDown) >= 4 )
        {
            QString str = mBlack? QStringLiteral("黑棋胜利!") : QStringLiteral("白棋胜利!");
            QMessageBox::information(NULL,  QStringLiteral("游戏结束"),str, QMessageBox::Ok , QMessageBox::Ok);
            mItems.clear();
            //NewGame();
            return;
        }
        //该另一方下棋了
        mBlack = !mBlack;
    }

    int MainWindow::CountNearItem(Item item,QPoint ptDirection)
    {
        int nCount = 0;
        item.mPt += ptDirection;

        while (mItems.contains(item))
        {
            nCount++;
            item.mPt += ptDirection;
        }
        return nCount;
    }



4,源码


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





liuchangyin 2018-05-21 09:41

shasidaran 2018-05-22 09:49
  

逆风微光 2018-05-25 12:35
liuchangyin:[表情]  (2018-05-21 09:41) 

谢谢支持!

逆风微光 2018-05-25 12:35
shasidaran:[表情]  [表情]  (2018-05-22 09:49) 

谢谢支持!

chrisv 2018-08-15 09:12
     好厉害,楼主辛苦了,学习学习。

逆风微光 2018-08-22 21:47
chrisv:[表情]  [表情]  [表情] 好厉害,楼主辛苦了,学习学习。 (2018-08-15 09:12) 

加油啦

unitcode 2018-11-22 09:59
挺不错的!


查看完整版本: [-- 《Qt实战小项目》2,五子棋游戏 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled