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

实现人机五子棋对战,需要将人类玩家和电脑玩家的逻辑结合起来,具体步骤如下: 1. 定义五子棋的棋盘,可以使用二维数组来表示。例如,定义一个 15 × 15 的二维数组 board 作为棋盘,每个元素表示一个交叉点的状态,0 表示该点为空,1 表示该点为黑子,2 表示该点为白子。 2. 实现人类玩家的逻辑。可以使用循环来实现游戏的交互过程,每次循环中,先由人类玩家输入下棋位置,然后检查该位置是否合法,若合法则在棋盘上放置一个黑子,并检查是否达成五子连珠的胜利条件。如果游戏结束,则跳出循环,否则进入下一个阶段。 3. 实现电脑玩家的逻辑。在每个回合中,电脑玩家需要根据当前棋盘状态计算出最优的下棋位置,可以使用 Minimax 算法或 Alpha-Beta 剪枝算法来实现 AI 算法。计算出下棋位置后,在棋盘上放置一个白子,并检查是否达成五子连珠的胜利条件。如果游戏结束,则跳出循环,否则进入下一个回合。 4. 实现 GUI 界面。使用 MFC 或者 QT 等框架来实现五子棋的图形化界面,并将棋盘和下棋逻辑结合到界面中。可以使用鼠标来实现人类玩家的下棋操作,点击棋盘上的某个位置即可下棋。 5. 调试和优化。在实现过程中,需要不断地调试和优化程序,确保程序能够正确运行,同时提高程序的效率和性能。 以上就是实现人机五子棋对战的基本步骤。需要注意的是,在实现过程中,需要处理好人类玩家和电脑玩家的交互逻辑,确保游戏的流畅性和可玩性。同时,还需要根据具体情况调整 AI 算法的参数,以提高程序的智能性和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值