90 lines
3.4 KiB
Python
90 lines
3.4 KiB
Python
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
|