mjAi/src/engine/actions.py

124 lines
4.7 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 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 # 奖励为 0done 为 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]