mahjong.hand_calculating.scores
Score calculation for winning hands.
Classes
ScoresResult- typed dictionary holding the score breakdownScoresCalculator- standard scoring with han/fu, honba, and kyoutaku bonusesAotenjou- variant scoring with no mangan cap (aotenjou rule)
- class mahjong.hand_calculating.scores.ScoresResult[source]
Bases:
TypedDictScore breakdown for a winning hand.
Each field represents a component of the final payment between players. The meaning of
mainandadditionaldepends on the win method:Ron:
mainis the full payment from the discarding player;additionalis always 0.Dealer tsumo:
mainandadditionalare equal — each non-dealer pays the same amount.Non-dealer tsumo:
mainis the dealer’s payment;additionalis the payment from each non-dealer.
- Parameters:
main – base cost (before honba bonus)
additional – base cost for each non-dealer (before honba bonus); 0 for ron
main_bonus – honba bonus added to
mainadditional_bonus – honba bonus added to
additionalkyoutaku_bonus – points from accumulated riichi deposits (1000 per deposit)
total – total points the winner earns
yaku_level – scoring tier label (e.g.
"mangan","yakuman",""for below mangan)
- class mahjong.hand_calculating.scores.ScoresCalculator[source]
Bases:
objectCalculate scores for a winning hand using standard Japanese mahjong rules.
Scores are determined by han and fu values, then adjusted for honba (tsumi) counters and kyoutaku (riichi deposit) bonuses. Hands at or above 5 han receive fixed-tier payouts (mangan through yakuman).
- static calculate_scores(han, fu, config, is_yakuman=False)[source]
Calculate score payment for a hand with the given han and fu.
Determine the base payment from han/fu, apply scoring tier caps (mangan, haneman, baiman, sanbaiman, yakuman), then add honba and kyoutaku bonuses.
A non-dealer ron at 3 han 30 fu:
>>> from mahjong.hand_calculating.scores import ScoresCalculator >>> from mahjong.hand_calculating.hand_config import HandConfig >>> result = ScoresCalculator.calculate_scores(han=3, fu=30, config=HandConfig()) >>> result["main"] 3900 >>> result["additional"] 0 >>> result["total"] 3900
A dealer tsumo mangan with 2 honba and 3 riichi deposits:
>>> from mahjong.constants import EAST >>> config = HandConfig(is_tsumo=True, player_wind=EAST, tsumi_number=2, kyoutaku_number=3) >>> result = ScoresCalculator.calculate_scores(han=5, fu=30, config=config) >>> result["main"] 4000 >>> result["additional"] 4000 >>> result["total"] 15600
Mangan (5 han):
>>> result = ScoresCalculator.calculate_scores(han=5, fu=30, config=HandConfig()) >>> result["yaku_level"] 'mangan' >>> result["main"] 8000
- Parameters:
han (int) – number of han (doubles)
fu (int) – fu (minipoints), rounded to nearest 10
config (HandConfig) – hand configuration with win method, dealer status, and bonuses
is_yakuman (bool) – True if the hand contains yakuman yaku (bypasses kazoe limit)
- Returns:
ScoresResultwith the full score breakdown- Return type:
- class mahjong.hand_calculating.scores.Aotenjou[source]
Bases:
ScoresCalculatorVariant scoring calculator for the aotenjou (blue ceiling) rule.
Under aotenjou, there is no mangan cap — the base-points formula
fu * 2^(2+han)is applied directly regardless of han count. Honba and kyoutaku bonuses are not applied. Yakuman yaku are treated as normal yaku and contribute their han values rather than triggering fixed payouts.- static calculate_scores(han, fu, config, is_yakuman=False)[source]
Calculate score payment under aotenjou rules.
Apply the base-points formula without any mangan cap or scoring tiers. Honba and kyoutaku bonuses are not included.
A non-dealer ron at 13 han 40 fu under aotenjou:
>>> from mahjong.hand_calculating.scores import Aotenjou >>> from mahjong.hand_calculating.hand_config import HandConfig >>> result = Aotenjou.calculate_scores(han=13, fu=40, config=HandConfig()) >>> result["main"] 5242900 >>> result["yaku_level"] ''
- Parameters:
han (int) – number of han (doubles)
fu (int) – fu (minipoints)
config (HandConfig) – hand configuration with win method and dealer status
is_yakuman (bool) – unused (aotenjou treats yakuman as normal yaku)
- Returns:
ScoresResultwith the score breakdown (no bonuses)- Return type:
- static aotenjou_filter_yaku(hand_yaku, config)[source]
Remove lower yaku that are precursors to yakuman yaku in aotenjou mode.
Under aotenjou, yakuman are scored as normal yaku with their han values. When a yakuman is present, its precursor yaku (e.g. shosangen for daisangen, toitoi for chinroto) must be removed to avoid double-counting.
- Parameters:
hand_yaku (MutableSequence[Yaku] | MutableSet[Yaku]) – mutable collection of yaku in the hand; modified in place
config (HandConfig) – hand configuration providing yaku definitions
- Return type:
None