diff --git a/src/engine/actions.py b/src/engine/actions.py index bb19e86..8c973db 100644 --- a/src/engine/actions.py +++ b/src/engine/actions.py @@ -1,45 +1,85 @@ from loguru import logger -from src.engine.utils import get_tile_name +from src.engine.mahjong_tile import MahjongTile def draw_tile(engine): """ 当前玩家摸牌逻辑,记录牌的详细信息和游戏状态。 """ + # 检查牌堆是否已空 if engine.state.remaining_tiles == 0: logger.warning("牌堆已空,游戏结束!") engine.game_over = True return 0, True # 游戏结束时返回 0 和 done = True - tile = engine.state.deck.pop(0) # 从牌堆中取出一张牌 - engine.state.remaining_tiles -= 1 # 更新剩余牌数 - engine.state.hands[engine.state.current_player][tile] += 1 # 加入当前玩家手牌 + # 当前玩家 + current_player = engine.state.current_player - tile_name = get_tile_name(tile) # 获取具体的牌名 + # 从牌堆中摸一张牌 + tile = engine.state.deck.pop(0) # 从牌堆抽取一张牌 + engine.state.remaining_tiles -= 1 # 更新剩余牌数 + engine.state.hands[current_player].add_tile(tile) # 将牌加入当前玩家手牌 + + # 获取牌名 + tile_name = str(tile) # 调用 MahjongTile 的 __repr__ 方法 logger.info( - f"玩家 {engine.state.current_player} 摸到一张牌: {tile_name}(索引 {tile})。剩余牌堆数量: {engine.state.remaining_tiles}" + f"玩家 {current_player} 摸到一张牌: {tile_name}(索引 {tile})。" + f"剩余牌堆数量: {engine.state.remaining_tiles}" ) + # 检查摸到的牌是否属于缺门 + missing_suit = engine.state.missing_suits[current_player] + if tile.suit == missing_suit: + logger.info(f"玩家 {current_player} 摸到缺门牌: {tile_name},需要优先打出") + + # 切换到下一位玩家 + next_player = (current_player + 1) % 4 + engine.state.current_player = next_player + # 返回奖励和游戏是否结束的标志 return 0, False # 奖励为 0,done 为 False(游戏继续) - def discard_tile(self, tile): """ 当前玩家打牌逻辑,记录打出的牌和当前牌河信息。 """ - if self.state.hands[self.state.current_player][tile] == 0: - logger.error(f"玩家 {self.state.current_player} 尝试打出不存在的牌: 索引 {tile}") + current_player = self.state.current_player + hand = self.state.hands[current_player] + + # 检查牌的有效性 + if not isinstance(tile, MahjongTile): + logger.error(f"玩家 {current_player} 尝试打出无效的牌: {tile}") + raise ValueError("打出的牌必须是 MahjongTile 对象") + + # 检查是否有这张牌 + if hand[tile] == 0: + logger.error(f"玩家 {current_player} 尝试打出不存在的牌: {tile}") raise ValueError("玩家没有这张牌") - self.state.hands[self.state.current_player][tile] -= 1 # 从手牌中移除 - self.state.discards[self.state.current_player].append(tile) # 加入牌河 + # 检查缺门规则 + missing_suit = self.state.missing_suits[current_player] + if tile.suit == missing_suit and any(t.suit == missing_suit for t in hand.tiles): + logger.error(f"玩家 {current_player} 尝试打出非缺门的牌: {tile}") + raise ValueError("必须先打完缺门花色的牌") - tile_name = get_tile_name(tile) # 获取具体的牌名 + # 从手牌中移除 + hand[tile] -= 1 + self.state.discards[current_player].append(tile) + + # 打出的牌名 + tile_name = get_tile_name(tile) + + # 打出牌后打印状态 logger.info( - f"玩家 {self.state.current_player} 打出一张牌: {tile_name}(索引 {tile})。当前牌河: {[get_tile_name(t) for t in self.state.discards[self.state.current_player]]}" + f"玩家 {current_player} 打出一张牌: {tile_name}(索引 {tile})。" + f"当前牌河: {[get_tile_name(t) for t in self.state.discards[current_player]]}" ) + # 检查是否触发其他玩家的操作(碰、杠、胡牌) + self.check_other_players(tile) + + return tile + def peng(self, tile): """