PHP算法之斗牛游戏牛型判断

在前段时间开发了一款斗牛士游戏,前面已经说到过是采用PHP开发的,这此我将详细描述此算法的实现过程。

由于此游戏逻辑较简单,仅判断牛型大小、并对牛型进行比较,所以我决定采用type、num、count的结构来表示一张牌对象。如下:

 

<?php
/**
 * Created by PhpStorm.
 * User: LiBing
 * Date: 2017/9/28
 * Time: 10:34
 * 表示扑克牌的类
 */
    class NiuNiuCard{
        //type : 1 : 黑桃 2:红桃 3:梅花 4:方块
        public $type;
        //num: 1-13对应牌型
        public $num;
        //count:对应的点数
        public $count;

        /**
         * NiuNiuCard constructor.
         * @param $type  牌型
         * @param $num   牌号
         * @param $count 牌点数 >10都作为10
         */
        function __construct($type, $num, $count)
        {
            $this->type = $type;
            $this->num = $num;
            $this->count = $count;
        }
    }
?>

所以我们斗牛中获得的对象便是五个这样的对象构成的数组,以下是算法代码:

 

 

<?php
/**
 * Created by PhpStorm.
 * User: LiBing
 * Date: 2017/10/13
 * Time: 下午3:29
 * 用于判断牛牛的算法逻辑
 */
require_once ('NiuniuType.php');
require_once ('NiuNiuCard.php');
class NiuniuLogic{

    /**
     * 辅助函数,用于排序
     * @param $cards 卡牌的引用
     */

    public function sortPlayerCards(&$cards){
        for($i = 0; $i < 5; $i++){
            for($j = 0; $j < 4 - $i; $j++){
                if($cards[$j]->num > $cards[$j + 1]->num ||
                    ($cards[$j]->num == $cards[$j+1]->num && $cards[$j]->type < $cards[$j+1]->type)){
                    $t = $cards[$j];
                    $cards[$j] = $cards[$j+1];
                    $cards[$j+1] = $t;
                }
            }
        }
    }


    /**
     * @param $playerCards 玩家的手牌,这里假设的是以{玩家ID,Cards(array)}的方式传过来的数据
     * @param $typeSelected  允许的可选牌型的数组,用于是否开启该牌型,包含数据为
     *          canShunDou: 能否顺斗; canKanDou: 能否坎斗
     *          canTongHuaShun: 能否同花顺
     *          canZhaDanNiu: 能否炸弹牛
     *          canWuXiaoNiu: 能否五小牛
     *          canWuHuaNiu:  能否五花牛
     *          canSiHuaNiu:  能否四花牛
     *          canHuLuNiu:   能否葫芦牛
     *          canTongHuaNiu: 能否同花牛
     *          canShunZiNiu:  能否顺子牛
     * @return $resultArray 某一个玩家的结果数组,存放结果
     *          'playerID' : 对应的玩家
     *          'level': 牌的级别,按照同花顺 > 五小牛 > 五花牛 > 四花牛 > 炸弹牛 > 葫芦牛 > 同花
     *                                     > 顺子 > 牛牛 > 牛9-牛5 > 牛4-牛1 > 无牛进行排列
     *                         注意:坎斗、顺斗以及普通牛是同一级别,都看点数
     *          'levelResult': 牌的级别对应的最大牌,用于同级别的判断
     *
     */

    public function getNiuniuResult($playerCards, $typeSelected){

        $resultArray = array();//array('playerID'=>'', 'level'=>0, 'levelResult'=>'');
        for($i = 0; $i < count($playerCards); $i++){
            //初始化一个基本结果,然后和所有数据判断
            $resultArray[$i]['playerID'] = $playerCards[$i]['playerID'];
            $resultArray[$i]['level'] = -1;
            $resultArray[$i]['levelResult'] = '';
            $resultArray[$i]["douPai"]=array();

            //保存一个临时牌组,并按从小到大排序
            $cards = $playerCards[$i]['cards'];

            $this->sortPlayerCards($cards);


            //获取普通牛数据
            $r = $this->getNiuniuCount($cards);
            $this->processResult($resultArray[$i], $r);

            if($typeSelected['canShunDou']){
                //获取顺斗的数据
                $r = $this->getShunDouPoint($cards);
                $this->processResult($resultArray[$i], $r);
            }

            if($typeSelected['canCanDou']){
                //获取豹子牛数据
                $r = $this->getBaoZhiNiuPoint($cards);
                if($r["level"]==BAOZHINIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            //可能出错
            if($typeSelected['canWuHuaNiu']){
                //获取五花牛
                $r = $this->isWuHuaNiu($cards);
                if($r["level"]==WUHUANIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            if($typeSelected['canShunZiNiu']){
                //获取顺子牛数据
                $r = $this->isShunZiNiu($cards);
                if($r["level"]==SHUNZINIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            if($typeSelected['canTongHuaNiu']){
                //获取同花牛
                $r = $this->isTonghuaNiu($cards);
                if($r["level"]==TONGHUANIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            if($typeSelected['canHuLuNiu']){
                //获取葫芦牛
                $r = $this->huluNiu($cards);
                if($r["level"]==HULUNIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            if($typeSelected['canZhaDanNiu']){
                //获取炸弹牛
                $r = $this->isBoomNiu($cards);
                if($r["level"]==ZHADANNIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            if($typeSelected['canWuXiaoNiu']){
                //获取五小牛
                $r = $this->isWuXiaoNiu($cards);
                if($r["level"]==WUXIAONIU){
                    $this->processResult($resultArray[$i], $r);
                }
            }

            if($typeSelected['canTongHuaShun']){
                //获取同花顺
                $r = $this->isTongHuaShun($cards);
                if($r["level"]==TONGHUASHUN){
                    $this->processResult($resultArray[$i], $r);
                }
            }

        }
        return $resultArray;
    }

    private function processResult(&$playerResult, $newResult){
        if($playerResult['level'] < $newResult['level']){
            $playerResult['level'] = $newResult['level'];
            $playerResult['levelResult'] = $newResult['maxCard'];
            $playerResult['douPai'] = $newResult['douPai'];
        }
    }

    /**
     * 判断牛牛点数
     * @param $playerCards 玩家的手牌,这里假设的是以玩家ID=》Cards(array)的方式传过来的数据
     * @return $array:[level:牌力,maxCard: 最大牌]
     */
    public function getNiuniuCount($playerCard){
        $result = array();
        $result['douPai']=array();
        //总点数
        $cardsTotalPoint = 0;
        //计算总点数
        for($i = 0; $i < count($playerCard); $i++){
            $cardsTotalPoint += $playerCard[$i]->count;
        }
        //计算余数
        $lave = $cardsTotalPoint % 10;
        for($i = 0; $i < count($playerCard) - 1; $i++){
            for($j = $i + 1; $j < count($playerCard); $j++){
                if(($playerCard[$i]->count + $playerCard[$j]->count) % 10 == $lave){
                    //此处是有牛,则取出斗的牌
                    if($i!=0&&$j!=0){
                        array_push($result["douPai"],$playerCard[0]);
                    }
                    if($i!=1&&$j!=1){
                        array_push($result["douPai"],$playerCard[1]);
                    }
                    if($i!=2&&$j!=2){
                        array_push($result["douPai"],$playerCard[2]);
                    }
                    if($i!=3&&$j!=3){
                        array_push($result["douPai"],$playerCard[3]);
                    }
                    if($i!=4&&$j!=4){
                        array_push($result["douPai"],$playerCard[4]);
                    }

                    $result['level'] = $this->_getCount($lave);
                    $result['maxCard'] = $playerCard[4];
                    return $result;
                }
            }
        }
        $result['level'] = WUNIU;
        $result['maxCard'] = $playerCard[4];
        return $result;

    }

    /*
     * 辅助函数,用于处理牛1-牛9的细分结果处理
     * @param $lave: getNiuniuCount的余数结果
     */
    private function _getCount($lave)
    {
        switch ($lave) {
            case 0:
                return NIUNIU;
            case 1:
                return NIUNIU1;
            case 2:
                return NIUNIU2;
            case 3:
                return NIUNIU3;
            case 4:
                return NIUNIU4;
            case 5:
                return NIUNIU5;

            case 6:
                return NIUNIU6;
            case 7:
                return NIUNIU7;
            case 8:
                return NIUNIU8;
            case 9:
                return NIUNIU9;

            default:
                return -1;
        }
    }


    /**
     * 判断是否为五花牛的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array:[level: 牌力,maxCard: 最大牌]
     */
    private function isWuHuaNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());
        for($i = 0; $i < count($playerCard); $i++){
            if($playerCard[$i]->num <= 10){
                return $result;
            }
        }
        $result['level'] = WUHUANIU;
        $result['maxCard'] = $playerCard[4];
        $result['douPai'] = $playerCard;
        return $result;
    }

    /**
     * 判断是否为同花牛的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array:[level:牌力,maxCard: 最大牌]
     */
    private function isTonghuaNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());
        $type = $playerCard[0]->type;
        $isTonghua = true;
        for($i = 1; $i < count($playerCard); $i++){
            if($type != $playerCard[$i]->type){
                $isTonghua = false;
                break;
            }
        }

        if($isTonghua){
            $result['level'] = TONGHUANIU;
            $result['maxCard'] = $playerCard[4];
            $result['douPai'] = $playerCard;
        }

        return $result;
    }


    /**
     * 判断是否为同花顺牛的函数
     * @param $playerCard
     * @return array:[level:牌力, maxCard: 同花顺的最大牌]
     */
    private function isTongHuaShun($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());
        $r1 = $this->isTonghuaNiu($playerCard);
        $r2 = $this->isShunZiNiu($playerCard);
        if($r1['level'] == TONGHUANIU && $r2['level'] == SHUNZINIU){
            $result['level'] = TONGHUASHUN;
            $result['maxCard'] = $playerCard[4];
            $result['douPai'] = $playerCard;
        }

        return $result;
    }


    /**
     * 判断是否为炸弹牛的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array:[level:牌力,maxCard: 炸弹牌]
     */
    private function isBoomNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());
        //假设牌已经按照从小到大排序
        //aaaa*
        if($playerCard[0]->num == $playerCard[3]->num){
            $result['level'] = ZHADANNIU;
            $result['maxCard'] = $playerCard[0];
            array_push($result["douPai"],$playerCard[0]);
            array_push($result["douPai"],$playerCard[1]);
            array_push($result["douPai"],$playerCard[2]);
            array_push($result["douPai"],$playerCard[3]);
        }
        //*aaaa
        else if($playerCard[1]->num == $playerCard[4]->num){
            $result['level'] = ZHADANNIU;
            $result['maxCard'] = $playerCard[1];
            array_push($result["douPai"],$playerCard[1]);
            array_push($result["douPai"],$playerCard[2]);
            array_push($result["douPai"],$playerCard[3]);
            array_push($result["douPai"],$playerCard[4]);
        }
        else{
            $result['level'] = -1;
            $result['maxCard'] = '';
            $result["douPai"]=array();
        }
        return $result;
    }

    /**
     * 判断是否为五小牛的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array:[level:是否为五小牛, maxCard:最大的卡牌]
     */
    private function isWuXiaoNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());
        $totalCount = 0;
        for($i = 0; $i < count($playerCard); $i++){
            if($playerCard[$i]->num > 5){
                return $result;
            }
            else{
                $totalCount += $playerCard[$i]->num;
            }
        }

        if($totalCount <= 10 && $totalCount > 0){
            $result['level'] = WUXIAONIU;
            $result['maxCard'] = $playerCard[4];
            $result["douPai"]=$playerCard;
        }

        return $result;
    }

    /**
     * 判断是否为葫芦牌型的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array: [level:是否为葫芦牛, maxCard:葫芦的点数最大牌]
     */
    private function huluNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>0,'douPai'=>array());
        //aaabb
        if($playerCard[0]->num == $playerCard[2]->num){
            if($playerCard[3]->num == $playerCard[4]->num){
                $result['level'] = HULUNIU;
                $result['maxCard'] = $playerCard[0];
                array_push($result["douPai"],$playerCard[0]);
                array_push($result["douPai"],$playerCard[1]);
                array_push($result["douPai"],$playerCard[2]);
            }
        }
        //aabbb
        if($playerCard[2]->num == $playerCard[4]->num){
            if($playerCard[0]->num == $playerCard[1]->num){
                $result['level'] = HULUNIU;
                $result['maxCard'] = $playerCard[2];
                array_push($result["douPai"],$playerCard[2]);
                array_push($result["douPai"],$playerCard[3]);
                array_push($result["douPai"],$playerCard[4]);
            }
        }
        return $result;
    }

    /**
     * 判断是否为四花型的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array:[level:是否为四花牛, maxCard:四花的最大牌]
     */
    private function isSiHuaNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'');
        $temp = true;
        for($i = 0; $i < count($playerCard); $i++){
            if($playerCard[$i]->num < 10){
                $temp = false;
                break;
            }
        }
        if($playerCard[0]->num == 10 && $temp){
            $result['level'] = SIHUANIU;
            $result['maxCard'] = $playerCard[4];
        }

        return $result;
    }

    /**
     * 判断是否为顺子牛的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $array:[level:是否为顺子牛, maxCard:顺子牛的最大牌]
     */
    private function isShunZiNiu($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());
        //abcde
        $temp=$playerCard[0]->num;
        $num=0;

        if($temp==1){
            //第一张为A
            //a 2 3 4 5
            if($playerCard[1]->num==2){
                $num++;
                for($i=2;$i<5;$i++){
                    if($playerCard[$i]->num-$i==$temp){
                        $num++;
                    }else{
                        return $result;
                    }
                }
            }else if($playerCard[1]->num==10){
                $num++;
                for($i=2;$i<5;$i++){
                    if($playerCard[$i]->num-$i+1==10){
                        $num++;
                    }else{
                        return $result;
                    }
                }
            }

            //10 J Q K A
        }else{
            for($i=1;$i<5;$i++){
                if($playerCard[$i]->num-$i==$temp){
                    $num++;
                }else{
                    return $result;
                }
            }
        }


        if($num==4){
            $result['level'] = SHUNZINIU;
            $result['maxCard'] = $playerCard[4];
            array_push($result["douPai"],$playerCard);
        }

//        if($playerCard[0]->num + 4 == $playerCard[4]->num){
//            $result['level'] = SHUNZINIU;
//            $result['maxCard'] = $playerCard[4];
//        }
        return $result;
    }

    /**
     * 获取是否为豹子牛的函数
     */
    private function getBaoZhiNiuPoint($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());

        //aaa**
        if($playerCard[0]->num == $playerCard[2]->num){
            //$count = $playerCard[3]->point + $playerCard[4]->point;
            $result['level'] = BAOZHINIU;
            $result['maxCard'] = $playerCard[4];
            array_push($result["douPai"],$playerCard[0]);
            array_push($result["douPai"],$playerCard[1]);
            array_push($result["douPai"],$playerCard[2]);
        }
        //*aaa*
        else if($playerCard[1]->num == $playerCard[3]->num){
            //$count = $playerCard[0]->point + $playerCard[4]->point;
            $result['level'] = BAOZHINIU;
            $result['maxCard'] = $playerCard[4];
            array_push($result["douPai"],$playerCard[1]);
            array_push($result["douPai"],$playerCard[2]);
            array_push($result["douPai"],$playerCard[3]);
        }
        //**aaa
        else if($playerCard[2]->num == $playerCard[4]->num){
            //$count = $playerCard[0]->point + $playerCard[1]->point;
            $result['level'] = BAOZHINIU;
            $result['maxCard'] = $playerCard[1];
            array_push($result["douPai"],$playerCard[2]);
            array_push($result["douPai"],$playerCard[3]);
            array_push($result["douPai"],$playerCard[4]);
        }
        //else{
            //$count = -1;
        //}
        //$count = $count % 10;

        //$result['level'] = BAOZHINIU;
        return $result;
    }

    /**
     * 获取是否为坎斗的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $result:[level:坎斗形成的点数, maxCard: 坎斗中的最大牌]
     */
    private function getKanDouPoint($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'');
        //aaa**
        if($playerCard[0]->num == $playerCard[2]->num){
            $count = $playerCard[3]->point + $playerCard[4]->point;
            $result['maxCard'] = $playerCard[4];
        }
        //*aaa*
        else if($playerCard[1]->num == $playerCard[3]->num){
            $count = $playerCard[0]->point + $playerCard[4]->point;
            $result['maxCard'] = $playerCard[4];
        }
        //**aaa
        else if($playerCard[2]->num == $playerCard[4]->num){
            $count = $playerCard[0]->point + $playerCard[1]->point;
            $result['maxCard'] = $playerCard[1];
        }
        else{
            $count = -1;
        }
        $count = $count % 10;

        $result['level'] = $this->_getCount($count);
        return $result;
    }

    /**
     * 获取是否为顺斗的函数
     * @param $playerCard 某一个玩家的手牌
     * @return $result:[level:顺斗形成的点数, maxCard: 顺斗中的最大牌]
     */
    private function getShunDouPoint($playerCard){
        $result = array('level'=>-1, 'maxCard'=>'','douPai'=>array());


        //枚举所有情况产生点数的数组
        $tempResult = array();
        //第一种情况abc**
        if( ($playerCard[0]->num+1 == $playerCard[1]->num) && ($playerCard[1]->num == $playerCard[2]->num - 1)){
            
            $r=array();
            array_push($r,$playerCard[0]);
            array_push($r,$playerCard[1]);
            array_push($r,$playerCard[2]);
            array_push($tempResult, array('level'=>($playerCard[3]->count + $playerCard[4]->count)%10, 'maxCard'=>$playerCard[4],'douPai'=>$r));
        }
        //第二种情况*abc*
        if (($playerCard[1]->num+1 == $playerCard[2]->num) && ($playerCard[2]->num == $playerCard[3]->num - 1)){
            
            $r=array();
            array_push($r,$playerCard[1]);
            array_push($r,$playerCard[2]);
            array_push($r,$playerCard[3]);
            array_push($tempResult, array('level'=>($playerCard[0]->count + $playerCard[4]->count)%10, 'maxCard'=>$playerCard[4],'douPai'=>$r));
        }

        //第三种情况**abc
        if (($playerCard[2]->num+1 == $playerCard[3]->num) && ($playerCard[3]->num == $playerCard[4]->num - 1)){
            $r=array();
            array_push($r,$playerCard[2]);
            array_push($r,$playerCard[3]);
            array_push($r,$playerCard[4]);
            array_push($tempResult, array('level'=>($playerCard[0]->count + $playerCard[1]->count)%10, 'maxCard'=>$playerCard[4],'douPai'=>$r));
        }

        //第四种情况abbc*
        if ($playerCard[0]->num+2 == $playerCard[3]->num && $playerCard[0]->num + 1 == $playerCard[1]->num){
            $r=array();
            array_push($r,$playerCard[0]);
            array_push($r,$playerCard[1]);
            array_push($r,$playerCard[3]);
            array_push($tempResult, array('level'=>($playerCard[4]->count + $playerCard[1]->count)%10, 'maxCard'=>$playerCard[4],'douPai'=>$r));
        }

        //第五种情况*bccd;
        if($playerCard[1]->num+2 == $playerCard[4]->num && $playerCard[3]->num + 1 == $playerCard[4]->num) {
            $r=array();
            array_push($r,$playerCard[1]);
            array_push($r,$playerCard[2]);
            array_push($r,$playerCard[4]);
            array_push($tempResult, array('level'=>($playerCard[0]->count + $playerCard[2]->count)%10, 'maxCard'=>$playerCard[3],'douPai'=>$r));
        }

        //第六种情况aabbc;
        if(($playerCard[0]->num+1 == $playerCard[2]->num) && ($playerCard[2]->num+1 == $playerCard[4]->num)){
            $r=array();
            array_push($r,$playerCard[0]);
            array_push($r,$playerCard[2]);
            array_push($r,$playerCard[4]);
            array_push($tempResult, array('level'=>($playerCard[0]->count + $playerCard[2]->count)%10, 'maxCard'=>$playerCard[3],'douPai'=>$r));
        }

        //第七种情况abbcc
        if(($playerCard[0]->num+1 == $playerCard[2]->num) && ($playerCard[2]->num+1 == $playerCard[4]->num)){
            $r=array();
            array_push($r,$playerCard[0]);
            array_push($r,$playerCard[1]);
            array_push($r,$playerCard[3]);
            array_push($tempResult, array('level'=>($playerCard[1]->count + $playerCard[3]->count)%10, 'maxCard'=>$playerCard[4],'douPai'=>$r));
        }

        //第8种情况abbbc
        if($playerCard[0]->num+2 == $playerCard[4]->num && $playerCard[0]->num + 1 == $playerCard[1]->num)
        {
            $r=array();
            array_push($r,$playerCard[0]);
            array_push($r,$playerCard[1]);
            array_push($r,$playerCard[4]);
            array_push($tempResult, array('level'=>($playerCard[1]->count * 2)%10, 'maxCard'=>$playerCard[3],'douPai'=>$r));
        }


        //有可能没有结果,直接返回
        if(count($tempResult) == 0){
            return $result;
        }

        //获取最大的可能性结果返回
        $level = $tempResult[0]['level'];
        $index = 0;
        for($i = 1; $i < count($tempResult); $i++){
            if($tempResult[$i]['level'] > $level){
                $index = $i;
            }
        }
        //echo $tempResult[$index]['level'];
        $result['level'] = $this->_getCount($tempResult[$index]['level'] % 10 );
        $result['maxCard'] = $tempResult[$index]['maxCard'];
        $result['douPai'] = $tempResult[$index]['douPai'];

        return $result;

    }

}
?>

基本思路便是把传进来的五张牌对象进行升序排列后,判断可能出现的情况,得到最后的牛型以及确定此牛型相关的牌(斗)。

发布了23 篇原创文章 · 获赞 25 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览