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()