Skip to main content

Jansou

License PyPI Python Coverage Docs

Python library for Riichi Mahjong environments and utilities.

  • Conversion between multiple tile notations (MPSZ, MJAI, 136)
  • Hand analysis (shanten, wait, efficiency, outlook, yaku, fu/han, score)
  • Game environment for 3/4 player game with configurable rules
  • Game replay log in multiple formats (mjlog XML, mjai JSONL, Tenhou JSON)

Examples

Notation

from jansou.core.notation import parse_mpsz, dump_mpsz, parse_mjai, dump_mjai, parse_136, dump_136

tiles = parse_mpsz("667s 34668m 2357p 2z")

dump_mpsz(tiles)  # 34668m2357p667s2z
dump_mjai(tiles)  # 6s 6s 7s 3m 4m 6m 6m 8m 2p 3p 5p 7p S
dump_136(tiles)  # [92, 93, 96, 8, 12, 20, 21, 28, 40, 44, 53, 60, 112]

Hand

from jansou.core.tiles import Tile, TileKind
from jansou.core.notation import parse_mpsz
from jansou.core.hand import Hand
from jansou.analysis.efficiency import discard_evaluation
from jansou.analysis.shanten import shanten, is_tenpai
from jansou.analysis.waits import waits

# (1) shanten advancement

hand = Hand(parse_mpsz("279m 1569p 1168s 35z 2m"))

shanten(hand)  # 3
is_tenpai(hand)  # False

options = discard_evaluation(hand)  # sorted by shanten advancement and wider acceptance
# in this case, 1p 9p 3z 5z are the best, with the same number of acceptance

best = options[0]
best.discard  # 1p
best.shanten  # 3
best.total_acceptance  # 20

# (2) acceptance

hand = Hand(parse_mpsz("567m 34567p 23489s 2z"))

options = discard_evaluation(hand)  # there are multiple options for 1 shanten

best = options[0]  # but the best option is 2z with the widest acceptance
best.discard  # 2z
best.shanten  # 1
best.total_acceptance  # 33

# (3) waits

hand = Hand(parse_mpsz("1112345678999m"))

waits(hand)  # 1m 2m 3m 4m 5m 6m 7m 8m 9m

Score

from jansou.core.tiles import Tile, TileKind, Wind
from jansou.core.notation import parse_mpsz
from jansou.core.rules import preset
from jansou.core.hand import Hand, Meld, MeldType, CallSource
from jansou.scoring.context import WinContext
from jansou.scoring.score import score

hand = Hand(
    parse_mpsz("77m 34p 055s 5p"),
    [
        Meld(MeldType.PON, parse_mpsz("111m"), Tile(TileKind.M1), CallSource.TOIMEN),
        Meld(MeldType.PON, parse_mpsz("777z"), Tile(TileKind.CHUN), CallSource.KAMICHA),
    ],
)

context = WinContext(
    rules=preset("m-league"),
    seat_wind=Wind.WEST,
    is_tsumo=False,
    dora_indicators=[Tile(TileKind.CHUN)],
)

result = score(hand, Tile(TileKind.P5), context)

result.yaku  # YAKUHAI_CHUN
result.han  # 2
result.fu.total  # 40 (20 + 4 + 4 + 4 = 32)

result.payment.total  # 2600

shanten(hand)  # 0
is_tenpai(hand)  # True
waits(hand)  # 2p, 5p

Game environment, replay log

from jansou.core.rules import preset
from jansou.game.environment import Environment
from jansou.game.agents import SmartEfficiencyAgent
from jansou.io.from_game import paifu_from_game
from jansou.io.tenhou_json import dump_tenhou_json_url

env = Environment(preset("tenhou"))
agents = [SmartEfficiencyAgent() for i in range(4)]

result = env.run(agents)

result.scores
result.ranking

paifu = paifu_from_game(env)
dump_tenhou_json_url(paifu)  # https://tenhou.net/6/#json=...
# can be viewed at https://mjv.snack.studio

Step-by-step play

from jansou.core.rules import preset
from jansou.game.environment import Environment

env = Environment(preset("tenhou"))
game = env.play()  # returns generator
# play() make take `observe` function for
# unmasked events


request = next(game)  # first decision

while True:
    action = __choose(request)  # any of request.actions
    try:
        request = game.send(action)
    except StopIteration as stop:
        result = stop.value  # GameResult
        break

Development

uv sync

uv run pytest
uv run pytest --cov

uv run ruff format
uv run ruff check

Download files

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

Source Distribution

jansou-0.12.0.tar.gz (299.0 kB view details)

Uploaded Source

Built Distribution

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

jansou-0.12.0-py3-none-any.whl (204.3 kB view details)

Uploaded Python 3

File details

Details for the file jansou-0.12.0.tar.gz.

File metadata

  • Download URL: jansou-0.12.0.tar.gz
  • Upload date:
  • Size: 299.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jansou-0.12.0.tar.gz
Algorithm Hash digest
SHA256 659484c17a7497d26b5e632361c389aef8ead153d7a81909eed4c8c72df55cc9
MD5 e16c536e8d9c805e6e0e2d715bbf1b8e
BLAKE2b-256 0695ca191f4f6e4562c4433cba3d1ab48b89bf2a9b0d11ad9c90de06eed83657

See more details on using hashes here.

File details

Details for the file jansou-0.12.0-py3-none-any.whl.

File metadata

  • Download URL: jansou-0.12.0-py3-none-any.whl
  • Upload date:
  • Size: 204.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jansou-0.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d1acbc2e18aba9d02f731087b726a4f003b8f570539f1b752afcfd888d5f618e
MD5 99b1453a21c511d7a0a3ef74239803dd
BLAKE2b-256 fd89923616e0e5d670ad66a60e483e66e652a2bf50b32271a9dfd3fe144623b4

See more details on using hashes here.

Release history Release notifications | RSS feed

0.14.0

2 files

0.13.0

2 files

This release

0.12.0 This release

2 files

0.11.1

2 files

0.11.0

2 files

0.10.0

2 files

0.9.0

2 files

0.8.1

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page