开发需求:实现一个单机版双人五子棋对战游戏,棋盘大小800*800,网格大小40*40,,棋子大小半径40的圆,玩法:玩家1执黑棋,玩家2执白棋,每回合玩家有一次下棋机会,在玩家成功连上5个棋子时(水平、竖直、倾斜方向连接5个都算玩家胜利)显示玩家游戏胜利,并重新开始。
开发文档:棋盘的实现使用qt的绘制函数实现,玩家的落子标记和落子选择使用qt的鼠标事件。
用一个变量存储当前玩家,为了区分绘制棋子的颜色。
用一个数组存储所有棋子的位置,为了绘制棋盘上所有的棋子。
用一个数组存储棋子属于哪个玩家。是为了最后判断输赢时用的。
要落子位置的判断:根据鼠标当前位置与所在网格的四个点的距离判断,取最小距离的那个网格点。
输赢的判断:以当前落子位置为中心水平、竖直、斜上、斜下方向分别判断是否有5子位置相邻。
上源码:.h
#include <QMainWindow>
#include <QMouseEvent>
#include <QMap>
#include <QtAlgorithms>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
// 绘制
void paintEvent(QPaintEvent *event) override;
// 监听鼠标移动情况,方便落子
void mouseMoveEvent(QMouseEvent *event) override;
// 实际落子
void mouseReleaseEvent(QMouseEvent *event) override;
private slots:
//void on_actionReStart_triggered();
private:
void playerCheck(bool player1,bool player2);
void reStart();
bool currentPlayerIsWin();
private:
Ui::MainWindow *ui;
QPoint chessmanPosition;//棋子的位置
QPoint mouseHovePosition;//要落子的位置
QVector<QPoint> haveChessmanVtr; //有棋子的数组
QVector<QString> chessPlayervtr;
bool isPlayer1;
bool isPlayer2;
QString currentPlayer;
};
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainter>
#include <QMessageBox>
const int m_width= 800;
const int m_height= 800;
const int m_space= 40;
const int radius=40;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setGeometry(600,200,m_width,m_height);
this->setAttribute(Qt::WA_Hover,true);
this->setMouseTracking(true);
isPlayer1=true;
isPlayer2=false;
currentPlayer="Player1";
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// 绘制棋盘
painter.setRenderHint(QPainter::Antialiasing, true);
painter.drawLine(QPoint(0,0),QPoint(10,0));
for(int i=0;i<m_height/m_space;i++)
{
painter.drawLine(QPoint(0,i*m_space),QPoint(m_width,i*m_space));
}
for(int j=0;j<m_width/m_space;j++)
{
painter.drawLine(QPoint(j*m_space,0),QPoint(j*m_space,m_height));
}
//鼠标悬停 画棋子标记
{
painter.drawRect(mouseHovePosition.x()-10,mouseHovePosition.y()-10,20,20);
}
//画棋子 棋子位置应该是鼠标位置-棋子半径/2
{
QBrush brush; //画刷
for(int i=0;i<haveChessmanVtr.size();i++)
{
if(0==chessPlayervtr[i].compare("Player1"))
{
brush.setColor(QColor(0,0,0));//设置填充颜色
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
}
else
{
brush.setColor(QColor(255,255,255));//设置填充颜色
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
}
painter.drawEllipse(haveChessmanVtr[i].x()-m_space/2,haveChessmanVtr[i].y()-m_space/2,radius,radius);
}
}
//判断输赢
{
//所有棋子填完啦,平局
if(haveChessmanVtr.size()>=(m_width/m_space+1)*(m_height/m_space+1))
{
qDebug()<<"tie game";
}
else if(currentPlayerIsWin())
{
if(currentPlayer=="Player1")
{
int result=QMessageBox::information(this, tr("恭喜"), "Player2 is win");
if (result == QMessageBox::Ok)
{
reStart();
}
}
else
{
int result = QMessageBox::information(this, tr("恭喜"), "Player1 is win");
if (result == QMessageBox::Ok)
{
reStart();
}
}
}
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
int x=event->pos().x();
int y=event->pos().y();
//判断鼠标周围的四点与鼠标悬停的距离
//左上角
QPoint leftTopPoistion;
leftTopPoistion.setX(x/m_space*m_space);
leftTopPoistion.setY(y/m_space*m_space);
int leftTop=QPoint::dotProduct(leftTopPoistion,event->pos());
//左下角
QPoint leftBottomPoistion;
leftBottomPoistion.setX(x/m_space*m_space);
leftBottomPoistion.setY(y/m_space*m_space+m_space);
int leftBottom=QPoint::dotProduct(leftBottomPoistion,event->pos());
//右上角
QPoint rightTopPoistion;
rightTopPoistion.setX(x/m_space*m_space+m_space);
rightTopPoistion.setY(y/m_space*m_space);
int rightTop=QPoint::dotProduct(rightTopPoistion,event->pos());
//右下角
QPoint rightBottomPoistion;
rightBottomPoistion.setX(x/m_space*m_space+m_space);
rightBottomPoistion.setY(y/m_space*m_space+m_space);
int rightBottom=QPoint::dotProduct(rightBottomPoistion,event->pos());
QMap<int,QPoint> map;
map[leftTop]=leftTopPoistion;
map[leftBottom]=leftBottomPoistion;
map[rightTop]=rightTopPoistion;
map[rightBottom]=rightBottomPoistion;
QVector<int> vtr;
vtr.append(leftTop);
vtr.append(leftBottom);
vtr.append(rightTop);
vtr.append(rightBottom);
qSort(vtr.begin(),vtr.end());
//让落子位置处于距离最小的那个角上
mouseHovePosition=map[vtr[0]];
update();
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
chessmanPosition=mouseHovePosition;
if(haveChessmanVtr.count(chessmanPosition)>0)
{
return;
}
haveChessmanVtr.append(chessmanPosition);
chessPlayervtr.append(currentPlayer);
update();
if(isPlayer1)
{
playerCheck(false,true);
}
else
{
playerCheck(true,false);
}
}
void MainWindow::playerCheck(bool player1, bool player2)
{
isPlayer1=player1;
isPlayer2=player2;
if(isPlayer1)
{
currentPlayer="Player1";
}
else
{
currentPlayer="Player2";
}
}
void MainWindow::reStart()
{
haveChessmanVtr.clear();
chessPlayervtr.clear();
isPlayer1=true;
isPlayer2=false;
currentPlayer="Player1";
update();
}
bool MainWindow::currentPlayerIsWin()
{
//以当前棋子开始,分别计算水平方向、竖直方向、斜方向
//遍历水平方向 起始位置:当前位置左侧4个,终止位置:当前位置右侧4个
int horizontalStartX=chessmanPosition.x()-4*m_space;
QPoint horizontalStartPosition;
horizontalStartPosition.setX(horizontalStartX);
horizontalStartPosition.setY(chessmanPosition.y());
int chessmanCount=0;
for(int i=0;i<9;i++)
{
QPoint tempPoint=QPoint(horizontalStartPosition.x()+i*m_space,horizontalStartPosition.y());
if(haveChessmanVtr.count(tempPoint)>0)
{
int index=haveChessmanVtr.indexOf(tempPoint);
if(chessPlayervtr[index]!=currentPlayer)
{
chessmanCount++;
if(chessmanCount==5)
{
return true;
}
}
else
{
chessmanCount = 0;
}
}
}
//竖直方向 起始位置:当前位置上面4个,终止位置:当前位置下面4个
int verticalStartY=chessmanPosition.y()-4*m_space;
QPoint verticalStartPosition;
verticalStartPosition.setX(chessmanPosition.x());
verticalStartPosition.setY(verticalStartY);
chessmanCount=0;
for(int i=0;i<9;i++)
{
QPoint tempPoint=QPoint(verticalStartPosition.x(),verticalStartPosition.y()+i*m_space);
if(haveChessmanVtr.count(tempPoint)>0)
{
int index=haveChessmanVtr.indexOf(tempPoint);
if(chessPlayervtr[index]!=currentPlayer)
{
chessmanCount++;
if(chessmanCount==5)
{
return true;
}
}
else
{
chessmanCount = 0;
}
}
}
//斜上方向,起始位置:当前位置左下4个位置,终止位置:右上4个位置
//Oblique upward direction;
int obliqueUpwardStartX=chessmanPosition.x()-4*m_space;
int obliqueUpwardStartY=chessmanPosition.y()+4*m_space;
QPoint obliqueUpwardPosition;
obliqueUpwardPosition.setX(obliqueUpwardStartX);
obliqueUpwardPosition.setY(obliqueUpwardStartY);
chessmanCount=0;
for(int i=0;i<9;i++)
{
QPoint tempPoint=QPoint(obliqueUpwardPosition.x()+i*m_space,obliqueUpwardPosition.y()-i*m_space);
if(haveChessmanVtr.count(tempPoint)>0)
{
int index=haveChessmanVtr.indexOf(tempPoint);
if(chessPlayervtr[index]!=currentPlayer)
{
chessmanCount++;
qDebug()<<chessmanCount;
if(chessmanCount==5)
{
return true;
}
}
else
{
chessmanCount = 0;
}
}
}
//斜下方向,起始位置:当前位置左上5个位置,终止位置:右下5个位置
//Oblique upward direction;
int obliqueDownStartX=chessmanPosition.x()-4*m_space;
int obliqueDownStartY=chessmanPosition.y()+4*m_space;
QPoint obliqueDownPosition;
obliqueDownPosition.setX(obliqueDownStartX);
obliqueDownPosition.setY(obliqueDownStartY);
chessmanCount=0;
for(int i=0;i<9;i++)
{
QPoint tempPoint=QPoint(obliqueDownPosition.x()+i*m_space,obliqueDownPosition.y()+i*m_space);
if(haveChessmanVtr.count(tempPoint)>0)
{
int index=haveChessmanVtr.indexOf(tempPoint);
if(chessPlayervtr[index]!=currentPlayer)
{
chessmanCount++;
if(chessmanCount==5)
{
return true;
}
}
else
{
chessmanCount = 0;
}
}
}
return false;
}
//void MainWindow::on_actionReStart_triggered()
//{
// reStart();
//}