一、下棋步骤的保存
在设置保存下棋步骤之前,先定义一个bool类型的变量player用于判定是哪一方下子,设定player=true时是红方下棋,player=false时是黑方下棋。
1:要想保存下棋的步骤,必须先弄明白需要保存的信息。一个下棋步骤需要记住棋子点,落子点,被移动的棋子,若存在吃子的行为,还要记下被吃掉的是哪个棋子。一个步骤至少要包含这四个信息。可根据这些新建一个名为steps的类(使用结构体定义也是可行的)。
2:steps.h文件
class steps
{
public:steps();steps(const steps &b);steps & operator=(const steps &);int getChessman();int getKilledChessman();QPoint getSP();QPoint getDP();void setChessman(int chessman);void setKilledChessman(int killedChessman);void setSP(QPoint start);void setDP(QPoint drop);private:int chessman;//移动的棋子int killedChessman;//被吃掉的棋子QPoint startPoint;//起始点QPoint dropPoint;//落子点
};
3:steps.cpp
#include "steps.h"steps::steps()
{//初始化this->chessman=-1;this->killedChessman=-1;this->startPoint.setX(-1);this->startPoint.setY(-1);this->dropPoint.setX(-1);this->dropPoint.setY(-1);
}steps::steps( const steps &b)
{//拷贝构造函数this->chessman=b.chessman;this->killedChessman=b.killedChessman;this->startPoint=b.startPoint;this->dropPoint=b.dropPoint;
}//运算符重载
steps & steps::operator=(const steps &b)
{this->chessman=b.chessman;this->killedChessman=b.killedChessman;this->startPoint=b.startPoint;this->dropPoint=b.dropPoint;return *this;
}int steps::getChessman()
{return chessman;
}int steps::getKilledChessman()
{return killedChessman;
}QPoint steps::getSP()
{return startPoint;
}QPoint steps::getDP()
{return dropPoint;
}
void steps::setChessman(int chessman)
{this->chessman=chessman;
}
void steps::setKilledChessman(int killedChessman)
{this->killedChessman=killedChessman;
}
void steps::setSP(QPoint start)
{this->startPoint=start;
}
void steps::setDP(QPoint drop)
{this->dropPoint=drop;
}
4:将steps类定义好后就可以来实现对下棋步骤的保存,考虑到悔棋就是将最新保存的下棋步骤删除,还原到原来的棋局状态。对于下棋步骤就是先进后出的操作,所以使用栈来对步骤进行保存。
QStack<steps> chessSteps; // 走棋步数
定义一个与之相关的函数
void myWidget::saveSteps(int chessman, QPoint start, QPoint drop)
{steps step;step.setChessman(chessman);//移动棋子step.setSP(start);//起始点step.setDP(drop);//落子点if(chessmap[drop.y()][drop.x()]>30)step.setKilledChessman(chessmap[drop.y()][drop.x()]);//被吃棋子chessSteps.push(step);//入栈
}
5:修改后的mousePressEvent函数,其中的test()函数的功能是查看下棋步骤是否保存成功,属于测试使用。
//鼠标点击(按压)事件
void myWidget::mousePressEvent(QMouseEvent *event)
{QPoint point=event->pos();int w=this->width()/col;int h=this->height()/row;X=point.x()/w;//x轴对应的下标Y=point.y()/h;//y轴所对应的下标emit clicked(X,Y,mou);//发出信号if(mou==0){if((player&&chessmap[Y][X]>30&&chessmap[Y][X]<40)||(!player&&chessmap[Y][X]>40)){//player为真必须选红子,为假必须选黑子fromX=X;fromY=Y;//记下移动棋子初始位置下标chessmap[fromY][fromX]+=20;//修改为棋子点击效果图的值qDebug()<<QString("初始坐标:")<<"("<<Y<<","<<X<<")";mou=1;//第一次点击完成update();//展示出棋子的被点击效果}}else if(mou==1){chessmap[fromY][fromX]-=20;//点击效果棋子值修改为棋子值if(game_moveRule(fromX,fromY,X,Y)){start.setX(fromX);start.setY(fromY);drop.setX(X);drop.setY(Y);saveSteps(chessmap[fromY][fromX],start,drop);test();chessmap[Y][X]=chessmap[fromY][fromX];//将目标位置的值改为被移动棋子的值chessmap[fromY][fromX]=chessboardVaule[fromY][fromX];//将棋子初始位置换位棋盘的值player=!player;//转换角色qDebug()<<QString("目的坐标:")<<"("<<Y<<","<<X<<")";}mou=0;//第二次点击完成update();//重绘}
}
6:测试效果,
二、悔棋
1:将在ui文件中的pushButton作为悔棋的按钮,右击该控件,选择”转到槽“。
2:在定义一个pushButton,界面以及其text如下图所示.两个按钮都设置点击后的槽函数。
3:查看widget.h文件中出现on_pushButton_clicked和on_pushButton_2_clicked函数,可知这两个函数都是QPushButton::clicked信号对应的槽函数。
private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();
3:上述的槽函数定义在widget.h中,而悔棋操作是在对mywidget中的chessmap和chessSteps进行操作,所以在mywidget.中定义一个deleteStep()函数,在槽函数中直接调用该函数即可。悔棋时根据实际情况来看删除几个步骤
void myWidget::deleteStep(bool regret)
{int i=0;if(regret){//红方悔棋if(!player){//在对方落子之前悔棋,只恢复自己最近下的一步。且将当前落子者转换为自己i=1;player=!player;}else if(player){//当前为红方落子,在自己落子前悔棋,恢复对方最近一步棋和自己最近的一步棋if(chessSteps.size()>1)i=2;}elsei=1;}else{//黑方悔棋if(player&&chessSteps.size()>2){//在对方落子之前悔棋,只恢复自己最近下的一步。且将当前落子者转换为自己i=1;player=!player;}else if(!player&&chessSteps.size()>2)i=2;}while(i>0){if(chessSteps.size()!=0){steps step=chessSteps.top();chessmap[step.getSP().y()][step.getSP().x()]=step.getChessman();//还原起始点位置棋子值chessmap[step.getDP().y()][step.getDP().x()]=chessboardVaule[step.getDP().y()][step.getDP().x()];//还原落子点位置棋盘值if(step.getKilledChessman()>30){//存在吃子行为,就还原落子点出的棋子值chessmap[step.getDP().y()][step.getDP().x()]= step.getKilledChessman();}chessSteps.pop();//出栈//testQPoint s=step.getSP();QPoint d=step.getDP();qDebug()<<"deleted "<<i<<" step is("<<s.y()<<","<<s.x()<<")to("<<d.y()<<","<<d.x()<<")";}i--;}update();//重绘
}
//红方悔棋
void Widget::on_pushButton_clicked()
{regret=true;//悔棋者为红方ui->widget->deleteStep(regret);
}//黑方悔棋
void Widget::on_pushButton_2_clicked()
{regret=false;//悔棋者为黑方ui->widget->deleteStep(regret);
}
4:悔棋效果
下图中所圈的步骤是进行第一次悔棋后所下的一步,所展示的是悔棋后恢复的棋盘。
下图可以看到是红方和黑方一共下了四步进行的悔棋,被删除的是最近的两步。删除顺序没有出现错误,悔棋后棋盘也被正确恢复。到此悔棋的操作就完成啦
最后只剩下对棋局输赢的判定,这个双人的中国象棋游戏就基本完成啦。
Qt实现中国象棋
(八)输赢判定