89 lines
3.6 KiB
Python
89 lines
3.6 KiB
Python
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) |