在上一节中实现了走棋,这篇博客将介绍中国象棋中的走棋规则
在写博客前先可能一下象棋的走棋规则:
1)将
将的坐标关系:横坐标相等,纵坐标相减绝对值等于1,或者纵坐标相等,横坐标相减绝对值等于1
将的特殊要求:目标坐标坐落于九宫内
将的例外情况:假设两个老将面对面而中间没有棋子阻拦。老将能够直接飞到对方九宫吃对方老将
2)士
士的坐标关系:纵坐标和横坐标相减的绝对值都是1,
士的特殊要求:目标坐标坐落于九宫内
3)象
象的坐标关系:纵坐标和横坐标相减的绝对值都是2
象的特殊要求:象眼不能有棋子,不能过河
4)车
车的坐标关系:横坐标或者纵坐标相等
车的特殊要求:两个坐标之间不能有棋子存在
5)马
马的坐标关系:横坐标相减等于1且纵坐标相减等于2,或者反过来
马的特殊要求:马腿不能憋着
6)炮
炮的坐标关系:与车同样
炮的特殊要求:假设目标坐标没有棋子,则与车一样,否则要求中间有一个棋子
7)兵
过河前:
兵的坐标关系:纵坐标相差1,并且仅仅能前进
兵的特殊要求:没有
过河后:
兵的坐标关系:纵坐标相差1或者横坐标相差1。不能后退
兵的特殊要求:没有
实现代码:
首先在在SceneGame类中定义一个成员函数canMove(int moveid, int killid, int x, int y)用于实现走棋规则
//走棋规则
bool SceneGame::canMove(int moveid, int killid, int x, int y)
{//获得选中的棋子Stone* s = _s[moveid];//棋子的类型switch(s->getType()){//将的走棋规则case Stone::JIANG:{return canMoveJiang(moveid, killid, x, y);}break;//士的走棋规则case Stone::SHI:{return canMoveShi(moveid, x, y);}break;//相的走棋规则case Stone::XIANG:{return canMoveXiang(moveid, x, y);}break;//车的走棋规则case Stone::CHE:{return canMoveChe(moveid, x, y);}break;//马的走棋规则case Stone::MA:{return canMoveMa(moveid, x, y);}break;//炮的走棋规则case Stone::PAO:{return canMovePao(moveid, killid, x, y);}break;//兵的走棋规则case Stone::BING:{return canMoveBing(moveid, x, y);}break;default:{break;}}return false;
}
然后针对不同的棋子定义成员函数。实现走棋规则
canMoveJiang(int moveid, int killid, int x, int y)实现将的走棋规则
//将的走棋规则
bool SceneGame::canMoveJiang(int moveid, int killid, int x, int y)
{Stone* skill = _s[killid];//将的走棋规则://1、一次走一格//2、不能出九宫格//CCLog("x=%d, y=%d", x, y);//CCLog("moveid=%d, killid=%d", moveid, killid);//将的对杀if(skill->getType() == Stone::JIANG){return canMoveChe(moveid, x, y);}//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得将当前的位置int xo = s->getX();int yo = s->getY();//获得将走的格数//(x,y)表示将走到的位置int xoff = abs(xo - x);int yoff = abs(yo - y);int d = xoff*10 + yoff;//走将的时候有两种情况//xoff=1, yoff=0:将向左或向右//xoff=0, yoff=1:将向前或向后if(d != 1 && d != 10){return false;}//推断将是否出了九宫//红色的将和黑色的将的x坐标的范围都是3<=x<=5if(x<3 || x>5){return false;}//假设玩家的棋子是红棋if(_redSide == s->getRed()){//推断将是否出了九宫if(y<0 || y>2){return false;}}else//推断黑色的将的范围{//推断将是否出了九宫if(y>9 || y<7){return false;}}return true;
}
canMoveShi(int moveid, int x, int y)实现士的走棋规则
//士的走棋规则
bool SceneGame::canMoveShi(int moveid, int x, int y)
{//士的走棋规则://1、一次走一格//2、不能出九宫格//3、斜着走//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得相走棋前的位置int xo = s->getX();int yo = s->getY();//获得相走的格数//(x,y)表示将走到的位置int xoff = abs(xo - x);int yoff = abs(yo - y);int d = xoff*10 + yoff;//士每走一步x方向走1格,y方向走1格//当走的格数大于1格时//返回falseif(d != 11){return false;}//推断士是否出了九宫//红色的士和黑色的士的x坐标的范围都是3<=x<=5if(x<3 || x>5){return false;}//假设玩家的棋子是红棋if(_redSide == s->getRed()){//推断士是否出了九宫if(y<0 || y>2){return false;}}else//推断黑色的士的范围{//推断士是否出了九宫if(y>9 || y<7){return false;}}return true;
}
canMoveXiang(int moveid, int x, int y)实现相的走棋规则
//相的走棋规则
bool SceneGame::canMoveXiang(int moveid, int x, int y)
{//相的走棋规则://每走一次x移动2格,y移动2格//不能过河//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得相走棋前的位置int xo = s->getX();int yo = s->getY();//获得相走的格数//(x,y)表示将走到的位置int xoff = abs(xo - x);int yoff = abs(yo - y);int d = xoff*10 + yoff;//相每一次x方向走2格子,y方向走2格//当走的格数大于2格时//返回falseif(d != 22){return false;}//计算两个坐标的中点坐标int xm = (xo + x) / 2;int ym = (yo + y) / 2;//得到(xm,ym)上的棋子int id = getStone(xm, ym);//当(xm,ym)上有棋子的时候if(id != -1){//不能走相return false;}//限制相不能过河//假设玩家的棋子是红棋if(_redSide == s->getRed()){//推断相是否过了河if(y > 4){return false;}}else//推断黑色的相的范围{//推断相是否过了河if(y < 5){return false;}}return true;
}
canMoveChe(int moveid, int x, int y)实现车的走棋规则
//车的走棋规则
bool SceneGame::canMoveChe(int moveid, int x, int y)
{//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得车走棋前的位置int xo = s->getX();int yo = s->getY();//当两点之间有棋子的时候车不能走if(getStoneCount(xo,yo,x,y) != 0){return false;}return true;
}
canMoveMa(int moveid, int x, int y)实现马的走棋规则
//马的走棋规则
bool SceneGame::canMoveMa(int moveid, int x, int y)
{//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得马走棋前的位置int xo = s->getX();int yo = s->getY();//CCLog("xo=%d", xo);//CCLog("yo=%d", yo);//获得马走的格数//(x,y)表示马走到的位置//马有两种情况://第一种情况:马先向前或向后走1步,再向左或向右走2步//另外一种情况:马先向左或向右走1不,再向前或向后走2步int xoff = abs(xo-x);int yoff = abs(yo-y);//CCLog("x=%d", x);//CCLog("y=%d", y);int d = xoff*10 + yoff;//CCLog("d=%d", d);if(d != 12 && d != 21) {return false;}int xm, ym;//记录绑脚点坐标if(d == 12)//当马走的是第一种情况{xm = xo;//绑脚点的x坐标为走棋前马的x坐标ym = (yo + y) / 2;//绑脚点的y坐标为走棋前马的y坐标和走棋后马的y坐标的中点坐标}else//当马走的是另外一种情况{xm = (xo + x) / 2;//绑脚点的x坐标为走棋前马的x坐标和走棋后马的x坐标的中点坐标ym = yo;;//绑脚点的y坐标为走棋前马的y坐标}//CCLog("xm=%d", xm);//CCLog("ym=%d", ym);//当绑脚点有棋子时,不能走if(getStone(xm, ym) != -1) {return false;}return true;
}
canMovePao(int moveid, int killid, int x, int y)实现炮的走棋规则
//炮的走棋规则
bool SceneGame::canMovePao(int moveid, int killid, int x, int y)
{//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得炮走棋前的位置int xo = s->getX();int yo = s->getY();//当触摸点上有一个棋子//并且两点之间仅仅有一个棋子的时候//炮吃掉触摸点上的棋子if(killid != -1 && this->getStoneCount(xo,yo,x,y) == 1){return true;}if(killid == -1 && this->getStoneCount(xo, yo, x, y) == 0) {return true;}return false;
}
canMoveBing(int moveid, int x, int y)实现兵的走棋规则
//兵的走棋规则
bool SceneGame::canMoveBing(int moveid, int x, int y)
{//兵的走棋规则://1、一次走一格//2、前进一格后不能后退//3、过河后才干够左右移动//通过棋子的ID得到棋子Stone* s = _s[moveid];//获得将当前的位置int xo = s->getX();int yo = s->getY();//获得兵走的格数//(x,y)表示将走到的位置int xoff = abs(xo - x);int yoff = abs(yo - y);int d = xoff*10 + yoff;//走将的时候有两种情况//xoff=1, yoff=0:将向左或向右//xoff=0, yoff=1:将向前或向后if(d != 1 && d != 10){return false;}//假设玩家的棋子是红棋if(_redSide == s->getRed()){//限制红色的兵不能后退if(y < yo){return false;}//红色的兵没有过河不能左右移动if(yo <= 4 && y == yo){return false;}}else//推断黑色的兵{//限制黑色的兵不能后退if(y > yo){return false;}//黑色的兵没有过河不能左右移动if(yo >= 5 && y == yo){return false;}}return true;
}
getStoneCount(int xo, int yo, int x, int y)推断两个棋子之间棋子的个数,用于车和炮以及将的对杀
///计算(xo,yo)和(x,y)之间的棋子数
//假设棋子数为-1,表示(xo,yo)和(x,y)不在一条直线上
int SceneGame::getStoneCount(int xo, int yo, int x, int y)
{int ret = 0;//记录两点之间的棋子的个数//(xo,yo)和(x,y)不在同一条直线上if(xo != x && yo != y){return -1;}//(xo,yo)和(x,y)在同一点上if(xo == x && yo == y){return -1;}//两点在同一条竖线上if(xo == x){//min为两个点中y坐标最小的点的y坐标int min = yo < y ?
yo : y; //max为两个点中y坐标最大的点的y坐标 int max = yo > y ? yo : y; //查找同一条竖线上两点之间的棋子数 for(int yy=min+1; yy<max; yy++) { //当两点之间有棋子的时候 if(getStone(x,yy) != -1) { ++ret;//棋子数加1 } } } else//两点在同一条横线上yo == y { //min为两个点中x坐标最小的点的x坐标 int min = xo < x ? xo : x; //max为两个点中x坐标最大的点的x坐标 int max = xo > x ? xo : x; //查找同一条竖线上两点之间的棋子数 for(int xx=min+1; xx<max; xx++) { //当两点之间有棋子的时候 if(getStone(xx,y) != -1) { ++ret;//棋子数加1 } } } //返回两点之间的棋子数 return ret; }
參考文章:http://blog.csdn.net/itcastcpp/article/details/17673393