逻辑比麻将简单,但实现尤其是缩写仍很繁琐的问题。
按照牌面能否组成同花或顺子,共有4种情况:都能、能组成顺子不能组成同花、能组成同花不能组成顺子、都不能。
因此把牌型分成四大类:(皇家)同花顺、顺子、乱同花、其它,放在一个长度为4的列表中。
用两个布尔量分别刻画能组成同花和能组成顺子两种情况、把两者相加,得一0到3之间的数,分别对应上述四种情况,用该数作下标访问列表,就实现了牌面的初步分类。
顺子和同花的判断:
用16进制数来区分牌面,注意到所有牌的ASCII码都在127137和127199之间,把每张牌的码模256,得到一个0到255之间的数来唯一地表示这张牌。
把这个数模16再加一个偏移量就得牌的点数,并把2到A之间的每个点数分别对应2到41之间的每个质数,把每张手牌对应的素数相乘得到手牌的点数积。
顺子的点数积只能是连续五个素数的积或$41\times 2\times 3\times 5\times 7=8610$(对应顺子A2345)。
把这个数除16取商再加上一个偏移量就得到0到3之间的数代表其花色,同样将之映射为2、3、5、7这四个素数,把每张手牌对应的素数相乘得到手牌的花色积。
同花的花色积只能是$2^5, 3^5, 5^5, 7^5$之一。
其它牌型的判断:
用一个多元组表示每种牌的数量,那么炸弹、葫芦、三条、两对、一对、高牌分别对应$(4,1), (3,2), (3,1,1), (2,2,1), (2,1,1,1), (1,1,1,1,1)$。
把多元组中的数映射为素数后再相乘,就得到手牌的牌型积,它与牌型唯一对应,用一个字典处理即可。
最终代码有五行。
代码长度:440字节 vs. 全站第一:270字节。
import sys,math
z,p=math.prod,[i-30for i in b' !#%)+/15;=CG']
q=[8610]+[z(p[k:k+5])for k in range(9)]
c,d,f="Straight ","Flush"," of a Kind"
for a in sys.argv[1:]:h=[ord(j)%256for j in a];v=[p[j%16-2-(j%16>12)]for j in h];r=z(v);print([{14:"Four"+f,15:"Full House",20:"Three"+f,18:"Two Pair",24:"Pair"}.get(z(p[v.count(j)-1]for j in{*v}),"High Card"),c,d,["Royal ",c][r
|