parent
5e4f49edbb
commit
b54b46ca11
|
|
@ -1,4 +1,4 @@
|
||||||
from src.engine.utils import try_win
|
from src.engine.utils import try_win,is_terminal_tile
|
||||||
|
|
||||||
def is_basic_win(hand):
|
def is_basic_win(hand):
|
||||||
# 将手牌转换为列表并按花色和数值排序
|
# 将手牌转换为列表并按花色和数值排序
|
||||||
|
|
@ -12,10 +12,7 @@ def is_basic_win(hand):
|
||||||
|
|
||||||
|
|
||||||
def is_cleared(hand, melds):
|
def is_cleared(hand, melds):
|
||||||
"""
|
# 合并所有牌(手牌和明牌)
|
||||||
检查手牌和明牌是否符合清一色的番型。
|
|
||||||
"""
|
|
||||||
# 获取手牌和明牌的所有牌
|
|
||||||
all_tiles = hand.tiles[:]
|
all_tiles = hand.tiles[:]
|
||||||
for meld in melds:
|
for meld in melds:
|
||||||
if meld.is_triplet():
|
if meld.is_triplet():
|
||||||
|
|
@ -28,12 +25,11 @@ def is_cleared(hand, melds):
|
||||||
if len(suits) != 1:
|
if len(suits) != 1:
|
||||||
return 0 # 不是清一色
|
return 0 # 不是清一色
|
||||||
|
|
||||||
# 检查杠的数量
|
# 计算杠的数量
|
||||||
gang_count = sum(1 for meld in melds if meld.is_kong())
|
gang_count = sum(1 for meld in melds if meld.is_kong())
|
||||||
|
|
||||||
# 根据杠的数量和是否符合基本胡规则确定番数
|
# 检查是否符合基本胡规则(四坎牌加一对将)
|
||||||
sorted_tiles = sorted(hand.tiles, key=lambda t: (t.suit, t.value))
|
if try_win(hand.tiles):
|
||||||
if try_win(sorted_tiles): # 检查是否符合基本胡(四坎牌加一对将)
|
|
||||||
if gang_count == 0:
|
if gang_count == 0:
|
||||||
return 2 # 素清
|
return 2 # 素清
|
||||||
elif gang_count == 1:
|
elif gang_count == 1:
|
||||||
|
|
@ -41,3 +37,36 @@ def is_cleared(hand, melds):
|
||||||
elif gang_count >= 2:
|
elif gang_count >= 2:
|
||||||
return 4 # 极中极
|
return 4 # 极中极
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_terminal_fan(hand, melds):
|
||||||
|
"""
|
||||||
|
计算带幺九番型,并返回对应番数。
|
||||||
|
"""
|
||||||
|
# 合并所有牌(手牌和明牌)
|
||||||
|
all_tiles = hand.tiles[:]
|
||||||
|
for meld in melds:
|
||||||
|
if meld.is_triplet():
|
||||||
|
all_tiles.extend([meld.tile] * 3)
|
||||||
|
elif meld.is_kong():
|
||||||
|
all_tiles.extend([meld.tile] * 4)
|
||||||
|
|
||||||
|
# 检查是否同时包含 1 和 9
|
||||||
|
contains_one = any(tile.value == 1 for tile in all_tiles)
|
||||||
|
contains_nine = any(tile.value == 9 for tile in all_tiles)
|
||||||
|
if not (contains_one and contains_nine):
|
||||||
|
return 0 # 不符合带幺九
|
||||||
|
|
||||||
|
# 检查是否符合花色限制
|
||||||
|
suits = {tile.suit for tile in all_tiles}
|
||||||
|
if len(suits) > 2:
|
||||||
|
return 0 # 不符合花色要求
|
||||||
|
|
||||||
|
# 检查是否符合基本胡规则(四坎牌加一对将)
|
||||||
|
sorted_tiles = sorted(all_tiles, key=lambda t: (t.suit, t.value))
|
||||||
|
if try_win(sorted_tiles):
|
||||||
|
return 3 # 带幺九
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,54 @@
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
def is_valid_group(tiles):
|
def is_valid_group(tiles):
|
||||||
"""
|
"""
|
||||||
判断是否是合法的刻子(AAA)或顺子(ABC)。
|
检查是否是合法组(AAA 或 ABC)。
|
||||||
"""
|
"""
|
||||||
if len(tiles) != 3:
|
if len(tiles) != 3:
|
||||||
return False
|
return False
|
||||||
tiles.sort(key=lambda t: (t.suit, t.value)) # 按花色和数值排序
|
tiles.sort(key=lambda t: (t.suit, t.value)) # 按花色和数值排序
|
||||||
# 判断是否为刻子
|
return (tiles[0].value == tiles[1].value == tiles[2].value and # AAA
|
||||||
if tiles[0].value == tiles[1].value == tiles[2].value and \
|
tiles[0].suit == tiles[1].suit == tiles[2].suit) or \
|
||||||
tiles[0].suit == tiles[1].suit == tiles[2].suit:
|
(tiles[0].value + 1 == tiles[1].value and # ABC
|
||||||
return True
|
tiles[1].value + 1 == tiles[2].value and
|
||||||
# 判断是否为顺子
|
tiles[0].suit == tiles[1].suit == tiles[2].suit)
|
||||||
if 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:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def try_win(remaining_tiles, groups_formed=0, has_pair=False):
|
def try_win(remaining_tiles, pairs_found=False):
|
||||||
"""
|
"""
|
||||||
尝试将剩余牌分组为合法的刻子或顺子,并检查是否有一对将牌。
|
尝试将剩余牌分组,必须满足 n * AAA + m * ABC + DD。
|
||||||
"""
|
"""
|
||||||
# 如果没有剩余牌,检查是否形成了四坎牌且有一对将牌
|
# 如果没有剩余牌,检查是否已经找到对子
|
||||||
if not remaining_tiles:
|
if not remaining_tiles:
|
||||||
return groups_formed == 4 and has_pair
|
return pairs_found # 必须存在一个对子
|
||||||
|
|
||||||
# 检查是否可以找到一对将牌
|
# 尝试找到一个对子
|
||||||
if not has_pair: # 如果还没有找到将牌
|
if not pairs_found:
|
||||||
for i in range(len(remaining_tiles) - 1):
|
tile_counter = Counter(remaining_tiles)
|
||||||
if remaining_tiles[i] == remaining_tiles[i + 1]: # 找到对子
|
for tile, count in tile_counter.items():
|
||||||
temp_tiles = remaining_tiles[:i] + remaining_tiles[i + 2:] # 移除对子
|
if count >= 2: # 找到一个对子
|
||||||
if try_win(temp_tiles, groups_formed, has_pair=True):
|
temp_tiles = remaining_tiles[:]
|
||||||
|
temp_tiles.remove(tile)
|
||||||
|
temp_tiles.remove(tile)
|
||||||
|
if try_win(temp_tiles, pairs_found=True):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 检查是否可以形成合法组(刻子或顺子)
|
# 尝试找到一个合法组(AAA 或 ABC)
|
||||||
for i in range(len(remaining_tiles)):
|
for i in range(len(remaining_tiles)):
|
||||||
for j in range(i + 1, len(remaining_tiles)):
|
for j in range(i + 1, len(remaining_tiles)):
|
||||||
for k in range(j + 1, len(remaining_tiles)):
|
for k in range(j + 1, len(remaining_tiles)):
|
||||||
group = [remaining_tiles[i], remaining_tiles[j], remaining_tiles[k]]
|
group = [remaining_tiles[i], remaining_tiles[j], remaining_tiles[k]]
|
||||||
if is_valid_group(group):
|
if is_valid_group(group):
|
||||||
temp_tiles = (
|
next_tiles = remaining_tiles[:i] + remaining_tiles[i + 1:j] + \
|
||||||
remaining_tiles[:i]
|
remaining_tiles[j + 1:k] + remaining_tiles[k + 1:]
|
||||||
+ remaining_tiles[i + 1:j]
|
if try_win(next_tiles, pairs_found):
|
||||||
+ remaining_tiles[j + 1:k]
|
|
||||||
+ remaining_tiles[k + 1:]
|
|
||||||
)
|
|
||||||
if try_win(temp_tiles, groups_formed + 1, has_pair):
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_terminal_tile(tile):
|
||||||
|
"""
|
||||||
|
检查单张牌是否是幺九牌(1 或 9)。
|
||||||
|
"""
|
||||||
|
return tile.value in {1, 9}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from src.engine.hand import Hand
|
from src.engine.hand import Hand
|
||||||
from src.engine.mahjong_tile import MahjongTile
|
from src.engine.mahjong_tile import MahjongTile
|
||||||
from src.engine.fan_type import is_basic_win,is_cleared
|
from src.engine.fan_type import is_basic_win,is_cleared,calculate_terminal_fan
|
||||||
from src.engine.meld import Meld
|
from src.engine.meld import Meld
|
||||||
|
|
||||||
def test_is_basic_win():
|
def test_is_basic_win():
|
||||||
|
|
@ -80,3 +80,24 @@ def test_is_cleared_with_one_gang():
|
||||||
assert is_cleared(hand, melds) == 3, "测试失败:极品应为 3 番"
|
assert is_cleared(hand, melds) == 3, "测试失败:极品应为 3 番"
|
||||||
print("测试通过:极品")
|
print("测试通过:极品")
|
||||||
|
|
||||||
|
def test_calculate_terminal_fan():
|
||||||
|
"""测试带幺九番型"""
|
||||||
|
|
||||||
|
# 示例1:基本带幺九
|
||||||
|
hand = Hand()
|
||||||
|
hand.add_tile(MahjongTile("条", 1))
|
||||||
|
hand.add_tile(MahjongTile("条", 2))
|
||||||
|
hand.add_tile(MahjongTile("条", 3))
|
||||||
|
hand.add_tile(MahjongTile("条", 7))
|
||||||
|
hand.add_tile(MahjongTile("条", 8))
|
||||||
|
hand.add_tile(MahjongTile("条", 9))
|
||||||
|
hand.add_tile(MahjongTile("筒", 1))
|
||||||
|
hand.add_tile(MahjongTile("筒", 1))
|
||||||
|
hand.add_tile(MahjongTile("筒", 1))
|
||||||
|
hand.add_tile(MahjongTile("筒", 9))
|
||||||
|
hand.add_tile(MahjongTile("筒", 9))
|
||||||
|
hand.add_tile(MahjongTile("筒", 9))
|
||||||
|
hand.add_tile(MahjongTile("条", 5))
|
||||||
|
hand.add_tile(MahjongTile("条", 5))
|
||||||
|
melds = []
|
||||||
|
assert calculate_terminal_fan(hand, melds) == 3, "测试失败:基本带幺九应为 3 番"
|
||||||
Loading…
Reference in New Issue