利用Qt制作中国象棋小游戏
先给出效果图:
1.首先是总的文件(其中chessmovelaw文件是自定义文件,res是资源文件-包括背景,棋子的图片等)
2.widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
enum ChessType //棋子
{
NullChess,
Ju_R,
Ma_R,
Xiang_R,
Shi_R,
Jiang_R,
Pao_R,
Bing_R,
Ju_B,
Ma_B,
Xiang_B,
Shi_B,
Jiang_B,
Pao_B,
Bing_B
};
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void paintEvent(QPaintEvent * e);
//鼠标按下事件
void mousePressEvent(QMouseEvent * event);
//被选中棋子,能否从选中位置移动到当前位置
bool CanMove(int tarRow,int tarCol);
bool IsRedChess(ChessType chessType);
void IsDead();
void timerEvent(QTimerEvent *event);
int eventID1;
int d=60;
void InitChess();
void DrawChess(QPainter*p,int row,int col,ChessType type);
private:
Ui::Widget *ui;
QPoint stPos,edPos;
int W,H;
ChessType chessType[10][9];
int pressRow,pressCol;
//turn=0为红,turn=1为黑
bool turn;
};
#endif // WIDGET_H
3.棋子文件chessmovelaw.h
声明棋子走法
#ifndef CHESSMOVELAW_H
#define CHESSMOVELAW_H
#include "widget.h"
//棋子移动规则文件
class ChessMoveLaw
{
public:
static bool ChessCanMove(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
protected:
static bool MaLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool XiangLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool ShiLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool JiangLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool JuLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool PaoLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool BingLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool IsSameColor(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol);
static bool IsRedChess(ChessType chessType);
};
#endif // CHESSMOVELAW_H
4.有关棋子的函数实现chessmovelaw.cpp
实现各类棋子对应走法规则-不知道走法要先了解象棋规则
#include "chessmovelaw.h"
#include <cmath>
#include <QDebug>
bool ChessMoveLaw::ChessCanMove(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
//如果目标棋子不为空且颜色相同
if(chessType[destRow][destCol]!=NullChess && IsSameColor( chessType, sourceRow, sourceCol, destRow, destCol))
return false;
//马-规则
if(chessType[sourceRow][sourceCol]==Ma_R || chessType[sourceRow][sourceCol]==Ma_B)
{
return MaLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
//象-规则
if(chessType[sourceRow][sourceCol]==Xiang_R || chessType[sourceRow][sourceCol]==Xiang_B)
{
return XiangLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
//士-规则
if(chessType[sourceRow][sourceCol]==Shi_R || chessType[sourceRow][sourceCol]==Shi_B)
{
return ShiLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
//将-规则
if(chessType[sourceRow][sourceCol]==Jiang_R || chessType[sourceRow][sourceCol]==Jiang_B)
{
return JiangLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
//车-规则
if(chessType[sourceRow][sourceCol]==Ju_R || chessType[sourceRow][sourceCol]==Ju_B)
{
return JuLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
//炮-规则
if(chessType[sourceRow][sourceCol]==Pao_R || chessType[sourceRow][sourceCol]==Pao_B)
{
return PaoLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
//兵-规则
if(chessType[sourceRow][sourceCol]==Bing_R || chessType[sourceRow][sourceCol]==Bing_B)
{
return BingLaw( chessType, sourceRow, sourceCol, destRow, destCol);
}
return true;
}
bool ChessMoveLaw::IsRedChess(ChessType chessType)
{
if(chessType==Ju_R || chessType==Ma_R || chessType==Xiang_R || chessType==Shi_R || chessType==Pao_R || chessType==Jiang_R || chessType==Bing_R )
return true;
else
return false;
}
bool ChessMoveLaw::IsSameColor(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
if(chessType[destRow][destCol]==NullChess)
return false;
return IsRedChess(chessType[sourceRow][sourceCol])==IsRedChess(chessType[destRow][destCol]);
}
//马的走法
bool ChessMoveLaw::MaLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
if(abs(sourceRow-destRow)==1)
{
if(abs(sourceCol-destCol)!=2)
return false;
else if(chessType[sourceRow][(sourceCol+destCol)/2]!=NullChess)
return false;
else
return true;
}
else if(abs(sourceRow-destRow)==2)
{
if(abs(sourceCol-destCol)!=1)
return false;
else if(chessType[(sourceRow+destRow)/2][sourceCol]!=NullChess)
return false;
else
return true;
}
else
{
return false;
}
}
//象的走法
bool ChessMoveLaw::XiangLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
//是否过河了
if(IsRedChess(chessType[sourceRow][sourceCol]))
{
if(sourceRow<=4 && destRow<=4)
{
if(abs(sourceRow-destRow)==2)
{
if(abs(sourceCol-destCol)!=2)
return false;
else
{
if(chessType[(sourceRow+destRow)/2][(sourceCol+destCol)/2]==NullChess)
return true;
else
return false;
}
}
else
{
return false;
}
}
}
else
{
if(sourceRow>=5 && destRow>=5)
{
if(abs(sourceRow-destRow)==2)
{
if(abs(sourceCol-destCol)!=2)
return false;
else
{
if(chessType[(sourceRow+destRow)/2][(sourceCol+destCol)/2]==NullChess)
return true;
else
return false;
}
}
else
{
return false;
}
}
}
}
//士的走法
bool ChessMoveLaw::ShiLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
//是否在田字格内
if(IsRedChess(chessType[sourceRow][sourceCol]))
{
if(sourceRow>=0 &&sourceRow<=2 && sourceCol>=3 && sourceCol<=5 && destRow>=0 && destRow<=2 && destCol>=3 && destCol<=5 )
{
//斜线走
if(abs(sourceRow-destRow)==1 && abs(sourceCol-destCol)==1)
return true;
else
return false;
}
return false;
}
else
{
if(sourceRow>=7 &&sourceRow<=9 && sourceCol>=3 && sourceCol<=5 && destRow>=7 && destRow<=9 && destCol>=3 && destCol<=5 )
{
if(abs(sourceRow-destRow)==1 && abs(sourceCol-destCol)==1)
return true;
else
return false;
}
return false;
}
}
//将的走法
bool ChessMoveLaw::JiangLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
//是否在田字格内
if(IsRedChess(chessType[sourceRow][sourceCol]))
{
if(sourceRow>=0 &&sourceRow<=2 && sourceCol>=3 && sourceCol<=5 && destRow>=0 && destRow<=2 && destCol>=3 && destCol<=5 )
{
//上下左右走
if(((abs(sourceRow-destRow)==1 && abs(sourceCol-destCol)==0))||((abs(sourceRow-destRow)==0 && abs(sourceCol-destCol)==1)))
return true;
else
return false;
}
return false;
}
else
{
if(sourceRow>=7 &&sourceRow<=9 && sourceCol>=3 && sourceCol<=5 && destRow>=7 && destRow<=9 && destCol>=3 && destCol<=5 )
{
if(((abs(sourceRow-destRow)==1 && abs(sourceCol-destCol)==0))||((abs(sourceRow-destRow)==0 && abs(sourceCol-destCol)==1)))
return true;
else
return false;
}
return false;
}
if(chessType[sourceRow][sourceCol]==Jiang_R)
{
int r,c;
int m=0;
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
{
if(chessType[i][j] == Jiang_B)
{
r=i;
c=j;
}
}
if(destCol==c)
{
for(int a=destRow;a<r;a++)
{
if(chessType[a][c] != NullChess)
{
m++;
}
}
if(m==0)
qDebug()<<"黑棋获胜!";
}
}
else if(chessType[sourceRow][sourceCol]==Jiang_B)
{
int r,c;
int m=0;
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
{
if(chessType[i][j] == Jiang_R)
{
r=i;
c=j;
}
}
if(destCol==c)
{
for(int a=r;a<destRow;a++)
{
if(chessType[a][c] != NullChess)
{
m++;
}
}
if(m==0)
qDebug()<<"红棋获胜!";
}
}
}
//车的走法
bool ChessMoveLaw::JuLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
int m=0;
if(sourceRow==destRow)
{
if(sourceCol<destCol)
{
for(int i=sourceCol+1;i<destCol;i++)
if(chessType[sourceRow][i]!=NullChess)
m++;
if(m==0)
return true;
else
return false;
}
if(sourceCol>destCol)
{
for(int i=destCol+1;i<sourceCol;i++)
if(chessType[sourceRow][i]!=NullChess)
m++;
if(m==0)
return true;
else
return false;
}
}
if(sourceCol==destCol)
{
if(sourceRow<destRow)
{
for(int i=sourceRow+1;i<destRow;i++)
if(chessType[i][sourceCol]!=NullChess)
m++;
if(m==0)
return true;
else
return false;
}
if(sourceRow>destRow)
{
for(int i=destRow+1;i<sourceRow;i++)
if(chessType[i][sourceCol]!=NullChess)
m++;
if(m==0)
return true;
else
return false;
}
}
}
//炮的走法
bool ChessMoveLaw::PaoLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
int m=0;
if(sourceRow==destRow)
{
if(sourceCol<destCol)
{
//是否隔山打牛
for(int i=sourceCol+1;i<destCol-1;i++)
if(chessType[sourceRow][i]!=NullChess)
m++;
if(m==0 && chessType[destRow][destCol]==NullChess)
return true;
else if(m==1 && chessType[destRow][destCol]!=NullChess && chessType[destRow][destCol-1]!=NullChess)
{
if(IsRedChess(chessType[sourceRow][sourceCol])!=IsRedChess(chessType[destRow][destCol]))
return true;
return false;
}
else
return false;
}
if(sourceCol>destCol)
{
for(int i=destCol+1;i<sourceCol;i++)
if(chessType[sourceRow][i]!=NullChess)
m++;
if(m==0 && chessType[destRow][destCol]==NullChess)
return true;
else if(m==1 && chessType[destRow][destCol]!=NullChess && chessType[destRow][destCol+1]!=NullChess)
{
if(IsRedChess(chessType[sourceRow][sourceCol])!=IsRedChess(chessType[destRow][destCol]))
return true;
return false;
}
else
return false;
}
}
if(sourceCol==destCol)
{
if(sourceRow<destRow)
{
for(int i=sourceRow+1;i<destRow;i++)
if(chessType[i][sourceCol]!=NullChess)
m++;
if(m==0 && chessType[destRow][destCol]==NullChess)
return true;
else if(m==1 && chessType[destRow][destCol]!=NullChess && chessType[destRow-1][destCol]!=NullChess)
{
if(IsRedChess(chessType[sourceRow][sourceCol])!=IsRedChess(chessType[destRow][destCol]))
return true;
return false;
}
else
return false;
}
if(sourceRow>destRow)
{
for(int i=destRow+1;i<sourceRow;i++)
if(chessType[i][sourceCol]!=NullChess)
m++;
if(m==0 && chessType[destRow][destCol]==NullChess)
return true;
else if(m==1 && chessType[destRow][destCol]!=NullChess && chessType[destRow+1][destCol]!=NullChess)
{
if(IsRedChess(chessType[sourceRow][sourceCol])!=IsRedChess(chessType[destRow][destCol]))
return true;
return false;
}
else
return false;
}
}
}
//兵的走法
bool ChessMoveLaw::BingLaw(ChessType chessType[10][9],int sourceRow,int sourceCol,int destRow,int destCol)
{
//是否过河了
if(IsRedChess(chessType[sourceRow][sourceCol]))
{
//没有过河
if(sourceRow<=4)
{
if(destRow-sourceRow==1 && sourceCol==destCol)
return true;
else
return false;
}
//过河了
else
{
if(destRow-sourceRow==1)
return true;
else if(sourceRow==destRow)
{
if(abs(sourceCol-destCol)==1)
return true;
else
return false;
}
else
return false;
}
}
else
{
if(sourceRow>=5)
{
if(sourceRow-destRow==1 && sourceCol==destCol)
return true;
else
return false;
}
else
{
if(sourceRow-destRow==1)
return true;
else if(sourceRow==destRow)
{
if(abs(sourceCol-destCol)==1)
return true;
else
return false;
}
else
return false;
}
}
}
5.widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QRect>
#include <QDebug>
#include <QPushButton>
#include <QPoint>
#include <QMouseEvent>
#include <QFont>
#include <QDialog>
#include "chessmovelaw.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
stPos=QPoint(73,42);
edPos=QPoint(630,663);
W = (edPos.x()-stPos.x())/8;
H = (edPos.y()-stPos.y())/9;
InitChess();
//未选中棋子
pressRow=-1;
pressCol=-1;
turn=false;
//定时器
eventID1=startTimer(1000); //可自定义切换快慢
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent *event)
{
//设置字体大小
QFont font;
font.setPointSize(20);
ui->label->setFont(font);
//设置定时器-倒计时
if(event->timerId()==eventID1)
{
d--;
ui->label->move(700,20);
ui->label->resize(200,60);
QString aa="倒计时";
QString bb=QString::number(d);
ui->label->setText(aa+bb);
}
}
void Widget::paintEvent(QPaintEvent * e)
{
QPainter painter(this);
QRect rect = this->rect();
rect.setWidth(rect.width()-100);
painter.drawPixmap(rect,QPixmap(":/res/background.png"));
if(pressRow>=0 && pressCol>=0)
{
QRect r(stPos.x()+pressCol*W-0.5*W,stPos.y()+pressRow*H-0.5*H,W,H);
painter.drawPixmap(r,QPixmap(":/res/selected.png"));
}
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
{
if(chessType[i][j] != NullChess)
DrawChess(&painter,i,j,chessType[i][j]);
}
}
void Widget::mousePressEvent(QMouseEvent * event)
{
event->pos();
if(event->button()==Qt::LeftButton)
{
int row=(event->y()-stPos.y()+0.5*H)/H;
int col=(event->x()-stPos.x()+0.5*W)/W;
//选中到行和列在棋盘内的时候
if(row>=0 && row<=9 && col>=0 && col<=8)
{
//之前选中到棋子为空
if(pressRow>=0 && pressCol>=0)
{
//如果满足象棋移动规则,移动棋子
if(CanMove(row,col))
{
d=61;
chessType[row][col]=chessType[pressRow][pressCol];
chessType[pressRow][pressCol]=NullChess;
pressRow=-1;
pressCol=-1;
turn=!turn;
IsDead();
repaint();
return;
}
}
//当前选中棋子为空
if(chessType[row][col]!=NullChess)
{
//如果是红棋走且选中的是红棋,或如果是黑棋走且选中的是黑棋,把棋子选中
if((turn==false &&IsRedChess(chessType[row][col]))||(turn==true && !IsRedChess(chessType[row][col])))
{
pressRow=row;
pressCol=col;
}
repaint();
}
}
}
}
void Widget::InitChess()
{
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
{
chessType[i][j]=NullChess;
}
chessType[0][0]=Ju_R;
chessType[0][1]=Ma_R;
chessType[0][2]=Xiang_R;
chessType[0][3]=Shi_R;
chessType[0][4]=Jiang_R;
chessType[9][0]=Ju_B;
chessType[9][1]=Ma_B;
chessType[9][2]=Xiang_B;
chessType[9][3]=Shi_B;
chessType[9][4]=Jiang_B;
for(int i=0;i<4;i++)
{
chessType[0][8-i]=chessType[0][i];
chessType[9][8-i]=chessType[9][i];
}
chessType[2][1]=Pao_R;
chessType[2][7]=Pao_R;
chessType[7][1]=Pao_B;
chessType[7][7]=Pao_B;
chessType[3][0]=Bing_R;
chessType[3][2]=Bing_R;
chessType[3][4]=Bing_R;
chessType[3][6]=Bing_R;
chessType[3][8]=Bing_R;
chessType[6][0]=Bing_B;
chessType[6][2]=Bing_B;
chessType[6][4]=Bing_B;
chessType[6][6]=Bing_B;
chessType[6][8]=Bing_B;
}
void Widget::DrawChess(QPainter*p,int row,int col,ChessType type)
{
QPixmap pix;
switch (type)
{
case Ju_R:
pix=QPixmap(":/res/rr.png");
break;
case Ma_R:
pix=QPixmap(":/res/rn.png");
break;
case Xiang_R:
pix=QPixmap(":/res/rb.png");
break;
case Shi_R:
pix=QPixmap(":/res/ra.png");
break;
case Jiang_R:
pix=QPixmap(":/res/rk.png");
break;
case Pao_R:
pix=QPixmap(":/res/rc.png");
break;
case Bing_R:
pix=QPixmap(":/res/rp.png");
break;
case Ju_B:
pix=QPixmap(":/res/br.png");
break;
case Ma_B:
pix=QPixmap(":/res/bn.png");
break;
case Xiang_B:
pix=QPixmap(":/res/bb.png");
break;
case Shi_B:
pix=QPixmap(":/res/ba.png");
break;
case Jiang_B:
pix=QPixmap(":/res/bk.png");
break;
case Pao_B:
pix=QPixmap(":/res/bc.png");
break;
case Bing_B:
pix=QPixmap(":/res/bp.png");
break;
default:
break;
}
QRect r(stPos.x()+col*W-0.5*W,stPos.y()+row*H-0.5*H,W,H);
p->drawPixmap(r,pix);
}
bool Widget::CanMove(int tarRow,int tarCol)
{
if(pressRow>=0 && pressCol>=0)
{
return ChessMoveLaw::ChessCanMove(chessType,pressRow,pressCol,tarRow,tarCol);
}
return false;
}
bool Widget::IsRedChess(ChessType chessType)
{
if(chessType==Ju_R || chessType==Ma_R || chessType==Xiang_R || chessType==Shi_R || chessType==Pao_R || chessType==Jiang_R || chessType==Bing_R )
return true;
else
return false;
}
void Widget::IsDead()
{
int red=0;
int black=0;
for(int i=0;i<10;i++)
{
for(int j=0;j<9;j++)
{
if(chessType[i][j]==Jiang_R)
red++;
else if(chessType[i][j]==Jiang_B)
black++;
}
}
if(red==0)
{
QFont font;
font.setPointSize(20);
ui->label_2->setFont(font);
ui->label_2->resize(200,60);
QString w="黑方获胜!!";
ui->label_2->move(700,80);
ui->label_2->setText(w);
}
else if(black==0)
{
QFont font;
font.setPointSize(20);
ui->label_2->setFont(font);
ui->label_2->resize(200,60);
QString w="红方获胜!!";
ui->label_2->move(700,80);
ui->label_2->setText(w);
}
else
return;
}
6.ui界面
如果有更好写法,请自行改进。