QT实现的人机对战五子棋

这是一个使用QT框架实现的五子棋游戏,支持人机对战和双人模式。代码中包括游戏界面绘制、鼠标事件处理和棋盘逻辑。玩家可以自由选择与电脑对战或者与其他玩家对弈,游戏界面简洁易操作。

QT实现的人机对战五子棋

QT实现的人机对战五子棋,支持双人模式和AI模式。界面简洁,操作方便。
QT五子棋.gif

部分代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMouseEvent>
#include<QPainter>
#include<math.h>
#include<QMessageBox>
#include<QTimer>
#include<QPushButton>
#include"settingdialog.h"

MainWindow::MainWindow(QWidget *parent)//窗口一创建就调用的构造
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{


    //设置窗口大小
    setFixedSize(MARGIN*2+BLOCK_SIZE*BOARD_GRAD_SIZE,
                 MARGIN*2+BLOCK_SIZE*BOARD_GRAD_SIZE);//宽和高,左右边界+棋子大小*尺寸

/*   QAction *actionPVE = new QAction("Person VS Computer", this);
    connect(actionPVE, SIGNAL(triggered()), this, SLOT(initPVEGame()));
    gameMenu->addAction(actionPVE);*/

    setMouseTracking(true);
    initGame();//开始游戏
}
MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *event)//实现绘制方法
{
    QPainter painter(this);
    //绘制棋盘
    painter.setRenderHint(QPainter::Antialiasing,true);//抗锯齿

    for(int i=0;i<BOARD_GRAD_SIZE+1;i++)//15行有16条线,所以+1
        {
        //从左到右,第i+1条竖线
        painter.drawLine(MARGIN+BLOCK_SIZE*i,MARGIN,
                         MARGIN+BLOCK_SIZE*i,size().height()-MARGIN);//起始坐标和终点坐标x1,y1 x2,y2!
        //从上到下,第i+1条横线
        painter.drawLine(MARGIN,MARGIN+BLOCK_SIZE*i,
                         size().width()-MARGIN,MARGIN+BLOCK_SIZE*i);
    }
    //绘制选中点
    QBrush brush;
    brush.setStyle(Qt::SolidPattern);//不透明
    //绘制落子标记(防止鼠标出框越界)
    if(clickPosRow>0&&clickPosRow<BOARD_GRAD_SIZE&&
       clickPosCol>0&&clickPosCol<BOARD_GRAD_SIZE&&
            game->mygameMap[clickPosRow][clickPosCol]==0)
    {
        if(game->playerFlag)
            brush.setColor(Qt::black);
        else
            brush.setColor(Qt::white);
        painter.setBrush(brush);
        painter.drawRect(MARGIN+BLOCK_SIZE*clickPosCol-MARK_SIZE/2,MARGIN+BLOCK_SIZE*clickPosRow-MARK_SIZE/2,MARK_SIZE,MARK_SIZE);

    }
    //绘制棋子
    for(int i=0;i<BOARD_GRAD_SIZE;i++){
         for(int j=0;j<BOARD_GRAD_SIZE;j++)
           {
        if(game->mygameMap[i][j]==1)
        {
            brush.setColor(Qt::black);
            painter.setBrush(brush);
            painter.drawEllipse(MARGIN+BLOCK_SIZE*j-CHESS_R,MARGIN+BLOCK_SIZE*i-CHESS_R,CHESS_R*2,CHESS_R*2);
             }
        else if(game->mygameMap[i][j]==-1)
        {
            brush.setColor(Qt::white);
            painter.setBrush(brush);
            painter.drawEllipse(MARGIN+BLOCK_SIZE*j-CHESS_R,MARGIN+BLOCK_SIZE*i-CHESS_R,CHESS_R*2,CHESS_R*2);
            }
        }
    }
    //判断输赢
    if(clickPosRow>0&&clickPosRow<BOARD_GRAD_SIZE&&
       clickPosCol>0&&clickPosCol<BOARD_GRAD_SIZE&&
       (game->mygameMap[clickPosRow][clickPosCol]==1||
            game->mygameMap[clickPosRow][clickPosCol]==-1))
    {
        if(game->isWin(clickPosRow,clickPosCol)&&game->gameStatus==PLAYING)
        {
            game->gameStatus=WIN;
            QString str;
            if(game->mygameMap[clickPosRow][clickPosCol]==1)
                str="黑棋";
            else if(game->mygameMap[clickPosRow][clickPosCol]==-1)
                str="白棋";
            QMessageBox::StandardButton bthValue =QMessageBox::information(this,"五子棋对战",str+"胜利!!");
            //重置游戏状态,否则容易死循环
            if(bthValue==QMessageBox::Ok)
            {
                game->startGame(game_type);
                game->gameStatus=PLAYING;//重置游戏
            }

        }
    }
}

void MainWindow::initGame()
{
    //初始化游戏模型
    game = new GameModel;
    SettingDialog dlg;
    if(dlg.Accepted)
    if(dlg.exec() == QDialog::Accepted){
        if(dlg.model == 0){
            initPersonGame();
        }else{
            initAIGame();
        }
    }else{
        initPersonGame();
    }
}

void MainWindow::initPersonGame()
{
    game_type=MAN;//人人模式
    game->gameStatus=PLAYING;//正在玩
    game->startGame(game_type);//启动游戏,在数据模型里初始化
    update();
}
void MainWindow::initAIGame()
{
    game_type=AI;//ai模式
    game->gameStatus=PLAYING;//正在玩
    game->startGame(game_type);//启动游戏,在数据模型里初始化
    update();
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    //通过鼠标的盘旋确定落子的标记
    int x=event->x();
    int y=event->y();
    //棋盘边缘不能落子
    if(x>=MARGIN+BLOCK_SIZE/2&&
            x<size().width()-MARGIN-BLOCK_SIZE/2&&
            y>MARGIN+BLOCK_SIZE/2&&
            y<size().height()-MARGIN-BLOCK_SIZE/2)
        {
        //获取最近的左上角的点
        int col=(x-MARGIN)/BLOCK_SIZE;
        int row=(y-MARGIN)/BLOCK_SIZE;
        int leftTopPosX=MARGIN+BLOCK_SIZE*col;
        int leftTopPosY=MARGIN+BLOCK_SIZE*row;
        //根据鼠标到四个点的距离选择半径最短的
        clickPosRow=-1;
        clickPosCol=-1;//初始化
        int len=0;//计算后取整
        selectPos=false;//表示有没有选成功
        len=sqrt((x-leftTopPosX)*(x-leftTopPosX)+(y-leftTopPosY)*(y-leftTopPosY));//四种情况表示到四个点距离以判断哪个点需要响应
        if(len<POS_OFFSET)
        {
            clickPosRow=row;
            clickPosCol=col;
            if(game->mygameMap[clickPosRow][clickPosCol]==0){//选中的地方要有棋子
                selectPos=true;
            }
        }
        len=sqrt((x-leftTopPosX-BLOCK_SIZE)*(x-leftTopPosX-BLOCK_SIZE)+(y-leftTopPosY)*(y-leftTopPosY));
        if(len<POS_OFFSET)
        {
            clickPosRow=row;
            clickPosCol=col+1;
            if(game->mygameMap[clickPosRow][clickPosCol]==0){//选中的地方要有棋子
                selectPos=true;
            }
        }
        len=sqrt((x-leftTopPosX)*(x-leftTopPosX)+(y-leftTopPosY-BLOCK_SIZE)*(y-leftTopPosY-BLOCK_SIZE));
        if(len<POS_OFFSET)
        {
            clickPosRow=row+1;
            clickPosCol=col;
            if(game->mygameMap[clickPosRow][clickPosCol]==0){//选中的地方要有棋子
                selectPos=true;
            }
        }
        len=sqrt((x-leftTopPosX-BLOCK_SIZE)*(x-leftTopPosX-BLOCK_SIZE)+(y-leftTopPosY-BLOCK_SIZE)*(y-leftTopPosY-BLOCK_SIZE));
        if(len<POS_OFFSET)
        {
            clickPosRow=row+1;
            clickPosCol=col+1;
            if(game->mygameMap[clickPosRow][clickPosCol]==0){//选中的地方要有棋子
                selectPos=true;
            }
        }


    }
    //重绘
    update();
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{

    if(selectPos==false){
        return;//如果之前没选成功,就返回,即不会落子
    }
    else{
        selectPos=false;//如果选成功了,马上要落子,把落子标记再标记为假,相当于将他失效
    }
 PersonNow(); //人下棋

    if(game_type==AI){//人机模式
        QTimer::singleShot(AI_THINK_TIME,this,SLOT(AINow()));//thinktime之后调用,调用this窗体的AINow方法
         }


}
void MainWindow::PersonNow()
{
    //根据当前存储的坐标下子
    //只有有效点击才下子,并且该处无字
    if(clickPosRow!=-1&&clickPosCol!=-1&&game->mygameMap[clickPosRow][clickPosCol]==0)
    {
        //在数据模型里修改二维数组以达到落子目的
        game->TurnToPerson(clickPosRow,clickPosCol);
        update();
    }
}
void MainWindow::AINow()
{
    game->TurnToAI(clickPosRow,clickPosCol);
    update();
}

源码下载

链接:程序源码下载链接
提取码:1111

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值