diff --git a/src/engine/hand.py b/src/engine/hand.py index 931057a..ca4323d 100644 --- a/src/engine/hand.py +++ b/src/engine/hand.py @@ -1,21 +1,24 @@ -from collections import defaultdict - +from src.engine.mahjong_tile import MahjongTile from collections import defaultdict class Hand: def __init__(self): - # 存储所有的牌 + # 存储所有的 MahjongTile 对象 self.tiles = [] - # 存储每种牌的数量,默认值为 0 + # 存储每种牌的数量,键为 MahjongTile 对象,值为数量 self.tile_count = defaultdict(int) def add_tile(self, tile): """ 向手牌中添加一张牌 """ + if not isinstance(tile, MahjongTile): + raise ValueError("必须添加 MahjongTile 类型的牌") 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 @@ -24,16 +27,23 @@ class Hand: 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): """ 判断是否可以杠(即是否已经有3张相同的牌,摸一张牌后可以杠) """ - return self.tile_count[tile] == 3 # 摸一张牌后总数为 4 张,才可以杠 + if not isinstance(tile, MahjongTile): + raise ValueError("必须是 MahjongTile 类型的牌") + return self.tile_count[tile] == 4 # 摸一张牌后总数为 4 张,才可以杠 def __repr__(self): """ 返回手牌的字符串表示 """ - return f"手牌: {self.tiles}, 牌的数量: {dict(self.tile_count)}" + tiles_str = ", ".join(str(tile) for tile in self.tiles) + return f"手牌: [{tiles_str}], 牌的数量: {dict(self.tile_count)}" diff --git a/tests/test_hand.py b/tests/test_hand.py index 1d2d136..e0e9aa8 100644 --- a/tests/test_hand.py +++ b/tests/test_hand.py @@ -1,64 +1,87 @@ from src.engine.hand import Hand +from src.engine.mahjong_tile import MahjongTile -def test_hand(): - # 创建一个玩家的手牌 +def test_add_tile(): + """测试添加牌功能""" hand = Hand() + tile1 = MahjongTile("条", 1) + tile2 = MahjongTile("条", 2) - # 添加一些牌到手牌中 - hand.add_tile("1条") - hand.add_tile("1条") - hand.add_tile("2条") - hand.add_tile("2条") - hand.add_tile("2条") - hand.add_tile("3条") + hand.add_tile(tile1) + hand.add_tile(tile1) + hand.add_tile(tile2) + print("\n测试添加牌功能,当前手牌:", hand) - # 打印手牌 - print("\n当前手牌:", hand) + assert hand.get_tile_count(tile1) == 2, f"测试失败:{tile1} 应该有 2 张" + assert hand.get_tile_count(tile2) == 1, f"测试失败:{tile2} 应该有 1 张" - # 测试获取某张牌的数量 - assert hand.get_tile_count("1条") == 2, f"测试失败:1条应该有 2 张" - assert hand.get_tile_count("2条") == 3, f"测试失败:2条应该有 3 张" - assert hand.get_tile_count("3条") == 1, f"测试失败:3条应该有 1 张" - # 测试移除一张牌 - hand.remove_tile("1条") - print("移除 1条 后的手牌:", hand) - assert hand.get_tile_count("1条") == 1, f"测试失败:1条应该有 1 张" +def test_remove_tile(): + """测试移除牌功能""" + hand = Hand() + tile1 = MahjongTile("条", 1) - # 确保移除后有足够的牌可以碰 - # 添加一张 1条,确保可以碰 - hand.add_tile("1条") - print("添加 1条 后的手牌:", hand) + hand.add_tile(tile1) + hand.add_tile(tile1) + hand.remove_tile(tile1) + print("\n测试移除牌功能,移除一张 1条 后的手牌:", hand) - # 测试是否可以碰 - assert hand.can_peng("1条") == True, f"测试失败:1条应该可以碰" - print("可以碰 1条 的牌:", hand.can_peng("1条")) - assert hand.can_peng("3条") == False, f"测试失败:3条不可以碰" - print("不可以碰 3条 的牌:", hand.can_peng("3条")) + assert hand.get_tile_count(tile1) == 1, f"测试失败:{tile1} 应该有 1 张" - # 测试是否可以杠 - assert hand.can_gang("1条") == False, f"测试失败:1条不可以杠" - print("不可以杠 1条 的牌:", hand.can_gang("1条")) - assert hand.can_gang("2条") == False, f"测试失败:2条不可以杠" - print("不可以杠 2条 的牌:", hand.can_gang("2条")) + +def test_can_peng(): + """测试是否可以碰""" + hand = Hand() + tile1 = MahjongTile("条", 1) + tile2 = MahjongTile("条", 2) + + hand.add_tile(tile1) + hand.add_tile(tile1) + print("\n测试碰功能,当前手牌:", hand) + + assert hand.can_peng(tile1) == True, f"测试失败:{tile1} 应该可以碰" + assert hand.can_peng(tile2) == False, f"测试失败:{tile2} 不可以碰" + + print(f"可以碰 {tile1} 的牌:", hand.can_peng(tile1)) + print(f"不可以碰 {tile2} 的牌:", hand.can_peng(tile2)) + + +def test_can_gang(): + """测试是否可以杠""" + hand = Hand() + tile2 = MahjongTile("条", 2) + + hand.add_tile(tile2) + hand.add_tile(tile2) + hand.add_tile(tile2) + print("\n测试杠功能,当前手牌:", hand) + + assert hand.can_gang(tile2) == False, f"测试失败:{tile2} 不可以杠" # 添加更多牌来形成杠 - hand.add_tile("2条") - print("添加牌后手牌:", hand) - hand.add_tile("2条") - print("添加牌后手牌:", hand) - assert hand.can_gang("2条") == False, f"测试失败:2条不可以杠" # still not enough for gang + hand.add_tile(tile2) + print("再添加一张 2条 后:", hand) - # 添加一张更多的 2条 来形成杠 - hand.add_tile("2条") - print("添加一张2条后:", hand) - assert hand.can_gang("2条") == True, f"测试失败:2条应该可以杠" + assert hand.can_gang(tile2) == True, f"测试失败:{tile2} 应该可以杠" + + +def run_all_tests(): + """运行所有测试""" + test_add_tile() + print("测试添加牌功能通过!") + + test_remove_tile() + print("测试移除牌功能通过!") + + test_can_peng() + print("测试碰功能通过!") + + test_can_gang() + print("测试杠功能通过!") + + print("\n所有测试通过!") - print("所有测试通过!") # 运行测试 -test_hand() - - - +run_all_tests() \ No newline at end of file