麻将判断胡牌 java_麻将基本胡的算法——Java

该博客介绍了如何使用Java实现麻将胡牌的基本算法。首先列出胡牌的必要条件,包括一对将牌和由顺子或刻子组成的其余牌。然后详细阐述了精简版和完整版的算法流程,并提供了完整的Java代码实现。最后通过一系列测试用例验证了算法的正确性。
摘要由CSDN通过智能技术生成

算法思想

胡的条件

必须有一对将(两个相同的牌)

除了将,其余牌必须为顺子或刻子

算法(精简版)

提取所有将牌

去除所有刻子

去除所有顺子

没有牌了,胡;还有牌,不胡

算法(完整版)

提取所有将牌(如果要胡,将牌是必须存在的,而且将牌可能会有多种)

取一对将牌,如果没有将牌了,则表示不能胡

将手牌去除选取的将牌

将剩余的手牌去除所有的刻子,去除所有的刻子后如果手牌没有了,则胡;手牌还有,则继续第5步判断

将手牌去除所有的顺子,去除所有的顺子后如果手牌没有了,则胡;手牌还有,则回到第2步重新判断

Java实现

代码

import java.util.Arrays;

/**

* @author Yawei Xi

* @date 2018-10-9

*/

public class MahjongCore {

/**

* 麻将所有牌型

* 一万,二万,三万,四万,五万,六万,七万,八万,九万

* 一筒,二筒,三筒,四筒,五筒,六筒,七筒,八筒,九筒

* 一条,二条,三条,四条,五条,六条,七条,八条,九条

* 东,西,南,北,中,发,白

*/

private static final int[] ALL_CARDS = new int[]{

11, 12, 13, 14, 15, 16, 17, 18, 19,

21, 22, 23, 24, 25, 26, 27, 28, 29,

31, 32, 33, 34, 35, 36, 37, 38, 39,

50, 60, 70, 80, 90, 100, 110

};

/**

* 判断手牌是否胡了

*

* @param cards 手牌

* @return 胡了(true), 没有胡(false)

*/

public static boolean isHu(int[] cards) {

if (null == cards) {

return false;

}

// 胡的牌的个数必须是2或5或8或11或14

if (cards.length != 2 && cards.length != 5 && cards.length != 8 && cards.length != 11 && cards.length != 14) {

return false;

}

// 将手牌中的将取出来

int[] js = getJiangs(cards);

if (null == js || js.length <= 0) {

return false;

}

for (int j : js) {

int[] tempCards = Arrays.copyOf(cards, cards.length);

tempCards = removeOne(tempCards, j);

tempCards = removeOne(tempCards, j);

Arrays.sort(tempCards);

// 去掉所有的刻子

tempCards = removeAllKe(tempCards);

if (tempCards.length <= 0) {

return true;

}

// 去掉所有的顺子

tempCards = removeAllShun(tempCards);

if (tempCards.length <= 0) {

return true;

}

}

return false;

}

/**

* 获取牌组中所有的“将”

*

* @param cards 牌组

* @return 所有的“将”组成的数组

*/

private static int[] getJiangs(int[] cards) {

int[] res = new int[0];

if (null != cards && cards.length > 1) {

for (int i = 0; i < cards.length - 1; i++) {

if (cards[i] == cards[i + 1]) {

res = add(res, cards[i]);

i++;

}

}

}

return res;

}

/**

* 去掉牌组中所有的刻子

*

* @param cards 牌组

*/

private static int[] removeAllKe(int[] cards) {

for (int i = 0; i < cards.length - 2; i++) {

if (cards[i] == cards[i + 1] && cards[i] == cards[i + 2]) {

cards = removeOne(cards, cards[i]);

cards = removeOne(cards, cards[i]);

cards = removeOne(cards, cards[i]);

}

}

return cards;

}

/**

* 去掉牌组中所有的顺子

*

* @param cards 牌组

*/

private static int[] removeAllShun(int[] cards) {

int[] res = Arrays.copyOf(cards, cards.length);

for (int i = 0; i < cards.length - 2; i++) {

if (cards[i] + 1 == cards[i + 1] && cards[i + 1] + 1 == cards[i + 2]) {

res = removeOne(res, cards[i]);

res = removeOne(res, cards[i + 1]);

res = removeOne(res, cards[i + 2]);

i += 2;

}

}

return res;

}

/**

* 获取去掉花色的牌的值

*

* @param card 原牌值

* @return 去掉花色的牌的值

*/

private static int getCardWithoutSuit(int card) {

return card % 10;

}

/**

* 将牌card加到牌组cards中

*

* @param cards 牌组

* @param card 牌

* @return 添加后的牌组

*/

private static int[] add(int[] cards, int card) {

int[] res = new int[cards.length + 1];

System.arraycopy(cards, 0, res, 0, cards.length);

res[res.length - 1] = card;

return res;

}

/**

* 在牌组中去掉一张牌

*

* @param cards 牌组

* @param card 要去掉的牌

* @return 去掉牌后的牌组

*/

private static int[] removeOne(int[] cards, int card) {

if (null == cards || cards.length <= 0) {

return cards;

}

Arrays.sort(cards);

int index = Arrays.binarySearch(cards, card);

if (index >= 0) {

int[] res = new int[cards.length - 1];

int j = 0;

for (int i = 0; i < cards.length; i++) {

if (i != index) {

res[j++] = cards[i];

}

}

return res;

}

return cards;

}

}

测试用例

/**

* @author Yawei Xi

* @date 2018-10-9

*/

public class Test {

public static void main(String[] args) {

// 空牌组

int[] a = {};

// 一万、一万

int[] b = {11, 11};

// 一万、二万、三万、四万、四万

int[] c = {11, 12, 13, 14, 14};

// 一万、二万、三万、二条、三条、四条、四万、四万

int[] d = {11, 12, 13, 32, 33, 34, 14, 14};

// 一万、二万、三万、二条、三条、四条、东风、东风、东风、四万、四万

int[] e = {11, 12, 13, 32, 33, 34, 50, 50, 50, 14, 14};

// 一万、二万、三万、二条、三条、四条、东风、东风、东风、五万、五万、五万、四万、四万

int[] f = {11, 12, 13, 32, 33, 34, 50, 50, 50, 15, 15, 15, 14, 14};

// 一万、二万、三万、四万、四万、五万、六万、六万、六万、七万、八万、九万、九万、九万

int[] g = {11, 12, 13, 14, 14, 15, 16, 16, 16, 17, 18, 19, 19, 19};

// 一万、二万、三万、四万、四万、五万、六万、六万、六万、六万、七万、八万、九万、九万

int[] h = {11, 12, 13, 14, 14, 15, 16, 16, 16, 16, 17, 18, 19, 19};

System.out.println("a牌型是否胡:" + (MahjongCore.isHu(a) ? "胡" : "不胡"));

System.out.println("b牌型是否胡:" + (MahjongCore.isHu(b) ? "胡" : "不胡"));

System.out.println("c牌型是否胡:" + (MahjongCore.isHu(c) ? "胡" : "不胡"));

System.out.println("d牌型是否胡:" + (MahjongCore.isHu(d) ? "胡" : "不胡"));

System.out.println("e牌型是否胡:" + (MahjongCore.isHu(e) ? "胡" : "不胡"));

System.out.println("f牌型是否胡:" + (MahjongCore.isHu(f) ? "胡" : "不胡"));

System.out.println("g牌型是否胡:" + (MahjongCore.isHu(g) ? "胡" : "不胡"));

System.out.println("h牌型是否胡:" + (MahjongCore.isHu(h) ? "胡" : "不胡"));

}

}

测试结果

a牌型是否胡:不胡

b牌型是否胡:胡

c牌型是否胡:胡

d牌型是否胡:胡

e牌型是否胡:胡

f牌型是否胡:胡

g牌型是否胡:不胡

h牌型是否胡:不胡

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
麻将胡牌算法涉及到很多细节和规则,下面是一个基本JAVA实现: 1. 首先,我们需要一个表示牌的数据结构,可以使用一个数组或者列表来存储玩家手牌的牌型。 ```java public class Mahjong { public static final int MAX_COUNT = 34; // 麻将牌的总数 public static final int MAX_WEAVE = 4; // 最大组合数 public static final int COLOR_WAN = 0; // 万 public static final int COLOR_TIAO = 1; // 条 public static final int COLOR_TONG = 2; // 筒 public static final int COLOR_FENG = 3; // 风 public static final int COLOR_JIAN = 4; // 箭 public static final int CARD_FENG_EAST = 27; // 东 public static final int CARD_FENG_SOUTH = 28; // 南 public static final int CARD_FENG_WEST = 29; // 西 public static final int CARD_FENG_NORTH = 30; // 北 public static final int CARD_JIAN_ZHONG = 31; // 中 public static final int CARD_JIAN_FA = 32; // 发 public static final int CARD_JIAN_BAI = 33; // 白 private int[] cards = new int[MAX_COUNT]; private int count = 0; // 添加一张牌 public void addCard(int card) { cards[card]++; count++; } // 移除一张牌 public void removeCard(int card) { if (cards[card] > 0) { cards[card]--; count--; } } // 获取指定牌的数量 public int getCardCount(int card) { return cards[card]; } // 清除手牌 public void clear() { for (int i = 0; i < MAX_COUNT; i++) { cards[i] = 0; } count = 0; } // 获取所有牌的数量 public int getCount() { return count; } } ``` 2. 接下来,我们需要实现一个判断是否能够胡牌的函数。这个函数需要考虑到麻将基本规则,如顺子、刻子、将牌等。 ```java public class MahjongUtils { public static final int MAX_HU_COUNT = 14; // 最大胡牌数 // 判断是否能够胡牌 public static boolean checkHu(Mahjong mahjong) { int[] cards = mahjong.getCards(); int count = mahjong.getCount(); // 如果牌的数量不是3n+2,则不能胡牌 if ((count % 3) != 2) { return false; } // 拆分牌型,分别判断顺子、刻子、将牌 int[] cardsCopy = Arrays.copyOf(cards, cards.length); int[] huCards = new int[MAX_HU_COUNT]; int huCount = 0; for (int i = 0; i < Mahjong.MAX_COUNT; i++) { if (cardsCopy[i] > 0) { // 判断顺子 if (i < Mahjong.CARD_FENG_EAST) { if (i % 9 <= 6 && cardsCopy[i + 1] > 0 && cardsCopy[i + 2] > 0) { cardsCopy[i]--; cardsCopy[i + 1]--; cardsCopy[i + 2]--; } } // 判断刻子 if (cardsCopy[i] >= 3) { cardsCopy[i] -= 3; } // 判断将牌 if (cardsCopy[i] == 2) { huCards[huCount++] = i; cardsCopy[i] -= 2; } } } // 如果剩余的牌型能够组成完整的顺子和刻子,则说明可以胡牌 for (int i = 0; i < Mahjong.MAX_COUNT; i++) { if (cardsCopy[i] != 0) { return false; } } return true; } } ``` 3. 最后,我们可以编写一个测试函数来验证算法的正确性。 ```java public class MahjongTest { public static void main(String[] args) { Mahjong mahjong = new Mahjong(); mahjong.addCard(Mahjong.CARD_WAN_1); mahjong.addCard(Mahjong.CARD_WAN_1); mahjong.addCard(Mahjong.CARD_WAN_1); mahjong.addCard(Mahjong.CARD_WAN_2); mahjong.addCard(Mahjong.CARD_WAN_3); mahjong.addCard(Mahjong.CARD_WAN_4); mahjong.addCard(Mahjong.CARD_WAN_5); mahjong.addCard(Mahjong.CARD_WAN_6); mahjong.addCard(Mahjong.CARD_WAN_7); mahjong.addCard(Mahjong.CARD_WAN_8); mahjong.addCard(Mahjong.CARD_WAN_9); mahjong.addCard(Mahjong.CARD_TONG_1); mahjong.addCard(Mahjong.CARD_TONG_1); boolean isHu = MahjongUtils.checkHu(mahjong); System.out.println("是否胡牌:" + isHu); } } ``` 这样,我们就实现了一个简单的麻将胡牌算法。当然,实际上麻将的规则非常复杂,这个算法只是一个基本的实现,还需要根据具体的麻将规则进行进一步的优化和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值