from src.engine.mahjong_tile import MahjongTile from collections import defaultdict class Hand: def __init__(self): # 存储所有的 MahjongTile 对象 self.tiles = [] # 存储每种牌的数量,键为 MahjongTile 对象,值为数量 self.tile_count = defaultdict(int) def add_tile(self, tile): """ 向手牌中添加一张牌 """ if not isinstance(tile, MahjongTile): raise ValueError("必须添加 MahjongTile 类型的牌") if len(self.tiles) >= 14: raise ValueError("手牌数量不能超过 14 张") self.tiles.append(tile) # 将牌添加到手牌中 self.tile_count[tile] += 1 # 增加牌的数量 def remove_tile(self, tile): """ 从手牌中移除一张牌 """ if not isinstance(tile, MahjongTile): raise ValueError("必须移除 MahjongTile 类型的牌") if self.tile_count[tile] > 0: self.tiles.remove(tile) self.tile_count[tile] -= 1 else: raise ValueError(f"手牌中没有该牌: {tile}") def get_tile_count(self, tile): """ 获取手牌中某张牌的数量 """ if not isinstance(tile, MahjongTile): raise ValueError("必须是 MahjongTile 类型的牌") return self.tile_count[tile] def can_peng(self, tile): """ 判断是否可以碰(即是否已经有2张相同的牌,摸一张牌后可以碰) """ if not isinstance(tile, MahjongTile): raise ValueError("必须是 MahjongTile 类型的牌") return self.tile_count[tile] == 2 # 摸一张牌后总数为 3 张,才可以碰 def can_gang(self, tile=None): """ 判断是否可以杠牌。 两种情况: 1. 当前手牌中已经有 4 张相同的牌,可以选择杠。 2. 当前手牌中有 3 张相同的牌,摸到第 4 张后可以杠。 :param tile: 需要判断的牌(可以为空)。 :return: True 如果可以杠,否则 False。 """ if tile is not None: # 情况 1: 摸到一张牌后形成四张 if not isinstance(tile, MahjongTile): raise ValueError("必须是 MahjongTile 类型的牌") return self.tile_count[tile] == 4 else: # 情况 2: 手牌中已有四张一样的牌 for t, count in self.tile_count.items(): if count == 4: return True return False def get_gang_type(self, tile=None): """ 判断杠牌的类型(暗杠或明杠)。 :param tile: 如果指定了牌,检查是否可以明杠。 :return: 杠牌类型,"暗杠" 或 "明杠",如果不能杠返回 None。 """ if tile is not None: # 明杠的判断逻辑:手牌中已有3张相同的牌,摸到第4张 if not isinstance(tile, MahjongTile): raise ValueError("必须是 MahjongTile 类型的牌") if self.tile_count[tile] == 4: return "明杠" else: # 暗杠的判断逻辑:手牌中已有4张相同的牌 for t, count in self.tile_count.items(): if count == 4: return "暗杠" return None def __repr__(self): """ 返回手牌的字符串表示 """ tiles_str = ", ".join(str(tile) for tile in self.tiles) return f"手牌: [{tiles_str}], 牌的数量: {dict(self.tile_count)}" def __iter__(self): """使 Hand 对象可迭代,直接迭代其 tiles 列表""" return iter(self.tiles)