个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈
此算法基本可以通用于所有麻将的平胡规则,即满足m * ABC + n * AAA + AA(其中m、n可为0)的胡牌公式,红黑字牌也可由此算法演变。
首先,我们要约定每张麻将都可以由一个数字表示,比如11表示一万,12表示二万,21表示一条,22表示二条,31表示一筒,32表示二筒……
即所有牌用两位数表示,表示万条筒的两位数个位为牌点,十位为牌类型,其它表示非字牌的两位数与牌类型相同,以下用一个枚举类定义:
import java.util.HashMap;
import java.util.Map;
/**
* 麻将类型枚举
*
* @author zkpursuit
*/
public enum CardType {
wan(1, "万"), tiao(2, "条"), tong(3, "筒"),
dong(40, "东风"), nan(41, "南风"), xi(42, "西风"),
bei(43, "北风"), zhong(44, "中"), fa(45, "发"), ban(46, "白板");
//类型
private final int value;
//牌名
private final String name;
private CardType(int value, String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
private static final Map<Integer, String> numMap = new HashMap<>();
private static final Map<Integer, CardType> types = new HashMap<>();
private static final Map<Integer, String> typeNames = new HashMap<>();
static {
numMap.put(1, "一");
numMap.put(2, "二");
numMap.put(3, "三");
numMap.put(4, "四");
numMap.put(5, "五");
numMap.put(6, "六");
numMap.put(7, "七");
numMap.put(8, "八");
numMap.put(9, "九");
CardType[] enums = CardType.values();
for (CardType cardType : enums) {
types.put(cardType.getValue(), cardType);
typeNames.put(cardType.getValue(), cardType.getName());
}
}
/**
* 获取牌类型枚举
*
* @param typeValue 牌类型值
* @return 牌类型枚举
*/
public static final CardType getCardType(int typeValue) {
return types.get(typeValue);
}
/**
* 获取牌的类型名
*
* @param typeValue 牌类型
* @return 牌类型名
*/
public static final String getCardTypeName(int typeValue) {
return typeNames.get(typeValue);
}
/**
* 获取牌类型数值表示
*
* @param card 牌号
* @return 牌类型数值表示
*/
public static final int getCardTypeValue(int card) {
if (card < 40) {
return HandCards.getCardLeftValue(card);
}
return card;
}
/**
* 将牌数据转换为现实中可读的牌
*
* @param card 牌数据
* @return 现实中可读的牌
*/
public static final String getCardName(int card) {
if (card < 40) {
int type = HandCards.getCardLeftValue(card);
int point = HandCards.getCardRightValue(card);
StringBuilder sb = new StringBuilder();
sb.append(numMap.get(point));
sb.append(getCardTypeName(type));
return sb.toString();
}
return getCardTypeName(card);
}
}
以上定义了各张牌的数字表示,接下来我们分析手牌的存储结构,手牌可以用一个数组表示,数组下标号能除尽10的数组元素为保留位,不用于存储任何数据。举例解释此数组存储牌的数据结构:
0号下标保留位
1~9号下标为万字牌牌点,其对应的数组元素为牌的张数
10号下标保留位
11~19号下标为条字牌牌点,其对应的数组元素为牌的张数
20号下标为保留位
21~29号下标为筒字牌牌点,其对应的数组元素为牌的张数
40~46号下标分别表示东、南、西、北、中、发、白的存储位。
根据以上的定义,则可以根据数组下标获得万条筒字牌的类型和牌点,(下标/10 + 1) 则为字牌类型,(下标%10) 则为字牌点数。
具体定义一个手牌类,里面定义了各种静态的换算函数,可参看注释。
/**
* 手牌
*
* @author zkpursuit
*/
public class HandCards {
/**
* 获取牌号最左边的一位数,如果牌为筒、条、万,则返回值为牌类型数值
*
* @param card 牌号
* @return 牌号从左至右第一位数(十位数)
*/
public final static int getCardLeftValue(int card) {
return card / 10