Skip to content

Instantly share code, notes, and snippets.

@hamukichi
Last active July 2, 2020 13:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hamukichi/58fba8acd3e034ec5ed542802a356846 to your computer and use it in GitHub Desktop.
Save hamukichi/58fba8acd3e034ec5ed542802a356846 to your computer and use it in GitHub Desktop.
Python 用ライブラリ mahjong を利用し,与えられた手牌について,和了していれば点数を計算し,さもなければ向聴数を計算する.鳴きには対応させていない(ライブラリ自体には機能が備わっている).
#!/usr/bin/env python3
# Hamukichi (Nombiri), MIT License
from mahjong import agari, constants, shanten, tile
from mahjong.hand_calculating import hand, hand_config
import fire
import copy
OPT_RULES = hand_config.OptionalRules(has_open_tanyao=True)
WIND_STR2CONST = {"EAST": constants.EAST,
"SOUTH": constants.SOUTH,
"WEST": constants.WEST,
"NORTH": constants.NORTH}
WIND_STR2CHARA = {"EAST": "東",
"SOUTH": "南",
"WEST": "西",
"NORTH": "北"}
def __analyze(all_tiles, win_tile, player_wind, round_wind, **hand_confs):
all_tiles_136 = tile.TilesConverter.one_line_string_to_136_array(all_tiles)
all_tiles_34 = tile.TilesConverter.one_line_string_to_34_array(all_tiles)
win_tile_136 = tile.TilesConverter.one_line_string_to_136_array(win_tile)[0]
player_wind = player_wind.upper()
round_wind = round_wind.upper()
player_wind_136 = WIND_STR2CONST[player_wind]
round_wind_136 = WIND_STR2CONST[round_wind]
all_hand_confs = copy.copy(hand_confs)
all_hand_confs["player_wind"] = player_wind_136
all_hand_confs["round_wind"] = round_wind_136
config = hand_config.HandConfig(options=OPT_RULES, **all_hand_confs)
sh_obj = shanten.Shanten()
sh_res = sh_obj.calculate_shanten(all_tiles_34)
ag = agari.Agari()
if not ag.is_agari(all_tiles_34):
return (sh_res, None)
else:
calc = hand.HandCalculator()
hand_res = calc.estimate_hand_value(tiles=all_tiles_136,
win_tile=win_tile_136,
config=config)
wind = "{}場{}".format(WIND_STR2CHARA[round_wind], WIND_STR2CHARA[player_wind])
han_fu = "{} 飜 {} 符".format(hand_res.han, hand_res.fu)
if hand_res.han <= 5:
basic_score = hand_res.fu * 2 ** (hand_res.han + 2)
if basic_score > 2000:
gan = "満貫"
else:
gan = ""
elif hand_res.han <= 7:
gan = "跳満"
elif hand_res.han <= 10:
gan = "倍満"
elif hand_res.han <= 12:
gan = "三倍満"
else:
n = hand_res.han // 13
if n == 1:
gan = "役満"
else:
gan = "{} 倍役満".format(n)
is_tsumo = hand_confs.get("is_tsumo", False)
is_dealer = player_wind == "EAST"
if hand_res.han < 1:
all_cost = "1 飜縛りを満たしていません"
elif is_tsumo:
if is_dealer:
all_cost = "{} 点 オール".format(hand_res.cost["additional"])
else:
all_cost = "{} 点 / {} 点".format(hand_res.cost["additional"],
hand_res.cost["main"])
else:
all_cost = "{} 点".format(hand_res.cost["main"])
hand_report = {"hand_res": hand_res, "wind": wind,
"han_fu": han_fu, "gan": gan, "all_cost": all_cost, "yakus": hand_res.yaku}
return (sh_res, hand_report)
def analyze(all_tiles, win_tile, player_wind="SOUTH", round_wind="EAST", **hand_confs):
analyze_res = __analyze(all_tiles, win_tile, player_wind, round_wind, **hand_confs)
sh_res, hand_report = analyze_res
if hand_report is None:
if sh_res != 0:
print("{} 向聴".format(sh_res))
else:
print("聴牌")
else:
print(hand_report["wind"])
print(hand_report["han_fu"], end=" ")
print(hand_report["gan"])
print(hand_report["all_cost"])
if hand_report["yakus"] is not None:
for yaku in hand_report["yakus"]:
print(yaku.japanese)
def main():
fire.Fire(analyze)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment