德州扑克
* * * *
拉格朗日计划
* * * *
德州扑克

给定一系列德州扑克的手牌,输出每副手牌对应的牌型。

全部牌型如下:

Royal Flush      皇家同花顺,同一花色10到A组成的顺子,例:🃁🃎🃍🃋🃊

Straight Flush   同花顺,同一花色(除10到A以外的)的顺子,例:🃛🃚🃙🃘🃗

Four of a Kind   炸弹,有四张相同点数的牌,例:🃕🃅🂵🂥🃂

Full House       葫芦,三条+一对,例:🂦🂶🃆🃞🂾

Flush            乱同花,五张相同花色且不能组成顺子的牌,例:🃋🃉🃈🃄🃃

Straight         顺子,五张点数连续的牌(注意A2345也是i顺子),例:🃊🂩🂸🃇🃖

Three of a Kind  三条,有三张相同点数的牌,且另两张牌不是对子,例:🃝🂭🂽🂹🂢

Two Pair         两对,有两幅点数不同的对子,例:🂻🂫🃓🂣🂲

Pair             一对,有两张相同点数的牌,和另外三张牌点数与之不同,且也互不相同的牌,例:🂪🂺🂨🂷🃔

High Card        高牌,五张点数互不相同、且不能组成顺子的牌,例:🃎🃍🂧🂤🂳


本题难度:



解答

逻辑比麻将简单,但实现尤其是缩写仍很繁琐的问题。

按照牌面能否组成同花或顺子,共有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