refactor(utils): 修复密码哈希比较逻辑错误 feat(user): 新增按状态筛选优惠券接口 docs: 添加虚拟发货与任务中心相关文档 fix(wechat): 修正Code2Session上下文传递问题 test: 补充订单折扣与积分转换测试用例 build: 更新配置文件与构建脚本 style: 清理多余的空行与注释
170 lines
5.7 KiB
Python
170 lines
5.7 KiB
Python
import os
|
||
import hmac
|
||
import hashlib
|
||
import time
|
||
from typing import List, Dict, Any, Tuple
|
||
from collections import Counter
|
||
|
||
class SecureBlindBoxRNG:
|
||
"""使用 HMAC-SHA256 的加密安全随机数生成器"""
|
||
|
||
def __init__(self):
|
||
self.server_seed = os.urandom(32)
|
||
self.server_seed_hash = hashlib.sha256(self.server_seed).hexdigest()
|
||
self.nonce = 0
|
||
|
||
def _generate_random_bytes(self, context: str) -> bytes:
|
||
self.nonce += 1
|
||
message = f"{context}|nonce:{self.nonce}".encode()
|
||
return hmac.new(self.server_seed, message, hashlib.sha256).digest()
|
||
|
||
def secure_randint(self, max_value: int, context: str = "rand") -> int:
|
||
if max_value <= 0:
|
||
return 0
|
||
rand_bytes = self._generate_random_bytes(context)
|
||
return int.from_bytes(rand_bytes[:8], 'big') % max_value
|
||
|
||
def secure_shuffle(self, items: List) -> List:
|
||
items = items[:]
|
||
n = len(items)
|
||
for i in range(n - 1, 0, -1):
|
||
j = self.secure_randint(i + 1, f"shuffle:{i}")
|
||
items[i], items[j] = items[j], items[i]
|
||
return items
|
||
|
||
|
||
class MatchingGame:
|
||
"""对对碰游戏 - 可视化版本"""
|
||
|
||
def __init__(self):
|
||
self.rng = SecureBlindBoxRNG()
|
||
|
||
# 11种卡牌,每种9张
|
||
self.card_types = ['🍎', '🍊', '🍋', '🍇', '🍓', '🍒', '🥝', '🍑', '🍌', '🍉', '🫐']
|
||
self.card_list = [card for card in self.card_types for _ in range(9)]
|
||
|
||
# 安全洗牌
|
||
self.card_list = self.rng.secure_shuffle(self.card_list)
|
||
|
||
self.hand = self.card_list[:9]
|
||
self.deck = self.card_list[9:]
|
||
self.total_pairs = 0
|
||
self.round = 0
|
||
|
||
def display_hand(self):
|
||
"""显示当前手牌"""
|
||
print(f"\n{'='*50}")
|
||
print(f" 第 {self.round} 轮 | 手牌: {len(self.hand)}张 | 牌堆: {len(self.deck)}张")
|
||
print(f"{'='*50}")
|
||
print(f" 手牌: {' '.join(self.hand)}")
|
||
|
||
# 统计每种牌的数量
|
||
counter = Counter(self.hand)
|
||
pairs_info = []
|
||
for card, count in counter.items():
|
||
if count >= 2:
|
||
pairs_info.append(f"{card}×{count}")
|
||
|
||
if pairs_info:
|
||
print(f" 可配对: {', '.join(pairs_info)}")
|
||
else:
|
||
print(f" 可配对: 无")
|
||
|
||
def find_and_remove_pairs(self) -> Tuple[int, List[str]]:
|
||
"""找出并移除配对的牌"""
|
||
counter = Counter(self.hand)
|
||
pairs_found = 0
|
||
pairs_detail = []
|
||
remaining = []
|
||
|
||
for card, count in counter.items():
|
||
pairs = count // 2
|
||
if pairs > 0:
|
||
pairs_found += pairs
|
||
pairs_detail.append(f"{card}×{pairs*2}")
|
||
|
||
# 剩余的单张
|
||
if count % 2 == 1:
|
||
remaining.append(card)
|
||
|
||
return pairs_found, remaining, pairs_detail
|
||
|
||
def play_round(self, is_first: bool = False):
|
||
"""执行一轮游戏"""
|
||
self.round += 1
|
||
|
||
# 第一轮:如果有🍎,额外抽牌
|
||
if is_first:
|
||
apple_count = self.hand.count('🍎')
|
||
if apple_count > 0:
|
||
print(f"\n 🎁 发现 {apple_count} 张🍎,额外抽取 {apple_count} 张牌!")
|
||
extra = self.deck[:apple_count]
|
||
self.hand.extend(extra)
|
||
self.deck = self.deck[apple_count:]
|
||
print(f" 抽到: {' '.join(extra)}")
|
||
|
||
self.display_hand()
|
||
|
||
# 配对
|
||
pairs, remaining, pairs_detail = self.find_and_remove_pairs()
|
||
|
||
if pairs > 0:
|
||
print(f"\n ✨ 配对成功: {', '.join(pairs_detail)}")
|
||
print(f" 本轮配对: {pairs} 对")
|
||
self.total_pairs += pairs
|
||
|
||
# 抽取新牌
|
||
draw_count = min(pairs, len(self.deck))
|
||
if draw_count > 0:
|
||
new_cards = self.deck[:draw_count]
|
||
self.deck = self.deck[draw_count:]
|
||
remaining.extend(new_cards)
|
||
print(f" 从牌堆抽取: {' '.join(new_cards)}")
|
||
|
||
self.hand = remaining
|
||
return True
|
||
else:
|
||
print(f"\n ❌ 无法配对,游戏结束")
|
||
self.hand = remaining
|
||
return False
|
||
|
||
def play(self):
|
||
"""完整游戏流程"""
|
||
print("\n" + "🎮" * 20)
|
||
print(" 欢迎来到 对对碰 游戏!")
|
||
print("🎮" * 20)
|
||
print(f"\n游戏规则:")
|
||
print(f" 1. 初始手牌 9 张")
|
||
print(f" 2. 相同的牌可以配对消除")
|
||
print(f" 3. 每配对一次,从牌堆抽取相应数量的新牌")
|
||
print(f" 4. 直到无法配对为止")
|
||
print(f"\n种子哈希: {self.rng.server_seed_hash[:16]}...")
|
||
|
||
# 第一轮
|
||
can_continue = self.play_round(is_first=True)
|
||
|
||
# 后续轮次
|
||
while can_continue:
|
||
input("\n 按回车继续...")
|
||
can_continue = self.play_round(is_first=False)
|
||
|
||
# 游戏结束
|
||
print(f"\n{'='*50}")
|
||
print(f" 🏆 游戏结束!")
|
||
print(f" 总配对数: {self.total_pairs} 对")
|
||
print(f" 剩余手牌: {len(self.hand)} 张 {' '.join(self.hand)}")
|
||
print(f" 剩余牌堆: {len(self.deck)} 张")
|
||
print(f"{'='*50}")
|
||
|
||
return {
|
||
"total_pairs": self.total_pairs,
|
||
"remaining_hand": self.hand,
|
||
"remaining_deck_count": len(self.deck),
|
||
"seed_hash": self.rng.server_seed_hash
|
||
}
|
||
|
||
|
||
if __name__ == "__main__":
|
||
game = MatchingGame()
|
||
result = game.play()
|