mjAi/src/engine/hand.py

89 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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)