麻将胡牌算法-癞子牌特别多(一)

麻将内最核心的算法,每一次出牌,摸牌都需要使用到。(仅个人想法,想要更快速度,建用把算出来的结果存储下来,通过查表法来使用)

 

1、计算前准备

    /*癞子数量*/
    protected byte laiNumber;
    /*癞子牌*/
    protected List laiPoker;
    /*手牌数量总计*/
    protected byte pokerNumber;
    /*计算手牌*/
    protected byte[] handPoker;
    /*手牌包含的颜色*/
    protected List colors;
    /*将牌信息*/
    protected List jiangPoker;
    /*胡牌可能性*/
    protected List tingPossibles = new ArrayList<>();
    /*一种将牌找到的*/
    protected List tingPossibleOne = new ArrayList<>();
    /*返回胡牌信息*/
    protected HuInfo huInfo = new HuInfo();
    /**
     * 将牌信息
     */
    public class JiangInfo{
        /*将牌*/
        byte jiangOne;
        byte jiangTwo;
        /*其中癞子数量*/
        byte tingNum;
    }

 

    /**
     * 癞子牌变牌信息
     */
    public class TingPossible{
        //剩余未变化癞子数量
        public byte laiNumber;
        //当前变化下的手牌
        public byte[] handPoker;
        //癞子已经变好的牌
        public List changes = new ArrayList<>();

        public TingPossible (byte laiNumber,byte[] handPoker,List changes){
            this.laiNumber = laiNumber;
            this.handPoker = handPoker;
            this.changes.addAll(changes);
        }
    }

 

    /**
     * 胡牌计算信息
     */
    public class HuInfo{
        //是否胡牌
        public boolean isHu;
        //胡牌可能性组合
        public List possibility = new ArrayList<>();
    }
    /**
     * 计算胡牌变化可能性
     * @param onlyHu 仅判断胡牌
     * @return
     */
    public HuInfo huInfo(byte[] handPoker,boolean onlyHu){
        this.handPoker = handPoker.clone();
        this.pokerNumber = (byte) handPoker.length;
        this.laiPoker = GameUtil.removeLaiPoker(this.handPoker,mjGame.specialClearn.guiMessage);
        this.laiNumber = (byte) this.laiPoker.size();
        this.colors = GameUtil.includeColor(this.handPoker,gamePlayer.playerSpecialClearn.chunk);
        ......
    }
  • 这是外部调用的接口
  • 两参数:1、传入手牌。2、是否只是想知道可以胡牌(不考虑癞子牌具体变化)
  • laiPoker 需要自定义算法(这个自己写,很简单的)。通过配置找出手牌中的癞子牌,存入laiPoker,并删除手牌this.handPoker中的癞子牌
  • colors 自定义算法。存储手牌移除癞子牌后,包含到的花色。

2、花猪检查(排除特殊条件)

某些麻将规则,花色超过2种,不能胡牌。

        //花猪,定缺检查
        if(colors.size() > HUA_ZHU_COLOR_NUM){
            return huInfo;
        }

3、七对检查(排除特殊条件)

        //小七对检查
        if(qiXiaoDui(onlyHu) && huInfo.isHu){
            return huInfo;
        }
    /**
     * 小七对检查
     */
    protected boolean qiXiaoDui(boolean onlyHu){
        if(pokerNumber == 14){
            //对子数
            byte duiZhiNumber = 0;
            //癞子数量
            byte laiNumber = this.laiNumber;
            TingPossible possible = new TingPossible((byte) 0,null,new ArrayList<>());

            //查找已有的牌组合
            for(byte i = 1; i < mjGame.handPokerSize(); i ++){
                byte number = handPoker[(int)i];
                if(number > 0){
                    boolean dan = number % 2 == 1;//单双判断
                    double duoDui = Math.ceil((double) number/2);
                    duiZhiNumber += duoDui;
                    if(dan){
                        laiNumber --;
                        //用一张癞子牌固定变成该张单牌
                        possible.changes.add(i);
                    }
                }
            }

            if(laiNumber > 0){
                duiZhiNumber += laiNumber / 2;
            }
            if(duiZhiNumber == 7){
                if(!onlyHu){
                    //癞子不变,查看是否能胡
                    addNoChangeQXD(laiNumber);
                    //查询多余癞子牌组合
                    moreTing(possible,laiNumber);
                    tingPossibles.add(possible);
                }
                return true;
            }
        }
        return false;
    }

 

    /**
     * 癞子牌变牌信息
     * 表示癞子牌能胡的情况下,一种变化
     */
    public class TingPossible{
        //剩余未变化癞子数量
        public byte laiNumber;
        //当前变化下的手牌
        public byte[] handPoker;
        //癞子已经变好的牌
        public List changes = new ArrayList<>();

        public TingPossible (byte laiNumber,byte[] handPoker,List changes){
            this.laiNumber = laiNumber;
            this.handPoker = handPoker;
            this.changes.addAll(changes);
        }
    }
    protected void moreTing(TingPossible possible,byte laiNumber){
        //变已有的牌,数量小于等于2的牌
        if(laiNumber > 1){
            for(byte i = 1; i < mjGame.handPokerSize(); i ++){
                if(i != guiMessage.fanChose && laiNumber > 1){
                    laiNumber -= addMoreTing(possible,i);
                }
            }
        }

        //癞子牌仍然有剩余,变已有颜色的牌(排除已有的牌)
        if(laiNumber > 1){
            for(byte pokerValue = 1; pokerValue < mjGame.handPokerSize(); pokerValue ++){
                if(handPoker[pokerValue] == 0){
                    possible.changes.add(pokerValue);
                    possible.changes.add(pokerValue);
                    laiNumber -= 2;
                    if(laiNumber > 1){
                        possible.changes.add(pokerValue);
                        possible.changes.add(pokerValue);
                        laiNumber -= 2;
                    }
                }
            }
        }
    }

 

  •  7对是不同于正常胡牌的牌型,需要单独计算
  • 需要满牌14长,不能有任何的碰、杠
  • 组成7个对子就能胡牌。(需要分高,癞子牌这里就需要变成。1尽量相同的颜色,2四张相同的牌尽量多)
  • 我这里是计算的最优组合,所有7对最终只会出现1个结果(就算1长普通牌,13长癞子牌。原则上不允许出现14长癞子牌)。
  • handPokerSize 指我这里定义的手牌长度。下标1-9代表1-9条,11-19代表1-9筒,21-29代表1-9万,31-34代表东南西北,41-43代表中发白
  • 先遍历普通牌,移除所有对子。如果是单长或3长,添加1张癞子牌(算2个对子)。
  • 普通牌组合完毕,还剩余癞子牌,自动每两张算一个对子
  • 癞子变牌计算(具体变成某一张牌,时分数最大化。)
    • 其实这里只会涉及,普通牌组合完毕后,仍然剩余偶数的癞子牌。
    • 优先组合,手上已经有1副对子的牌,变成4长一样的牌。(大多数麻将,这里都会有加分)
    • 如果手牌全是4长一样的牌,则在手牌已有花色中,选手中没有的牌去变,组成一样的花色。(清一色一条龙)

你可能感兴趣的:(算法,麻将,算法,智能)