zoukankan      html  css  js  c++  java
  • 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

    
  • 相关阅读:
    antd按需加载
    解决vscode开发react项目没有代码提示问题
    在react中配置less
    flutter之fluro导航传参数
    Flutter游戏:简单规则与结束页
    zsh: command not found:XXX
    React的安装与使用
    git stash 用法总结和注意点
    【OSS】工具类
    ajax将数组或list集合传到后台 的 【坑】
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7270587.html
Copyright © 2011-2022 走看看