from .utils import get_suit,get_tile_name from loguru import logger class ChengduMahjongState: def __init__(self): # 每个玩家的手牌,使用108个索引表示 self.hands = [[0] * 108 for _ in range(4)] # 每个玩家108张牌的计数 # 每个玩家的打出的牌 self.discards = [[] for _ in range(4)] # 每个玩家的弃牌列表 # 每个玩家的明牌(碰、杠) self.melds = [[] for _ in range(4)] # 剩余的牌堆 self.deck = list(range(108)) # 0-107 表示108张牌 # 当前玩家索引 self.current_player = 0 # 玩家分数 self.scores = [100, 100, 100, 100] # 剩余牌数量 self.remaining_tiles = 108 # 胜利玩家列表 self.winners = [] # 缺门信息 self.missing_suits = [None] * 4 # 每个玩家的缺门("条"、"筒" 或 "万") def set_missing_suit(self, player, missing_suit): """ 设置玩家的缺门信息。 参数: - player: 玩家索引(0-3)。 - missing_suit: 玩家选择的缺门("条"、"筒" 或 "万")。 异常: - ValueError: 如果缺门设置无效。 """ valid_suits = ["条", "筒", "万"] if missing_suit not in valid_suits: raise ValueError("缺门设置无效") self.missing_suits[player] = missing_suit def can_win(self, hand): """ 判断是否满足胡牌条件:四组(顺子或刻子)+ 一对将。 """ from collections import Counter def is_valid_group(tiles): """ 判断是否为合法的顺子或刻子。 """ if len(tiles) != 3: return False tiles.sort() # 确保顺子检查按顺序排列 return (tiles[0] == tiles[1] == tiles[2]) or \ (tiles[0] + 1 == tiles[1] and tiles[1] + 1 == tiles[2]) def try_win(remaining_tiles, depth=0): """ 递归检查是否可以将剩余牌分为合法组合。 """ if not remaining_tiles: return depth == 4 # 必须分成四组 for i in range(len(remaining_tiles)): for j in range(i + 1, len(remaining_tiles)): for k in range(j + 1, len(remaining_tiles)): group = [remaining_tiles[i], remaining_tiles[j], remaining_tiles[k]] if is_valid_group(group): next_tiles = remaining_tiles[:i] + remaining_tiles[i + 1:j] + \ remaining_tiles[j + 1:k] + remaining_tiles[k + 1:] # 确保顺子检查按顺序排列 next_tiles.sort() if try_win(next_tiles, depth + 1): return True return False counter = Counter({tile: count for tile, count in enumerate(hand) if count > 0}) pairs = [tile for tile, count in counter.items() if count >= 2] for pair in pairs: temp_hand = hand[:] temp_hand[pair] -= 2 # 移除将牌 remaining_tiles = [tile for tile, count in enumerate(temp_hand) for _ in range(count)] remaining_tiles.sort() # 确保顺子检查按顺序排列 if try_win(remaining_tiles): return True return False