xiangting-py documentation

Python bindings for xiangting.

See also xiangting for more information.

The hand is represented as an array of list[int], where each element represents the count of a specific tile. The correspondence between the index and the tile is shown in the table below.

Index

0

1

2

3

4

5

6

7

8

Tile

1m

2m

3m

4m

5m

6m

7m

8m

9m

Index

9

10

11

12

13

14

15

16

17

Tile

1p

2p

3p

4p

5p

6p

7p

8p

9p

Index

18

19

20

21

22

23

24

25

26

Tile

1s

2s

3s

4s

5s

6s

7s

8s

9s

Index

27

28

29

30

31

32

33

Tile

East (1z)

South (2z)

West (3z)

North (4z)

White (5z)

Green (6z)

Red (7z)

Example

>>> # 123m456p789s11222z
>>> hand = [
...     1, 1, 1, 0, 0, 0, 0, 0, 0, # m
...     0, 0, 0, 1, 1, 1, 0, 0, 0, # p
...     0, 0, 0, 0, 0, 0, 1, 1, 1, # s
...     2, 3, 0, 0, 0, 0, 0, # z
... ]
>>> r = calculate_replacement_number(hand, None)
>>> print(r)
0
class xiangting.ClaimedTilePosition

Position of the claimed tile in the melded sequence.

Used in FuluMianzi.Shunzi.

LOW

The claimed tile is the lowest in the sequence. For example, claiming a 3 to form a sequence of 3-4-5.

MIDDLE

The claimed tile is the middle in the sequence. For example, claiming a 4 to form a sequence of 3-4-5.

HIGH

The claimed tile is the highest in the sequence. For example, claiming a 5 to form a sequence of 3-4-5.

xiangting.calculate_replacement_number(bingpai, fulu_mianzi_list)

Calculates the replacement number (= xiangting number + 1) for a given hand.

This function is for 4-player mahjong.

In some rulesets, melded tiles are excluded when checking whether a hand contains four identical tiles. In others, melded tiles are included in the calculation. This function allows you to control that behavior via the fulu_mianzi_list argument:

  • Use None if melds are excluded in the ruleset (e.g., Tenhou, Mahjong Soul).

  • Provide Sequence[FuluMianzi] if melds are included (e.g., World Riichi Championship, M.LEAGUE).

If fewer melds are provided than required for a complete hand, the missing ones are treated as melds that do not overlap with the tiles in the hand. For example, with the hand 123p1s, three melds are required. If only two are given (e.g., [444p, 777s]), the third is considered to be a non-overlapping meld, such as 111z.

Parameters:
  • bingpai (list[int]) – A hand excluding melds (兵牌 a.k.a. pure hand, 純手牌).

  • fulu_mianzi_list (Sequence[FuluMianzi] | None) – An optional list of melds.

Returns:

The replacement number (= xiangting number + 1).

Return type:

int

Raises:

ValueError – If an invalid hand (手牌) is provided.

Examples

>>> # 123m456p789s11222z
>>> hand = [
...     1, 1, 1, 0, 0, 0, 0, 0, 0, # m
...     0, 0, 0, 1, 1, 1, 0, 0, 0, # p
...     0, 0, 0, 0, 0, 0, 1, 1, 1, # s
...     2, 3, 0, 0, 0, 0, 0, # z
... ]
>>> r = calculate_replacement_number(hand, None)
>>> print(r)
0
>>> # 123m1z
>>> hand = [
...     1, 1, 1, 0, 0, 0, 0, 0, 0, # m
...     0, 0, 0, 0, 0, 0, 0, 0, 0, # p
...     0, 0, 0, 0, 0, 0, 0, 0, 0, # s
...     1, 0, 0, 0, 0, 0, 0, # z
... ]
>>> # 456p 7777s 111z
>>> melds_3 = [
...     FuluMianzi.Shunzi(12, ClaimedTilePosition.LOW),
...     FuluMianzi.Gangzi(24),
...     FuluMianzi.Kezi(27),
... ]
>>> r_wo_melds = calculate_replacement_number(hand, None)
>>> print(r_wo_melds)
1
>>> r_w_melds = calculate_replacement_number(hand, melds_3)
>>> print(r_w_melds)
2
>>> # 456p 7777s
>>> melds_2 = [
...     FuluMianzi.Shunzi(12, ClaimedTilePosition.LOW),
...     FuluMianzi.Gangzi(24),
... ]
>>> r_w_missing_melds = calculate_replacement_number(hand, melds_2)
>>> print(r_w_missing_melds)
1
xiangting.calculate_replacement_number_3_player(bingpai, fulu_mianzi_list)

Calculates the replacement number (= xiangting number + 1) for a given hand.

This function is for 3-player mahjong.

Tiles from 2m (二萬) to 8m (八萬) are not used. In addition, melded sequences (明順子) are not allowed.

In some rulesets, melded tiles are excluded when checking whether a hand contains four identical tiles. In others, melded tiles are included in the calculation. This function allows you to control that behavior via the fulu_mianzi_list argument:

  • Use None if melds are excluded in the ruleset (e.g., Tenhou, Mahjong Soul).

  • Provide Sequence[FuluMianzi] if melds are included (e.g., World Riichi Championship, M.LEAGUE).

If fewer melds are provided than required for a complete hand, the missing ones are treated as melds that do not overlap with the tiles in the hand. For example, with the hand 123p1s, three melds are required. If only two are given (e.g., [444p, 777s]), the third is considered to be a non-overlapping meld, such as 111z.

Parameters:
  • bingpai (list[int]) – A hand excluding melds. (兵牌 a.k.a. pure hand, 純手牌).

  • fulu_mianzi_list (Sequence[FuluMianzi] | None) – An optional list of melds.

Returns:

The replacement number (= xiangting number + 1).

Return type:

int

Raises:

ValueError – If an invalid hand (手牌) is provided.

Examples

>>> # 111m456p789s11222z
>>> hand = [
...     3, 0, 0, 0, 0, 0, 0, 0, 0, # m
...     0, 0, 0, 1, 1, 1, 0, 0, 0, # p
...     0, 0, 0, 0, 0, 0, 1, 1, 1, # s
...     2, 3, 0, 0, 0, 0, 0, # z
... ]
>>> r = calculate_replacement_number(hand, None)
>>> print(r)
0
>>> # 111m1z
>>> hand = [
...     3, 0, 0, 0, 0, 0, 0, 0, 0, # m
...     0, 0, 0, 0, 0, 0, 0, 0, 0, # p
...     0, 0, 0, 0, 0, 0, 0, 0, 0, # s
...     1, 0, 0, 0, 0, 0, 0, # z
... ]
>>> # 444p 7777s 111z
>>> melds_3 = [
...     FuluMianzi.Kezi(12),
...     FuluMianzi.Gangzi(24),
...     FuluMianzi.Kezi(27),
... ]
>>> r_wo_melds = calculate_replacement_number(hand, None)
>>> print(r_wo_melds)
1
>>> r_w_melds = calculate_replacement_number(hand, melds_3)
>>> print(r_w_melds)
2
>>> # 444p 7777s
>>> melds_2 = [
...     FuluMianzi.Kezi(12),
...     FuluMianzi.Gangzi(24),
... ]
>>> r_w_missing_melds = calculate_replacement_number(hand, melds_2)
>>> print(r_w_missing_melds)
1
class xiangting.FuluMianzi

副露面子: Meld.

Examples
>>> # 4-56p (Chii 4p Low)
>>> shunzi = FuluMianzi.Shunzi(12, ClaimedTilePosition.LOW)
>>> # 1-11z (Pon 1z)
>>> kezi = FuluMianzi.Kezi(27)
>>> # 7-777s (Kan 7s)
>>> gangzi = FuluMianzi.Gangzi(24)
class Gangzi(tile: int, /)

槓子: Quad.

Parameters:

tile (int) – The index of the tile. The correspondence between the index and the tile is the same as bingpai.

Examples
>>> # 1-111m (Kan 1m)
>>> gangzi = FuluMianzi.Gangzi(0)
class Kezi(tile: int, /)

刻子: Triplet.

Parameters:

tile (int) – The index of the tile. The correspondence between the index and the tile is the same as bingpai.

Examples
>>> # 1-11m (Pon 1m)
>>> kezi = FuluMianzi.Kezi(0)
class Shunzi(tile: int, position: ClaimedTilePosition, /)

順子: Sequence.

Parameters:
  • tile (int) – The index of the tile. The correspondence between the index and the tile is the same as bingpai.

  • position (ClaimedTilePosition) – The position of the claimed tile in the meld. The correspondence between the index and the tile is the same as bingpai.

Examples
>>> # 1-23m (Chii 1m Low)
>>> shunzi_low = FuluMianzi.Shunzi(0, ClaimedTilePosition.LOW)
>>> # 2-13m (Chii 2m Middle)
>>> shunzi_middle = FuluMianzi.Shunzi(1, ClaimedTilePosition.MIDDLE)
>>> # 3-12m (Chii 3m High)
>>> shunzi_high = FuluMianzi.Shunzi(2, ClaimedTilePosition.HIGH)