最近又做了一个新的德州扑克算法,和之前的还略有不同,
之前的德州扑克算法规则为:玩家手中的两张私有牌必须参与到牌型组合中去,
也就是公共牌最多选择3张,这次做的又不一样了:限度放宽,可以5张牌全部来自于公共牌,
换个角度,也就是从2张私有牌和5张公共牌组合成的7张牌中选择一个最优解.
解法分析
最简单的解法自然是穷举,但是逻辑也很恶心,而且运算量也比较大,PASS掉。
我想到的一种抽丝拨茧的方法是:
- 对卡组进行降序排序
- 遍历卡组,记录如下特征:最长顺子长度以及起始值、
3张相同牌的集合、2张相同牌的集合、4张相同牌的值、牌的类型数目 - 接下来就是判断过程了
- 判断是否有4张相同的牌,如果有,那么在剩下的牌中选张最大的组成四条
- 如果可以同花色,且最长顺子长度大于4,判断是否可以组成(皇家)同花顺
- 如果有3张相同的牌, 而且同时存在另外一套3张相同的牌或者存在2张相同的牌,
那么牌型是葫芦 - 如果可以同花色,那么牌型是同花
- 如果最大顺子长度大于4,那么可以是顺子
- 如果存在3张相同的牌,再找两张大牌组成三条
- 如果有多组2张相同的牌,那么再找一张最大牌组成两对
- 如果只有一组2张相同的牌,那么再找3张最大的牌组成对子
- 最后就只可能是高牌了
示例代码
class TaxasPlayerV2(object):
def __init__(self, cds):
self.cards = cds
self.cards.sort(cmp=GameBase.get_card_cmp_func(1), reverse=True)
def find_best_solution(self):
max_seq_num = 1
seq_start_val = self.cards[0].value
pre = None
# pairs 和 thirds 存的是该对子或三张的牌值
pairs = []
thirds = []
four = None
same_count = 1
card_types = [[], [], [], [], []]
for card in self.cards:
val = card.value
card_types[card.type].append(val)
if pre:
if pre == val:
# 对子情况
same_count += 1
if same_count == 2:
pairs.append(val)
elif same_count == 3:
pairs.pop()
thirds.append(val)
elif same_count == 4:
four = val
break
else:
# 与前面一张牌值不同
same_count = 1
if max_seq_num < 5:
# 没有组成序列
diff = pre - val
if diff == 1 or diff == -12:
# 顺子情况, 3 -> 2 or A -> k
max_seq_num += 1
else:
# 无法构成序列时重置数据
seq_start_val = val
max_seq_num = 1
pre = val
if four:
# 找到最大的单牌
for item in self.cards:
if item.value != four:
return TaxasSolution(ResultType.Four, (four, item.value))
same_color = None
for card_list in card_types:
if len(card_list) > 4:
same_color = card_list
break
# same_color = [card1, card2, ...]
if same_color and max_seq_num > 4:
# 判断是否是同花, 相同颜色的已经排好队在same_color中了
idx = 1
ng_count = 0
header = pre = same_color[0] if same_color[0] > 1 else 14
while idx < len(same_color):
val = same_color[idx] if same_color[idx] > 1 else 14
if pre - val == 1:
ng_count += 1
else:
ng_count = 1
header = val
if ng_count == 4:
break
idx += 1
pre = val
if ng_count >= 4:
return TaxasSolution(ResultType.RoyalFlush if header == 14 else ResultType.Flush, (header,))
if thirds:
if len(thirds) == 2:
return TaxasSolution(ResultType.Gourd, (thirds[0], thirds[1]))
if pairs:
return TaxasSolution(ResultType.Gourd, (thirds[0], pairs[0]))
if same_color:
return TaxasSolution(ResultType.SameColor, same_color[:5])
if max_seq_num > 4:
return TaxasSolution(ResultType.Sequence, (seq_start_val,))
if thirds:
thirds_val = thirds[0]
flag = [thirds_val]
for item in self.cards:
if item.value != thirds_val:
flag.append(item.value)
if len(flag) == 3:
break
# 再找两个散牌
return TaxasSolution(ResultType.Three, flag)
if len(pairs) > 1:
pair_tag = [pairs[0], pairs[1]]
for item in self.cards:
val = item.value
if val not in pair_tag:
pair_tag.append(val)
break
# 使用前两对, 再找一个大散牌
return TaxasSolution(ResultType.TwoPair, pair_tag)
elif len(pairs) == 1:
pair_tag = [pairs[0]]
for item in self.cards:
val = item.value
if val != pairs[0]:
pair_tag.append(val)
if len(pair_tag) == 4:
break
return TaxasSolution(ResultType.SinglePair, pair_tag)
return TaxasSolution(ResultType.HighCard, [self.cards[i].value for i in range(0, 5)])