Cocos2d-X开发中国象棋《九》走棋规则

上一节中实现了走棋,这篇博客将介绍中国象棋中的走棋规则


在写博客前先可能一下象棋的走棋规则:

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


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值