Update actions.py
parent
6a6baeb460
commit
64c7b47a4b
|
|
@ -1,22 +1,24 @@
|
||||||
|
from random import random
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from src.engine.mahjong_tile import MahjongTile
|
from src.engine.mahjong_tile import MahjongTile
|
||||||
|
|
||||||
|
|
||||||
def draw_tile(engine):
|
def draw_tile(engine):
|
||||||
"""
|
"""
|
||||||
当前玩家摸牌逻辑,记录牌的详细信息和游戏状态。
|
当前玩家摸牌逻辑,按照顺序从牌堆顶部摸牌,并记录牌的详细信息和游戏状态。
|
||||||
"""
|
"""
|
||||||
# 检查牌堆是否已空
|
# 检查牌堆是否已空
|
||||||
if engine.state.remaining_tiles == 0:
|
if engine.state.remaining_tiles == 0:
|
||||||
logger.warning("牌堆已空,游戏结束!")
|
logger.warning("牌堆已空,游戏结束!")
|
||||||
engine.game_over = True
|
engine.game_over = True
|
||||||
return 0, True # 游戏结束时返回 0 和 done = True
|
return None, True # 游戏结束时返回 None 和 done = True
|
||||||
|
|
||||||
# 当前玩家
|
# 当前玩家
|
||||||
current_player = engine.state.current_player
|
current_player = engine.state.current_player
|
||||||
|
|
||||||
# 从牌堆中摸一张牌
|
# 从牌堆顶部摸一张牌
|
||||||
tile = engine.state.deck.pop(0) # 从牌堆抽取一张牌
|
tile = engine.state.deck.pop(0) # 按顺序从牌堆取出一张牌
|
||||||
engine.state.remaining_tiles -= 1 # 更新剩余牌数
|
engine.state.remaining_tiles -= 1 # 更新剩余牌数
|
||||||
engine.state.hands[current_player].add_tile(tile) # 将牌对象加入当前玩家手牌
|
engine.state.hands[current_player].add_tile(tile) # 将牌对象加入当前玩家手牌
|
||||||
|
|
||||||
|
|
@ -32,12 +34,8 @@ def draw_tile(engine):
|
||||||
if tile.suit == missing_suit:
|
if tile.suit == missing_suit:
|
||||||
logger.info(f"玩家 {current_player} 摸到缺门牌: {tile_name},需要优先打出")
|
logger.info(f"玩家 {current_player} 摸到缺门牌: {tile_name},需要优先打出")
|
||||||
|
|
||||||
# 切换到下一位玩家
|
# 返回摸到的牌和游戏是否结束的标志
|
||||||
next_player = (current_player + 1) % 4
|
return tile, False # 返回摸到的牌对象和游戏继续的标志
|
||||||
engine.state.current_player = next_player
|
|
||||||
|
|
||||||
# 返回奖励和游戏是否结束的标志
|
|
||||||
return 0, False # 奖励为 0,done 为 False(游戏继续)
|
|
||||||
|
|
||||||
def discard_tile(self, tile):
|
def discard_tile(self, tile):
|
||||||
"""
|
"""
|
||||||
|
|
@ -192,9 +190,10 @@ def set_missing_suit(player, game_state):
|
||||||
def check_other_players(self, tile):
|
def check_other_players(self, tile):
|
||||||
"""
|
"""
|
||||||
检查其他玩家是否可以对打出的牌进行操作(如碰、杠、胡牌)。
|
检查其他玩家是否可以对打出的牌进行操作(如碰、杠、胡牌)。
|
||||||
|
如果有玩家选择碰或杠,修改游戏状态和出牌顺序。
|
||||||
"""
|
"""
|
||||||
current_player = self.state.current_player
|
current_player = self.state.current_player
|
||||||
next_player = (current_player + 1) % 4
|
actions_taken = False
|
||||||
|
|
||||||
for player in range(4):
|
for player in range(4):
|
||||||
if player == current_player:
|
if player == current_player:
|
||||||
|
|
@ -203,20 +202,145 @@ def check_other_players(self, tile):
|
||||||
# 检查是否可以碰
|
# 检查是否可以碰
|
||||||
if self.state.hands[player].tile_count[tile] >= 2:
|
if self.state.hands[player].tile_count[tile] >= 2:
|
||||||
logger.info(f"玩家 {player} 可以碰玩家 {current_player} 的牌: {tile}")
|
logger.info(f"玩家 {player} 可以碰玩家 {current_player} 的牌: {tile}")
|
||||||
# 根据规则决定是否碰
|
if self.handle_peng(player, tile): # 执行碰牌逻辑
|
||||||
# 这里可以扩展为调用 AI 或玩家输入
|
actions_taken = True
|
||||||
# self.peng(tile)
|
break # 碰牌后不检查其他玩家
|
||||||
|
|
||||||
# 检查是否可以杠
|
# 检查是否可以杠
|
||||||
if self.state.hands[player].tile_count[tile] >= 3:
|
if self.state.hands[player].tile_count[tile] >= 3:
|
||||||
logger.info(f"玩家 {player} 可以杠玩家 {current_player} 的牌: {tile}")
|
logger.info(f"玩家 {player} 可以杠玩家 {current_player} 的牌: {tile}")
|
||||||
# 根据规则决定是否杠
|
if self.handle_gang(player, tile, mode="ming"): # 执行明杠逻辑
|
||||||
# self.gang(tile, mode="ming")
|
actions_taken = True
|
||||||
|
break # 杠牌后不检查其他玩家
|
||||||
|
|
||||||
# 检查是否可以胡牌
|
# 检查是否可以胡牌
|
||||||
if self.can_win(self.state.hands[player], self.state.melds[player], self.state.missing_suits[player]):
|
if self.can_win(self.state.hands[player], self.state.melds[player], self.state.missing_suits[player]):
|
||||||
logger.info(f"玩家 {player} 可以胡玩家 {current_player} 的牌: {tile}")
|
logger.info(f"玩家 {player} 可以胡玩家 {current_player} 的牌: {tile}")
|
||||||
# 根据规则决定是否胡牌
|
self.handle_win(player, current_player, tile)
|
||||||
# self.handle_win(player)
|
actions_taken = True
|
||||||
|
break # 胡牌后结束
|
||||||
|
|
||||||
logger.info(f"玩家 {current_player} 打出的牌 {tile} 没有触发其他玩家的操作")
|
if not actions_taken:
|
||||||
|
logger.info(f"玩家 {current_player} 打出的牌 {tile} 没有触发其他玩家的操作")
|
||||||
|
|
||||||
|
def handle_peng(self, player, tile):
|
||||||
|
"""
|
||||||
|
处理玩家碰牌逻辑并更新出牌顺序。
|
||||||
|
"""
|
||||||
|
if self.state.hands[player].tile_count[tile] < 2:
|
||||||
|
logger.error(f"玩家 {player} 无法碰牌: {tile}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 减少两张牌
|
||||||
|
self.state.hands[player].tile_count[tile] -= 2
|
||||||
|
self.state.melds[player].append(("peng", tile))
|
||||||
|
|
||||||
|
logger.info(f"玩家 {player} 碰了牌: {tile}。当前明牌: {self.state.melds[player]}")
|
||||||
|
|
||||||
|
# 设置出牌顺序为碰牌的玩家
|
||||||
|
self.state.current_player = player
|
||||||
|
|
||||||
|
# 提供玩家手牌信息,等待玩家选择打出的牌
|
||||||
|
chosen_tile = self.get_player_discard_choice(player)
|
||||||
|
|
||||||
|
# 验证玩家选择的牌是否合法
|
||||||
|
if chosen_tile not in self.state.hands[player].tiles:
|
||||||
|
logger.error(f"玩家 {player} 选择了不合法的牌: {chosen_tile}")
|
||||||
|
raise ValueError("打出的牌必须存在于玩家的手牌中")
|
||||||
|
|
||||||
|
# 玩家选择打出这张牌
|
||||||
|
self.discard_tile(player, chosen_tile)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_player_discard_choice(self, player):
|
||||||
|
"""
|
||||||
|
模拟获取玩家打牌的选择。
|
||||||
|
在实际项目中,使用 GUI 或 AI 决策替代。
|
||||||
|
"""
|
||||||
|
hand_tiles = self.state.hands[player].tiles
|
||||||
|
logger.info(f"玩家 {player} 当前手牌: {[str(tile) for tile in hand_tiles]}")
|
||||||
|
|
||||||
|
# 模拟玩家选择打出第一张非碰牌
|
||||||
|
chosen_tile = hand_tiles[0] # 在真实项目中替换为实际用户输入或AI决策
|
||||||
|
logger.info(f"玩家 {player} 选择打出牌: {chosen_tile}")
|
||||||
|
return chosen_tile
|
||||||
|
|
||||||
|
def handle_gang(self, player, tile, mode):
|
||||||
|
"""
|
||||||
|
处理玩家杠牌逻辑并更新状态。
|
||||||
|
"""
|
||||||
|
if mode == "ming" and self.state.hands[player].tile_count[tile] < 3:
|
||||||
|
logger.error(f"玩家 {player} 无法明杠: {tile}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 减少牌数量并更新明牌
|
||||||
|
if mode == "ming":
|
||||||
|
self.state.hands[player].tile_count[tile] -= 3
|
||||||
|
self.state.melds[player].append(("ming_gang", tile))
|
||||||
|
logger.info(f"玩家 {player} 明杠了牌: {tile}")
|
||||||
|
elif mode == "an":
|
||||||
|
if self.state.hands[player].tile_count[tile] < 4:
|
||||||
|
logger.error(f"玩家 {player} 无法暗杠: {tile}")
|
||||||
|
return False
|
||||||
|
self.state.hands[player].tile_count[tile] -= 4
|
||||||
|
self.state.melds[player].append(("an_gang", tile))
|
||||||
|
logger.info(f"玩家 {player} 暗杠了牌: {tile}")
|
||||||
|
|
||||||
|
# 杠牌后玩家补摸一张牌
|
||||||
|
self.draw_tile_for_player(player)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def random_discard_tile(engine):
|
||||||
|
"""
|
||||||
|
当前玩家随机选择一张牌打出,优先打缺门牌。
|
||||||
|
"""
|
||||||
|
current_player = engine.state.current_player
|
||||||
|
hand = engine.state.hands[current_player].tiles # 当前玩家的手牌
|
||||||
|
missing_suit = engine.state.missing_suits[current_player] # 当前玩家的缺门
|
||||||
|
|
||||||
|
if not hand:
|
||||||
|
logger.error(f"玩家 {current_player} 的手牌为空,无法打牌")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 使用改进后的 random_choice 函数选择牌
|
||||||
|
tile = random_choice(hand, missing_suit)
|
||||||
|
|
||||||
|
# 从手牌中移除该牌
|
||||||
|
engine.state.hands[current_player].remove_tile(tile)
|
||||||
|
engine.state.discards[current_player].append(tile)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"玩家 {current_player} 打出了一张牌: {tile}。"
|
||||||
|
f"当前牌河: {[str(t) for t in engine.state.discards[current_player]]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 检查其他玩家是否可以操作
|
||||||
|
engine.check_other_players(tile)
|
||||||
|
|
||||||
|
# 切换到下一个玩家
|
||||||
|
next_player = (current_player + 1) % 4
|
||||||
|
engine.state.current_player = next_player
|
||||||
|
|
||||||
|
|
||||||
|
def random_choice(hand, missing_suit):
|
||||||
|
"""
|
||||||
|
根据缺门优先随机选择打出的牌。
|
||||||
|
|
||||||
|
:param hand: 当前玩家的手牌(列表,包含 MahjongTile 对象)。
|
||||||
|
:param missing_suit: 当前玩家的缺门花色(字符串)。
|
||||||
|
:return: 随机选择的 MahjongTile 对象。
|
||||||
|
"""
|
||||||
|
if not hand:
|
||||||
|
raise ValueError("手牌不能为空")
|
||||||
|
|
||||||
|
# 筛选出缺门的牌
|
||||||
|
missing_suit_tiles = [tile for tile in hand if tile.suit == missing_suit]
|
||||||
|
|
||||||
|
# 如果缺门牌存在,优先从缺门牌中随机选择
|
||||||
|
if missing_suit_tiles:
|
||||||
|
index = random.randint(0, len(missing_suit_tiles) - 1)
|
||||||
|
return missing_suit_tiles[index]
|
||||||
|
|
||||||
|
# 如果缺门牌不存在,从剩余牌中随机选择
|
||||||
|
index = random.randint(0, len(hand) - 1)
|
||||||
|
return hand[index]
|
||||||
Loading…
Reference in New Issue