This commit is contained in:
2024-11-30 23:26:13 +08:00
parent c3dc6cf234
commit ccbe55dbc7
4 changed files with 134 additions and 22 deletions

View File

@@ -2,7 +2,7 @@ import random
from loguru import logger
from .game_state import ChengduMahjongState
from .chengdu_mahjong_state import ChengduMahjongState
class ChengduMahjongEngine:

View File

@@ -1,7 +1,7 @@
from collections import Counter
from .hand import Hand
from .mahjong_tile import MahjongTile
from loguru import logger
class ChengduMahjongState:
def __init__(self):
@@ -40,28 +40,33 @@ class ChengduMahjongState:
raise ValueError("缺门设置无效")
self.missing_suits[player] = missing_suit
def can_win(self, hand: Hand):
def can_win(self, hand: Hand, missing_suit: str):
"""
判断是否满足胡牌条件四组顺子或刻子+ 一对将
判断玩家是否能胡牌
:param hand: 玩家手牌Hand 对象
:param missing_suit: 玩家设置的缺门花色
:return: True 表示能胡牌False 表示不能胡牌
"""
def is_valid_group(tiles):
"""
判断是否合法的顺子或刻子
检查是否合法AAA ABC
"""
if len(tiles) != 3:
return False
tiles.sort(key=lambda t: (t.suit, t.value))
return (tiles[0] == tiles[1] == tiles[2]) or \
(tiles[0].value + 1 == tiles[1].value and tiles[1].value + 1 == tiles[2].value and
tiles[0].suit == tiles[1].suit == tiles[2].suit)
tiles.sort(key=lambda t: (t.suit, t.value)) # 按花色和数值排序
return (tiles[0].value == tiles[1].value == tiles[2].value and # AAA
tiles[0].suit == tiles[1].suit == tiles[2].suit) or \
(tiles[0].value + 1 == tiles[1].value and # ABC
tiles[1].value + 1 == tiles[2].value and
tiles[0].suit == tiles[1].suit == tiles[2].suit)
def try_win(remaining_tiles, depth=0):
"""
递归检查是否可以将剩余牌分为合法组合
尝试将剩余牌分组必须满足 n * AAA + m * ABC
"""
if not remaining_tiles:
return depth == 4 # 必须分成四
return True # 所有牌成功分
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)):
@@ -73,18 +78,27 @@ class ChengduMahjongState:
return True
return False
# 统计每张牌的数量
# **第一步:检查花色限制**
suits = {tile.suit for tile in hand.tiles}
if len(suits) > 2:
logger.info("花色超过两种,不能胡牌")
return False # 花色超过两种,不能胡牌
# 检查是否打完缺门的花色
if any(tile.suit == missing_suit for tile in hand.tiles):
return False # 仍有缺门的花色,不能胡牌
# **第二步:寻找对子并分组**
# 找到所有对子(至少两张相同的牌)
tile_counter = Counter(hand.tiles)
pairs = [tile for tile, count in tile_counter.items() if count >= 2]
# 遍历所有对子,尝试用剩余牌分组
for pair in pairs:
# 移除一对将牌
temp_tiles = hand.tiles[:]
temp_tiles.remove(pair)
temp_tiles.remove(pair)
# 检查剩余牌是否能分组
if try_win(temp_tiles):
temp_tiles.remove(pair) # 移除一张将牌
temp_tiles.remove(pair) # 再移除一张将牌
if try_win(temp_tiles): # 检查是否可以分组
return True
return False
return False # 如果没有找到符合条件的组合,则不能胡牌