mjAi/src/engine/game_state.py

90 lines
3.4 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 .utils import get_suit,get_tile_name
from loguru import logger
class ChengduMahjongState:
def __init__(self):
# 每个玩家的手牌使用108个索引表示
self.hands = [[0] * 108 for _ in range(4)] # 每个玩家108张牌的计数
# 每个玩家的打出的牌
self.discards = [[] for _ in range(4)] # 每个玩家的弃牌列表
# 每个玩家的明牌(碰、杠)
self.melds = [[] for _ in range(4)]
# 剩余的牌堆
self.deck = list(range(108)) # 0-107 表示108张牌
# 当前玩家索引
self.current_player = 0
# 玩家分数
self.scores = [100, 100, 100, 100]
# 剩余牌数量
self.remaining_tiles = 108
# 胜利玩家列表
self.winners = []
# 缺门信息
self.missing_suits = [None] * 4 # 每个玩家的缺门("条"、"筒" 或 "万"
def set_missing_suit(self, player, missing_suit):
"""
设置玩家的缺门信息。
参数:
- player: 玩家索引0-3
- missing_suit: 玩家选择的缺门("""""")。
异常:
- ValueError: 如果缺门设置无效。
"""
valid_suits = ["", "", ""]
if missing_suit not in valid_suits:
raise ValueError("缺门设置无效")
self.missing_suits[player] = missing_suit
def can_win(self, hand):
"""
判断是否满足胡牌条件:四组(顺子或刻子)+ 一对将。
"""
from collections import Counter
def is_valid_group(tiles):
"""
判断是否为合法的顺子或刻子。
"""
if len(tiles) != 3:
return False
tiles.sort() # 确保顺子检查按顺序排列
return (tiles[0] == tiles[1] == tiles[2]) or \
(tiles[0] + 1 == tiles[1] and tiles[1] + 1 == tiles[2])
def try_win(remaining_tiles, depth=0):
"""
递归检查是否可以将剩余牌分为合法组合。
"""
if not remaining_tiles:
return depth == 4 # 必须分成四组
for i in range(len(remaining_tiles)):
for j in range(i + 1, len(remaining_tiles)):
for k in range(j + 1, len(remaining_tiles)):
group = [remaining_tiles[i], remaining_tiles[j], remaining_tiles[k]]
if is_valid_group(group):
next_tiles = remaining_tiles[:i] + remaining_tiles[i + 1:j] + \
remaining_tiles[j + 1:k] + remaining_tiles[k + 1:]
# 确保顺子检查按顺序排列
next_tiles.sort()
if try_win(next_tiles, depth + 1):
return True
return False
counter = Counter({tile: count for tile, count in enumerate(hand) if count > 0})
pairs = [tile for tile, count in counter.items() if count >= 2]
for pair in pairs:
temp_hand = hand[:]
temp_hand[pair] -= 2 # 移除将牌
remaining_tiles = [tile for tile, count in enumerate(temp_hand) for _ in range(count)]
remaining_tiles.sort() # 确保顺子检查按顺序排列
if try_win(remaining_tiles):
return True
return False