chore: update 2026-04-21
This commit is contained in:
101
solutions/0054.PokerHands/euler_54_better.py
Normal file
101
solutions/0054.PokerHands/euler_54_better.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import time
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def timer(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
start_time = time.time()
|
||||
result = func(*args, **kwargs)
|
||||
end_time = time.time()
|
||||
elapsed_time = end_time - start_time
|
||||
print(f"{func.__name__} time: {elapsed_time:.6f} seconds")
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# 牌面数值映射
|
||||
VAL = {
|
||||
"2": 2,
|
||||
"3": 3,
|
||||
"4": 4,
|
||||
"5": 5,
|
||||
"6": 6,
|
||||
"7": 7,
|
||||
"8": 8,
|
||||
"9": 9,
|
||||
"T": 10,
|
||||
"J": 11,
|
||||
"Q": 12,
|
||||
"K": 13,
|
||||
"A": 14,
|
||||
}
|
||||
|
||||
|
||||
def hand_key(cards: tuple[str, ...]) -> tuple[int, ...]:
|
||||
"""
|
||||
将一手5张牌映射为规范元组。
|
||||
元组的字典序即牌力大小,可直接用 > / < 比较。
|
||||
"""
|
||||
# 1. 提取数值并降序排列
|
||||
nums = sorted([VAL[c[0]] for c in cards], reverse=True)
|
||||
suits = {c[1] for c in cards}
|
||||
|
||||
# 2. 判断同花与顺子
|
||||
is_flush = len(suits) == 1
|
||||
is_straight = len(set(nums)) == 5 and nums[0] - nums[4] == 4
|
||||
|
||||
# 3. 处理 A-2-3-4-5 顺子(A作为1,5-high)
|
||||
if nums == [14, 5, 4, 3, 2]:
|
||||
is_straight = True
|
||||
nums = [5, 4, 3, 2, 1]
|
||||
|
||||
# 4. 统计出现次数,并按 (次数, 牌面) 降序排列
|
||||
# 这是整个方法的数学核心:多重集的字典序
|
||||
counts = Counter(nums)
|
||||
by_count = sorted(counts.items(), key=lambda x: (x[1], x[0]), reverse=True)
|
||||
|
||||
# 5. 按牌型返回规范元组
|
||||
if is_flush and is_straight:
|
||||
return (9, nums[0]) # 同花顺(皇家同花顺只是顶牌为A)
|
||||
if by_count[0][1] == 4:
|
||||
return (8, by_count[0][0], by_count[1][0]) # 四条
|
||||
if by_count[0][1] == 3 and len(by_count) == 2:
|
||||
return (7, by_count[0][0], by_count[1][0]) # 葫芦
|
||||
if is_flush:
|
||||
return (6, *nums) # 同花:比全部5张降序
|
||||
if is_straight:
|
||||
return (5, nums[0]) # 顺子:比顶牌
|
||||
if by_count[0][1] == 3:
|
||||
return (4, by_count[0][0], by_count[1][0], by_count[2][0]) # 三条
|
||||
if by_count[0][1] == 2 and len(by_count) == 3:
|
||||
return (3, by_count[0][0], by_count[1][0], by_count[2][0]) # 两对
|
||||
if by_count[0][1] == 2:
|
||||
return (
|
||||
2,
|
||||
by_count[0][0],
|
||||
by_count[1][0],
|
||||
by_count[2][0],
|
||||
by_count[3][0],
|
||||
) # 一对
|
||||
return (1, *nums) # 高牌:比全部5张降序
|
||||
|
||||
|
||||
def read_hands(path: Path):
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
cards = line.strip().split()
|
||||
if len(cards) == 10:
|
||||
yield tuple(cards[:5]), tuple(cards[5:])
|
||||
|
||||
|
||||
@timer
|
||||
def main() -> int:
|
||||
data_path = Path(__file__).parent / "0054_poker.txt"
|
||||
wins = sum(1 for p1, p2 in read_hands(data_path) if hand_key(p1) > hand_key(p2))
|
||||
return wins
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(main())
|
||||
Reference in New Issue
Block a user