在上一节中实现了走棋,这篇博客将介绍中国象棋中的走棋规则
在写博客前先可能一下象棋的走棋规则:
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<=5 if(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格时 //返回false if(d != 11) { return false; } //推断士是否出了九宫 //红色的士和黑色的士的x坐标的范围都是3<=x<=5 if(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格时 //返回false if(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