#calculator #riichi #mode #input #mahc

bin+lib mahc

riichi mahjong calculator library and CLI

28 stable releases

Uses new Rust 2024

1.16.0 Apr 22, 2025
1.15.0 Apr 13, 2025
1.8.4 Mar 30, 2025
1.8.0 Sep 8, 2024
1.4.1 Jul 31, 2024

#68 in Math

Download history 9/week @ 2025-01-13 3/week @ 2025-02-03 8/week @ 2025-02-10 5/week @ 2025-02-17 141/week @ 2025-03-03 8/week @ 2025-03-10 4/week @ 2025-03-17 253/week @ 2025-03-24 589/week @ 2025-03-31 1368/week @ 2025-04-07 195/week @ 2025-04-14 143/week @ 2025-04-21 10/week @ 2025-04-28

2,034 downloads per month

MIT license

1.5MB
6.5K SLoC

Riichi Mahjong Scoring Library and Calculator

CLI tool that calculates the score of a hand in riichi mahjong.

  • Manual mode (Calculator Mode): given han and fu, calculates the score
  • Normal mode: given a hand, calculates the score with included yaku and fu
  • Analyse mode: Given tiles, will find valid tile shapes

This also doubles as a scoring library! check out the docs on crates.io

demo gif

Examples

Library Usage

use mahc::{
    calc::{calculate, get_hand_score},
    hand::Hand,
    suit::Suit,
    tile::{Tile, WValue, EAST_VALUE},
    tile_group::TileGroup,
};

// creating a tilegroup from a string
let one_two_three_seq: TileGroup = "123s".to_string().try_into().unwrap();
let seven_eight_nine_seq: TileGroup = "789m".to_string().try_into().unwrap();

// creating a tilegroup from tiles
let seven_tile: Tile = "7m".to_string().try_into().unwrap();
let seven_pair: TileGroup =
    TileGroup::new(vec![seven_tile.clone(), seven_tile.clone()], false).unwrap();

// creating tiles in a few ways
let win_tile: Tile = "7m".to_string().try_into().unwrap();
let seat_wind: Tile = Tile::new(EAST_VALUE, &Suit::Wind).unwrap();
let prevelent_wind: Tile = Tile::Wind(WValue::West);

let hand = Hand::new(
    vec![
        one_two_three_seq.clone(),
        one_two_three_seq.clone(),
        seven_eight_nine_seq.clone(),
        seven_eight_nine_seq.clone(),
        seven_pair.clone(),
    ],
    win_tile,
    seat_wind,
    prevelent_wind,
)
.unwrap();
assert!(hand.is_ryanpeikou());

// get list of yaku, fu
let score = get_hand_score(
    &hand, &None, false, false, false, false, false, false, false, false, 0,
)
.unwrap();
assert_eq!(score.han(), 3);
assert_eq!(score.fu_score(), 40);

// get payment information
let payment = calculate(&score.han(), &score.fu_score()).unwrap();
assert_eq!(payment.base_points(), 1280);
assert_eq!(payment.dealer_ron(score.honba()), 7700);

Calculator Mode

~/$ mahc -m 4 30 --ba 3
> Dealer:    12500 (4200) 
  non-dealer: 8600 (2300/ 4200)

Normal Mode

note: the winning group has to go last (this is to calculate fu correctly)

~/$ mahc --tiles 777z 111z 234p 234p 11p -w 1p -p Ew -s Ew
> rrrd EEEw 234p 234p 11p | 1p

  7 Han/ 50 Fu
  Dealer: 18000 (6000)
  Non-dealer: 12000 (3000/6000)
  Yaku:
    Iipeikou: 1
    Honitsu: 3
    Yakuhai: 1
    Yakuhai: 1
    Yakuhai: 1
  
  Fu:
    BasePoints: 20
    ClosedRon: 10
    NonSimpleClosedTriplet: 8
    NonSimpleClosedTriplet: 8
    SingleWait: 2

Analyse Mode

This is a pretty new feature and needs some work

~/$ mahc --tiles 1p 2p 3p 1p 2p 3p 1p 2p 3p rd rd rd rd Ew Ew -w Ew --analyse-tiles

> Handshapes found
  111p 222p 333p EEw rrrrd
  123p 123p 123p EEw rrrrd

~/$ mahc --tiles 1p 2p 3p 1p 2p 3p 1p 2p 3p rd rd rd rd Ew Ew -w Ew --analyse-tiles --json

> {"hands":["111p 222p 333p EEw rrrrd ","123p 123p 123p EEw rrrrd "]}

Using file input

# hands.txt
--tiles 1p 9p 1s 9s 1m 9m rd gd wd Ew Sw Nw WWw -w Ww -p Ew -s Ew
--tiles 11z NNw SSw WWw rrd wwd ggd -w gd -p Ew -s Ew -d Ew Ew
-m 4 30 --ba 3
~/$ mahc -f hands.txt

 1p 9p 1s 9s 1m 9m rd gd wd Ew Sw Nw WWw | Ww

  Dealer: 96000 (32000)
  Non-dealer: 64000 (16000/32000)
  Yaku:
    KokushiMusou Yakuman
    KokushiMusou Yakuman 13 sided wait

 EEw NNw SSw WWw rrd wwd ggd | gd 

  Dealer: 144000 (48000)
  Non-dealer: 96000 (24000/48000)
  Yaku:
    Tsuuiisou Yakuman
    Daichiishin Yakuman
  
  4 Han/ 30 Fu/ 3 Honba
  Dealer: 12500 (4200)
  non-dealer: 8600 (2300/4200)

Json out

in normal mode

~/$ mahc --tiles 123p 456p 789p rrrdo 99p -w 9p -p Ew -s Ew -d 9p --json

yields

{
    "dora":1,
    "fu":30,
    "fuString":[ "BasePoints: 20", "NonSimpleOpenTriplet: 4", "SingleWait: 2"
    ],
    "han":5,
    "honba":0,
    "scores":{
        "dealer":{"ron":12000,"tsumo":4000},
        "non-dealer":{
            "ron":8000, 
            "tsumo":{"dealer":4000,"non-dealer":2000}
        }
    },
    "yakuString":["Honitsu: 2","Ittsuu: 1","Yakuhai: 1"]
}

and in calculator mode

~/$ mahc -m 4 30 --ba 3 --json

yields

{
    "fu":30,
    "han":4,
    "honba":3,
    "scores":{
        "dealer":{ "ron":12500, "tsumo":4200 },
        "non-dealer":{ "ron":8600, "tsumo":{ "dealer":4200, "non-dealer":2300 }
        }
    }
}

Notation

Suits

Type Notation
Man (Characters) 1m, 2m, 3m, 4m, 5m, 6m, 7m, 8m, 9m
Pin (Circles) 1p, 2p, 3p, 4p, 5p, 6p, 7p, 8p, 9p
Sou (Bamboos) 1s, 2s, 3s, 4s, 5s, 6s, 7s, 8s, 9s

Honors

Type Notation MPSZ Notation
Winds Ew, Sw, Ww, Nw 1z, 2z, 3z, 4z
Dragons wd, gd, rd 5z, 6z, 7z

Special Notation

Description Example
Open Sets 234po (an open sequence of 2, 3, 4 in Pin suit)
akadora 0m, 0p, 0s
  • eg: EEEw - triplet of east wind
  • eg: 234m - sequence of 2 3 4 Man
  • eg: 406s - sequence of 4 5 6 Sou with the akadora 5 sou
  • eg: 7777zo - open quad of red dragon
  • eg: 11s - pair of 1 sou
  • eg: 8m - 8 man tile

Installation

using cargo

If you want to use mahc as a scoring library

cargo add mahc 

If you want to use mahc as a cli program use

cargo install mahc
mahc --help

build from source

git clone https://github.com/DrCheeseFace/mahc
cd mahc
cargo build
./target/debug/mahc --version

from latest release

curl -s https://api.github.com/repos/DrCheeseFace/rusty-riichi-mahjong-calculator/releases/latest | grep "browser_download_url" | cut -d '"' -f 4 | wget -i -
unzip mahc-vX.X.X-x86_64-unknown-linux-gnu.zip -d mahc
cd mahc/x86_64-unknown-linux-gnu/release
./mahc --version

Contributing

  • ---- @gondoly @GuoDCZ

  • If you spot a bug, put in an issue with how to reproduce it

  • If you'd like to contribute, DO IT (send a PR)

  • If you think this library could do with some interface changes, make a suggestion

License

MIT all the way baby

this.jpg

Dependencies