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.dev3.tar.gz (35.8 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.dev3-py3-none-any.whl (68.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: mahjong-1.2.0.dev3.tar.gz
  • Upload date:
  • Size: 35.8 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.dev3.tar.gz
Algorithm Hash digest
SHA256 e9b472ecad560d3fa3d629b2822fdef06ad4acb0dac1f4ce691e2b0c7db6f48c
MD5 84016dfb93e5609a8f967b03192fb9fe
BLAKE2b-256 54a5666de69d8d0696fb9e3ca7d15df99df1d598399f107bf9e83392bd050ccd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: mahjong-1.2.0.dev3-py3-none-any.whl
  • Upload date:
  • Size: 68.3 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.dev3-py3-none-any.whl
Algorithm Hash digest
SHA256 52d0ab11e17712dd7826995d8998c6e2f4233c2f2c96ecde68bc2a64d840e4e8
MD5 cee07f1bf4efd63f92c945021dc09401
BLAKE2b-256 30efff6a38ec365c14aedcc1ef555d68882fc1369de71dc3a768d8f657c9d2fe

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