php实现麻将牌型的胡牌检测算法

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

麻将基本牌型的胡牌检测算法,不包含小七对,针对小七对可以增加牌型检测,与此组成牌型树。
此类可以获得胡牌的牌型组合,取得后针对组合可以进行牌型名称检测。
先上一个,后面会持续更新各地特殊的胡牌算法,如癞子

 

<?php
/**
 * 麻将基本胡牌 (不包含小七对)
 *
 * 此类检测是否胡牌,返回胡牌的组合, 你可以再将获得的胡牌组合,进行相应牌型检测获得牌型
 * 不能用于小七对的胡牌检测
 *
 * @package 
 * @author  sunshine
 *
 * $Id: HuAlgorithm.php 2017.12.05 $
 */

class HuAlgorithm
{

	private $stack = [];  	# 牌组栈
    private $cards = [];  	# 剩余手牌
    private $pairs = 0;  	# 将对个数
    private $raw = false;  	# 是否直接返牌组栈
    private $number = [];	# 牌堆
	
	public function __construct($number = [], $raw = false)
	{
		$this->number = $number;
		$this->raw = $raw;
	}

	public function clear($raw = false)
	{
		$this->stack = [];
        $this->cards = [];
        $this->pairs = 0;
        $this->raw = $raw;
	}

    public function start($cards)
    {
    	$this->cards = $cards;
    	sort($this->cards);

        if ($this->try_hu())
        {
        	if ($this->raw)
        	{
        		# 直接返回牌组栈
                return $this->stack;
        	}
        	else
        	{
        		# 返回胡牌的排列
                $win_cards = [];
                foreach ($this->stack as $e)
                {
                	$win_cards[] = $e;
                }
                return $win_cards;
        	}
        }
        else
        {
        	return [];
        }
    }

    # 将牌组压栈
    private function push($group)
    {
    	array_push($this->stack, $group);
    }

    # 牌组出栈
    private function roll_back()
    {
        $group = array_pop($this->stack);
        array_push($this->cards, $group);
        sort($this->cards);
    }

   	# 刻子,则将此组牌压栈
    private function try_triplet($card)
    {
    	if ($this->array_count($this->cards, $card) >= 3)
    	{
    		$this->cards = $this->array_remove($this->cards, $card, 3);
    		$this->push([$card, $card, $card]);
    		return true;
    	}
    	else
    		return false;
    }

	# 顺子,则将此组牌压栈
    private function try_along($card)
    {
    	if (!in_array($card, $this->number))
    		return false;

        if (in_array($card, $this->cards) && in_array($card + 1, $this->cards) && in_array($card + 2, $this->cards))
        {
        	$this->cards = $this->array_remove($this->cards, $card);
        	$this->cards = $this->array_remove($this->cards, $card + 1);
        	$this->cards = $this->array_remove($this->cards, $card + 2);
        	$this->push([$card, $card + 1, $card + 2]);
        	return true;
        }
        else
        	return false;
    }

    # 对子,对子只能有一个
    private function try_sub($card)
    {
        if ($this->pairs == 1)
            return false;

    	if ($this->array_count($this->cards, $card) >= 2)
    	{
    		$this->cards = $this->array_remove($this->cards, $card, 2);
    		$this->push([$card, $card]);
    		$this->pairs = 1;
    		return true;
        }
        else
        	return false;
    }

    # 回溯尝试组成顺子刻子对子
    private function try_hu()
    {
    	if (!$this->cards)
    	{
    		if ($this->pairs == 1)
    			return true;
    		else
    			return false;
    	}

    	$active_card = reset($this->cards);

        if ($this->try_triplet($active_card))
        {
        	if (!$this->try_hu())
                $this->roll_back();
            else
                return true;
        }
        if ($this->try_sub($active_card))
        {
        	if (!$this->try_hu())
            {
                $this->roll_back();
                $this->pairs = 0;
            }
            else
                return true;
        }
        if ($this->try_along($active_card))
        {
        	if (!$this->try_hu())
                $this->roll_back();
            else
                return true;
        }

        return false;
    }

    private function array_remove($cards, $card, $d = 1)
    {
		foreach ($cards as $k => $v)
		{
			if ($v == $card && $d)
			{
				$d--;
				unset($cards[$k]);
			}
		}
		return $cards;
    }

    private function array_count($cards, $card)
    {
    	$rs = array_count_values($cards);
		foreach ($rs as $k => $v)
		{
			if ($card == $k) return $v;
		}
		return 0;
    }

}


##############################################################
# 牌
# 万 筒 条 东南西北 中发白 花
$wan = [17, 18, 19, 20 ,21, 22, 23, 24, 25];
$dot = [33, 34, 35, 36, 37, 38, 39, 40, 41];
$suo = [49, 50, 51, 52, 53, 54, 55, 56, 57];
$win = [61, 62, 63, 64];
$dragon = [71, 72, 73];
$flower = [];
$number = array_merge($wan, $dot, $suo);



##############################################################


# test 平胡
$cards = [17, 18, 19, 19, 19, 21, 22, 23, 35, 37, 36, 38, 36, 37];
# test 大对子
// $cards = [17, 17, 17, 19, 19, 19, 23, 23, 23, 36, 36, 36, 37, 37];
$ha = new HuAlgorithm($number);
$rs = $ha->start($cards);
print_r($rs);
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看