QT实现的人机对战五子棋
QT实现的人机对战五子棋,支持双人模式和AI模式。界面简洁,操作方便。
部分代码
#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