麻将之胡牌

最近打麻将有点频繁(有点罪恶),结合得发一篇博客的情况,因此这里小水一篇文章,用回溯的方式实现一下胡牌的判定。

基础胡牌:三副刻子或者顺子加上一对子,即可胡牌。

特殊牌面:

  • 十三幺:由三种序数牌的1、9牌,东西南北中发白各一种,以及再加上这里面任意一张牌组成对子
  • 七小对:即七个对子组成

对于十三幺和七小对比较容易判断,本质上计数即可:

用数组来表示各种类型的牌,即下标0-33分为代表1-9万,1-9筒,1-9条,以及东西南北中发白。用value表示所持牌的数量。

首先判断七小对:即判断是否有七个对子。

//判断七小对
public boolean isSevenPairs(int[] pai) {
    int pairCount = 0;
    for (int i = 0; i < 34; ++i) {
        if (pai[i] == 2 || pai[i] == 4) {
            pairCount += pai[i] / 2;
        } else if (pai[i] == 3 || pai[i] == 1) {
            return false;
        }
    }
    return (pairCount == 7);
}

判断是否是十三幺:首先列出十三幺所有牌型的下标,然后同样判断是否具有这个牌型即可。

public boolean isThirteenYao(int[] pai) {
    int[] wonders = new int[]{0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33};
    for (int i : wonders) {
        if (pai[i] < 1)
            return false;
    }
    int pairCount = 0;
    for (int i : wonders) {
        if (pai[i] == 2) {
            pairCount++;
        }
    }
    return (pairCount == 1);
}

基础胡牌:市面上的麻将相关游戏应该有更加高效的判断算法,这里实现一种比较容易理解,回溯的方式来依次遍历所有可能性,以此看看有没有符合胡牌牌型。

在回溯过程中,每遍历一张牌,会先尝试将其作为对子,如果不符合,再尝试作为刻子,或者顺子。

public boolean isWinn(int[] pai, int index, int pairs, int melds) {
    if (index >= pai.length) {
        return pairs == 7 || (pairs == 1 && melds == 4);
    }
    //尝试形成对子
    if (pai[index] >= 2) {
        pai[index] -= 2;
        if (isWinn(pai, index, pairs + 1, melds)) {
            return true;
        }
        pai[index] += 2;
    }
    
    //尝试形成顺子
    if (index < 27 && !isEightAndNight(index) && pai[index] > 0 && pai[index + 1] > 0 && pai[index + 2] > 0) {
        pai[index]--;
        pai[index + 1]--;
        pai[index + 2]--;
        if (isWinn(pai, index, pairs, melds + 1)) {
            return true;
        }
        pai[index]++;
        pai[index + 1]++;
        pai[index + 2]++;
    }
    
    // 尝试形成刻子
    if (pai[index] >= 3) {
        pai[index] -= 3;
        if (isWinn(pai, index, pairs, melds + 1)) {
            return true;
        }
        pai[index] += 3;
    }
    
    if (pai[index] == 0 && isWinn(pai, index + 1, pairs, melds)) {
        return true;
    }

    return false;
}

//因为8 和9的牌后续是没有了,无法形成顺子,因此需要排除
public isEightAndNight(int index) {
    if(index == 7 || index == 8 || index == 16 || index == 17 || index == 25 || index == 26 ){
        return true;
    }
    return false;
}

你可能感兴趣的:(java,回溯)