124 lines
4.7 KiB
Python
124 lines
4.7 KiB
Python
from loguru import logger
|
||
from src.engine.utils import get_tile_name
|
||
|
||
|
||
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 # 加入当前玩家手牌
|
||
|
||
tile_name = get_tile_name(tile) # 获取具体的牌名
|
||
logger.info(
|
||
f"玩家 {engine.state.current_player} 摸到一张牌: {tile_name}(索引 {tile})。剩余牌堆数量: {engine.state.remaining_tiles}"
|
||
)
|
||
|
||
# 返回奖励和游戏是否结束的标志
|
||
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}")
|
||
raise ValueError("玩家没有这张牌")
|
||
|
||
self.state.hands[self.state.current_player][tile] -= 1 # 从手牌中移除
|
||
self.state.discards[self.state.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]]}"
|
||
)
|
||
|
||
|
||
def peng(self, tile):
|
||
"""
|
||
当前玩家碰牌逻辑,记录碰牌操作和手牌状态。
|
||
"""
|
||
player = self.state.current_player
|
||
if self.state.hands[player][tile] < 2:
|
||
logger.error(f"玩家 {player} 尝试碰牌失败: {get_tile_name(tile)}(索引 {tile})")
|
||
raise ValueError("碰牌条件不满足")
|
||
|
||
self.state.hands[player][tile] -= 2 # 减去两张牌
|
||
self.state.melds[player].append(("peng", tile)) # 加入明牌列表
|
||
|
||
tile_name = get_tile_name(tile)
|
||
logger.info(f"玩家 {player} 碰了一张牌: {tile_name}(索引 {tile})。当前明牌: {self.state.melds[player]}")
|
||
|
||
|
||
def gang(self, tile, mode):
|
||
"""
|
||
当前玩家杠牌逻辑,记录杠牌类型和状态更新。
|
||
"""
|
||
player = self.state.current_player
|
||
tile_name = get_tile_name(tile)
|
||
|
||
if mode == "ming" and self.state.hands[player][tile] == 3:
|
||
self.state.hands[player][tile] -= 3
|
||
self.state.melds[player].append(("ming_gang", tile))
|
||
logger.info(f"玩家 {player} 明杠: {tile_name}(索引 {tile})")
|
||
self.state.scores[player] += 1 # 奖励1分
|
||
logger.info(f"玩家 {player} 因明杠获得1分")
|
||
|
||
elif mode == "an" and self.state.hands[player][tile] == 4:
|
||
self.state.hands[player][tile] -= 4
|
||
self.state.melds[player].append(("an_gang", tile))
|
||
logger.info(f"玩家 {player} 暗杠: {tile_name}(索引 {tile})")
|
||
self.state.scores[player] += 1 # 奖励1分
|
||
logger.info(f"玩家 {player} 因暗杠获得1分")
|
||
|
||
else:
|
||
logger.error(f"玩家 {player} 尝试杠牌失败: {tile_name}(索引 {tile}),条件不满足")
|
||
raise ValueError("杠牌条件不满足")
|
||
|
||
|
||
|
||
def check_blood_battle(self):
|
||
"""
|
||
检查游戏是否流局或血战结束,记录状态。
|
||
"""
|
||
if any(score <= 0 for score in self.state.scores):
|
||
logger.info(f"游戏结束,某玩家分数小于等于0: {self.state.scores}")
|
||
self.game_over = True
|
||
|
||
if len(self.state.winners) >= 3 or self.state.remaining_tiles == 0:
|
||
logger.info(f"游戏结束,赢家列表: {self.state.winners}")
|
||
self.game_over = True
|
||
|
||
|
||
def set_missing_suit(player, missing_suit, game_state):
|
||
"""
|
||
玩家设置缺门的动作。
|
||
|
||
参数:
|
||
- player: 玩家索引(0-3)。
|
||
- missing_suit: 玩家选择的缺门("条"、"筒" 或 "万")。
|
||
- game_state: 当前的游戏状态(`ChengduMahjongState` 实例)。
|
||
|
||
异常:
|
||
- ValueError: 如果缺门设置无效。
|
||
"""
|
||
valid_suits = ["条", "筒", "万"]
|
||
if missing_suit not in valid_suits:
|
||
logger.error(f"玩家 {player} 尝试设置无效的缺门: {missing_suit}")
|
||
raise ValueError("缺门设置无效")
|
||
|
||
if game_state.missing_suits[player] is not None:
|
||
logger.error(f"玩家 {player} 已经设置了缺门,不能重复设置")
|
||
raise ValueError("缺门已经设置,不能重复设置")
|
||
|
||
game_state.missing_suits[player] = missing_suit
|
||
logger.info(f"玩家 {player} 设置缺门为: {missing_suit}")
|
||
|
||
return game_state.missing_suits[player] |