一、下棋步骤的保存
在设置保存下棋步骤之前,先定义一个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;
}
else
i=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();//出栈
//test
QPoint 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:悔棋效果
下图中所圈的步骤是进行第一次悔棋后所下的一步,所展示的是悔棋后恢复的棋盘。
下图可以看到是红方和黑方一共下了四步进行的悔棋,被删除的是最近的两步。删除顺序没有出现错误,悔棋后棋盘也被正确恢复。到此悔棋的操作就完成啦
最后只剩下对棋局输赢的判定,这个双人的中国象棋游戏就基本完成啦。