Skip to main content

Mahjong hands calculation

Project description

https://github.com/MahjongRepository/mahjong/workflows/Mahjong%20lib/badge.svg

Python 3.5+ is supported. If you need Python 2 support you can use v1.1.11 version of the library.

The library contains various tools (shanten, agari, hand calculation) for the Japanese version of mahjong (riichi mahjong).

Riichi mahjong hands calculation

This library can calculate hand cost (han, fu with details, yaku, and scores) for riichi mahjong (Japanese version).

It supports optional features like:

Feature

Keyword parameter

Default value

Disable or enable open tanyao yaku

has_open_tanyao

False

Disable or enable aka dora in the hand

has_aka_dora

False

Disable or enable double yakuman (like suuanko tanki)

has_double_yakuman

True

Settings for different kazoe yakuman calculation (it сan be an yakuman or a sanbaiman)

kazoe_limit

HandConstants.KAZOE_LIMITED

Support kiriage mangan

kiriage

False

Allow to disable additional +2 fu in open hand (you can make 1-20 hand with that setting)

fu_for_open_pinfu

True

Disable or enable pinfu tsumo

fu_for_pinfu_tsumo

False

Counting renhou as 5 han or yakuman

renhou_as_yakuman

False

Disable or enable Daisharin yakuman

has_daisharin

False

Disable or enable Daisharin in other suits (Daisuurin, Daichikurin)

has_daisharin_other_suits

False

Disable or enable yakuman for dealing into open hands

has_sashikomi_yakuman

False

Limit yakuman calculation to 6 (maximum score 192000)

limit_to_sextuple_yakuman

True

Disable or enable extra yakuman for all honors 7 pairs

has_daichisei

False

Disable or enable paarenchan without any yaku

paarenchan_needs_yaku

True

The code was validated on tenhou.net phoenix replays in total on 11,120,125 hands.

So, we can say that our hand calculator works the same way that tenhou.net hand calculation.

Project repository: https://github.com/MahjongRepository/mahjong

How to install

pip install mahjong

How to use

You can find more examples here: https://github.com/MahjongRepository/mahjong/blob/master/doc/examples.py

Let’s calculate how much will cost this hand:

https://user-images.githubusercontent.com/475367/30796350-3d30431a-a204-11e7-99e5-aab144c82f97.png

Tanyao hand by ron

from mahjong.hand_calculating.hand import HandCalculator
from mahjong.tile import TilesConverter
from mahjong.hand_calculating.hand_config import HandConfig
from mahjong.meld import Meld

calculator = HandCalculator()

# we had to use all 14 tiles in that array
tiles = TilesConverter.string_to_136_array(man='22444', pin='333567', sou='444')
win_tile = TilesConverter.string_to_136_array(sou='4')[0]

result = calculator.estimate_hand_value(tiles, win_tile)

print(result.han, result.fu)
print(result.cost['main'])
print(result.yaku)
for fu_item in result.fu_details:
    print(fu_item)

Output:

1 40
1300
[Tanyao]
{'fu': 30, 'reason': 'base'}
{'fu': 4, 'reason': 'closed_pon'}
{'fu': 4, 'reason': 'closed_pon'}
{'fu': 2, 'reason': 'open_pon'}

How about tsumo?

result = calculator.estimate_hand_value(tiles, win_tile, config=HandConfig(is_tsumo=True))

print(result.han, result.fu)
print(result.cost['main'], result.cost['additional'])
print(result.yaku)
for fu_item in result.fu_details:
    print(fu_item)

Output:

4 40
4000 2000
[Menzen Tsumo, Tanyao, San Ankou]
{'fu': 20, 'reason': 'base'}
{'fu': 4, 'reason': 'closed_pon'}
{'fu': 4, 'reason': 'closed_pon'}
{'fu': 4, 'reason': 'closed_pon'}
{'fu': 2, 'reason': 'tsumo'}

What if we add open set?

melds = [Meld(meld_type=Meld.PON, tiles=TilesConverter.string_to_136_array(man='444'))]

result = calculator.estimate_hand_value(tiles, win_tile, melds=melds, config=HandConfig(options=OptionalRules(has_open_tanyao=True)))

print(result.han, result.fu)
print(result.cost['main'])
print(result.yaku)
for fu_item in result.fu_details:
    print(fu_item)

Output:

1 30
1000
[Tanyao]
{'fu': 20, 'reason': 'base'}
{'fu': 4, 'reason': 'closed_pon'}
{'fu': 2, 'reason': 'open_pon'}
{'fu': 2, 'reason': 'open_pon'}

Shanten calculation

from mahjong.shanten import Shanten

shanten = Shanten()
tiles = TilesConverter.string_to_34_array(man='13569', pin='123459', sou='443')
result = shanten.calculate_shanten(tiles)

print(result)

Aotenjou scoring rules

tiles = self.TilesConverter.string_to_136_array(honors='11133555666777')
win_tile = self.TilesConverter.string_to_136_array(honors='3')[0]

melds = [
    Meld(meld_type=Meld.KAN, tiles=TilesConverter.string_to_136_array(honors='1111'), opened=False),
    Meld(meld_type=Meld.KAN, tiles=TilesConverter.string_to_136_array(honors='5555'), opened=False),
    Meld(meld_type=Meld.KAN, tiles=TilesConverter.string_to_136_array(honors='6666'), opened=False),
    Meld(meld_type=Meld.KAN, tiles=TilesConverter.string_to_136_array(honors='7777'), opened=False),
]

result = hand.estimate_hand_value(tiles, win_tile, melds=melds, dora_indicators=TilesConverter.string_to_136_array(honors='44447777'),
    scores_calculator_factory=Aotenjou, config=HandConfig(is_riichi=True, is_tsumo=True, is_ippatsu=True, is_haitei=True, player_wind=EAST, round_wind=EAST))

print(result.han, result.fu)
print(result.cost['main'])
print(result.yaku)
for fu_item in result.fu_details:
    print(fu_item)

Output:

95 160
50706024009129176059868128215100
[Menzen Tsumo, Riichi, Ippatsu, Haitei Raoyue, Yakuhai (wind of place), Yakuhai (wind of round), Daisangen, Suu kantsu, Tsuu iisou, Suu ankou tanki, Dora 24]
{'fu': 32, 'reason': 'closed_terminal_kan'}
{'fu': 32, 'reason': 'closed_terminal_kan'}
{'fu': 32, 'reason': 'closed_terminal_kan'}
{'fu': 32, 'reason': 'closed_terminal_kan'}
{'fu': 20, 'reason': 'base'}
{'fu': 2, 'reason': 'pair_wait'}
{'fu': 2, 'reason': 'tsumo'}

Releases History

1.1.11 (2020-10-28)

  • Speed up performance a bit

  • Add support for Python 3.9

1.1.10 (2020-05-11)

  • Add japanese yaku names

  • Fix an issue with not correct ryuuiisou detection

  • Allow to print aka dora in TilesConverter.to_one_line_string() method (“0” symbol)

  • Add support for Python 3.8

1.1.9 (2019-07-29)

  • Add TilesConverter.one_line_string_to_136_array() and TilesConverter.one_line_string_to_34_array() methods

1.1.8 (2019-07-25)

  • Fix an issue with incorrect daburu chuuren poutou calculations

  • Allow passing ‘0’ as a red five to tiles converter

1.1.7 (2019-04-09)

  • Introduce OptionalRules hand configuration

1.1.6 (2019-02-10)

  • Fix a bug when hatsu yaku was added to the hand instead of chun

  • Fix a bug where kokushi wasn’t combined with tenhou/renhou/chihou

  • Add English names to all yaku

  • Add support of python 2.7

  • Add a way to pass aka dora to tile converter

1.1.5 (2018-09-04)

  • Allow to disable chiitoitsu or kokushi in shanten calculator

1.1.4 (2018-08-31)

  • Add is_terminal() and is_dora_indicator_for_terminal() functions to the utils.py

1.1.3 (2018-08-22)

  • Add is_tile_strictly_isolated() function to the utils.py

1.1.2 (2017-10-14)

  • Add settings for different kazoe yakuman calculation (it kan be an yakuman or a sanbaiman)

  • Support up to sextuple yakuman scores

  • Support kiriage mangan

  • Allow to disable +2 fu in open hand

  • Allow to disable tsumo pinfu (add 2 additional fu for hand like that)

1.1.1 (2017-10-07)

  • Fix a bug with not correct agari state determination and closed kan in the hand

1.1.0 (2017-10-07)

Breaking changes:

  • Interface of hand calculator was changed. New interface will allow to easy support different game rules

Additional fixes:

  • Refactor hand divider. Allow to pass melds objects instead of arrays

  • Add file with usage examples

  • Minor project refactoring

1.0.5 (2017-09-25)

  • Improve installation script

1.0.4 (2017-09-25)

Bug fixes:

  • Fix refactoring regressions with kan sets and dora calculations

  • Fix regression with sankantsusuukantsu and called chankan

  • Closed kan can’t be used in chuuren poutou

  • Fix yaku ids (some of them had incorrect numbers)

Features:

  • Allow to disable double yakuman (like suuanko tanki)

  • Remove float calculations from scores and fu

  • Add travis build status

  • Add usage examples to the readme

1.0.3 (2017-09-23)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mahjong-1.2.0.dev4.tar.gz (35.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mahjong-1.2.0.dev4-py3-none-any.whl (68.1 kB view details)

Uploaded Python 3

File details

Details for the file mahjong-1.2.0.dev4.tar.gz.

File metadata

  • Download URL: mahjong-1.2.0.dev4.tar.gz
  • Upload date:
  • Size: 35.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.8.5

File hashes

Hashes for mahjong-1.2.0.dev4.tar.gz
Algorithm Hash digest
SHA256 efb3b83e8c92c59218bc3efb08dd70181e0aa4307f730bea54dabf1b86c33086
MD5 2a82af401c607b235a87a077a0537908
BLAKE2b-256 94b518afb27305c58fddda02ae4edfdca9be2fc1caebe9f5d8f6ddefed24db15

See more details on using hashes here.

File details

Details for the file mahjong-1.2.0.dev4-py3-none-any.whl.

File metadata

  • Download URL: mahjong-1.2.0.dev4-py3-none-any.whl
  • Upload date:
  • Size: 68.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.8.5

File hashes

Hashes for mahjong-1.2.0.dev4-py3-none-any.whl
Algorithm Hash digest
SHA256 0ddbb3f8ee94a0758eaa05a4688abb85ce0e7d8db742783cd10a5bfadb8c0563
MD5 f0895198100d99a515cd2bd7c8279cdf
BLAKE2b-256 3816309fd307fe180b297124e58293ccbf115f965b7be72b6dc512fd0b98895b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page