npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mahjong-tile-efficiency

v1.0.3

Published

Tile efficiency calculation for several Mahjong variants

Downloads

5

Readme

Mahjong Tile Efficiency

  • Calculate shanten number of mahjong hands.
  • Support multiple rulesets (Menzu, Hong Kong Old Style, Riichi, ZungJung, MCR, Taiwan, Hong Kong Taiwan Style)
  • Calculate ukeire (tile acceptace)

API

TilesToHand

Convert a hand of tiles format to hand format

const tiles = [
  '1m', '2m', '3m', '6p', '7p', '7p', '7p', '8p', '8p', '5s', '5s', '1z', '1z'
]
const hand = tilesToHand(tiles)
console.log(hand)
// [
//   [1, 1, 1, 0, 0, 0, 0, 0, 0],
//   [0, 0, 0, 0, 0, 1, 3, 2, 0],
//   [0, 0, 0, 0, 2, 0, 0, 0, 0],
//   [2, 0, 0, 0, 0, 0, 0]
// ]

RuleSet

A RuleSet is a class. An instance of RuleSet has two functions: calShanten and calUkeire. Both functions take in a hand as param.

import { tilesToHand, RuleSet } from 'mahjong-tile-efficiency'
const tiles = [
  '1m', '2m', '3m', '6p', '7p', '7p', '7p', '8p', '8p', '5s', '5s', '1z', '1z'
]
const hand = tilesToHand(tiles)

const riichiRule = new RuleSet('Riichi')  // 'Menzu' | 'HK' | 'Riichi' | 'ZungJung' | 'MCR' | 'Taiwan' | 'HKTW'
const shantenResult = riichiRule.calShanten(hand)
const ukeireResult = riichiRule.calUkeire(hand)

console.log(shantenResult)
console.log(ukeireResult)

// 1
// {
//   shanten: 1,
//   ukeire: { '6p': 3, '7p': 1, '8p': 2, '9p': 4, '5s': 2, '1z': 2 },
//   totalUkeire: 14
// }

Note: if is a karaten (empty tenpai, waiting for the "fifth tile"), the function still count this as tenpai (returns 0).

calShanten function works on either (3n + 1) or (3n + 2) tiles.

calUkeire function also works on either (3n + 1) or (3n + 2) tiles, but behavior are different

  • With 3n + 1 tiles, the status is "to draw". calUkeire().ukeire tells what next drawn tiles can advance the shanten number, and the number of such tiles that are unseen.
  • With 3n + 2 tiles, the status is "to discard". calUkeire().normalDiscard tells what discard can keep the shanten number, while calUkeire().recedingDiscard tells what discard will make shaten number increases (usually inferior play).
import { tilesToHand, RuleSet } from 'mahjong-tile-efficiency'
const tiles = [
  '1m', '1m', '1m', '6p', '7p', '7p', '1s', '1s', '2s', '5s', '5s', '1z', '1z', '1z'
]
const hand = tilesToHand(tiles)

const riichiRule = new RuleSet('Riichi')
const ukeireResult = riichiRule.calUkeire(hand)

console.log(ukeireResult)
// {
//   shanten: 1,
//   normalDiscard: {
//     '1m': { '6p': 3, '2s': 3 },
//     '6p': { '7p': 2, '1s': 2, '3s': 4, '5s': 2 },
//     '7p': { '5p': 4, '8p': 4, '1s': 2, '3s': 4, '5s': 2 },
//     '1s': { '5p': 4, '7p': 2, '8p': 4, '3s': 4, '5s': 2 },
//     '2s': { '5p': 4, '7p': 2, '8p': 4, '1s': 2, '5s': 2 },
//     '1z': { '6p': 3, '2s': 3 }
//   },
//   recedingDiscard: {
//     '5s': {
//       '4p': 4,
//       '5p': 4,
//       '6p': 3,
//       '7p': 2,
//       '8p': 4,
//       '9p': 4,
//       '1s': 2,
//       '2s': 3,
//       '3s': 4,
//       '4s': 4,
//       '5s': 3,
//       '6s': 4,
//       '7s': 4
//     }
//   }

Calculate shanten based on final shape

Each mahjong rule consists of different winning pattern.

  • calShantenMenzu: 面子手 standard hand
  • calShantenChiitoi: 七對子 7 pairs (disallow identical pairs)
  • calShantenSevenPairs: 七對 7 pairs (allow identical pairs)
  • calShantenKokushi: 十三么九 / 十三么 / 國士無雙 13 orphans.
  • calShantenHonourAndKnittedTiles: 全不靠 (see MCR rules)
  • calShantenKnittedStraight: 組合龍 (see MCR rules)
  • calShantenLikgu: 嚦咕嚦咕 (see HKTW rules)
  • calShantenBatDaap: 十六不搭 (see HKTW rules)
  • calShantenSapSaamJiu: 十三么 (specifically for HKTW rules)

You can calculate the shanten specifically for a winning pattern. For example:

import { cal, tilesToHand } from 'mahjong-tile-efficiency'


const tiles = [
  '1m', '4m', '9m', '5p', '8p', '8p', '4s', '6s', '9s', '1z', '2z', '3z', '4z', '5z'
]

const hand = tilesToHand(tiles)
console.log(cal.calShantenHonourAndKnittedTiles(hand))
// 2

Terminologies

TileName

There are 34 valid tile names, which are 1m to 9m, 1p to 9p, 1s to 9s, and 1z to 9z. m p s corresponds to "Man", "Pin", and "Sou" plain suits (萬筒索). z represents honour tiles (東南西北白發中).

The program does not support 0m 0p 0s for Aka-dora as in Riichi Mahjong.

Tiles and Hand

Both Tiles and Hand are representations of a player's hand. Tiles is an array of tiles. Hand is an array of arrays of tile count, in which each subarray represents a suit.

The following tiles and hand represents the same player's hand.

const tiles = [
  '1m', '2m', '3m', '6p', '7p', '7p', '7p', '8p', '8p', '5s', '5s', '1z', '1z'
]

const hand = [
  [1, 1, 1, 0, 0, 0, 0, 0, 0],  // man
  [0, 0, 0, 0, 0, 1, 3, 2, 0],  // pin
  [0, 0, 0, 0, 2, 0, 0, 0, 0],  // sou
  [2, 0, 0, 0, 0, 0, 0]  // zi
]

RuleName

The program supports multiple rules. Use the following literals for the rules:

  • Menzu: Standard shapes only
  • HK: Hong Kong Old Style
  • Riichi: Japanese mahjong
  • ZungJung: Zung Jung Rules (Similar to Riichi, except identical pairs are allowed for 7 pairs)
  • MCR: Chinese MCR rule
  • Taiwan: Taiwanese Rule (like menzu, but maximum 17 tiles)
  • HKTW: Taiwan Mahjong Hong Kong style (with 嚦咕嚦咕、十六不搭、十三么)