Skip to content

tomohxx/shanten-number

Repository files navigation

Shanten Number

The algorithm used in this program has been proven to calculate shanten numbers accurately.

Read this in Japanese (日本語).

What Is the Shanten Number in Mahjong?

The shanten number is the minimum number of draws needed to reach tenpai.

Build

Debug mode

$ mkdir build
$ cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Debug
$ make

Release mode

$ mkdir build
$ cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Release
$ make

Note

A compiler compatible with C++20 or later is required.

Compile options

-DENABLE_NYANTEN

This enables the table search algorithm to use the minimal perfect hash function used in Cryolite's nyanten12. Enabling this option can reduce the size of the tables. However, the number of tiles in a hand for which shanten numbers can be calculated is limited to 14 or less.

-DFIX_RANDOM_SEED

It fixes the random seed used in the example program.

Building tables

Build the parameter tables required for calculating shanten numbers. This creates the files index_h.bin and index_s.bin.

$ ./mkind

Tip

Intel Threading Building Blocks (TBB) is optional and, if available, will be automatically linked to enable parallel builds.

Usage

  1. Prepare a std::array<int, 34> array representing a hand.

    • The n-th element stores the number of copies of the n-th tile.

      1 2 3 4 5 6 7 8 9
      Manzu 0 (1m) 1 (2m) 2 (3m) 3 (4m) 4 (5m) 5 (6m) 6 (7m) 7 (8m) 8 (9m)
      Pinzu 9 (1p) 10 (2p) 11 (3p) 12 (4p) 13 (5p) 14 (6p) 15 (7p) 16 (8p) 17 (9p)
      Souzu 18 (1s) 19 (2s) 20 (3s) 21 (4s) 22 (5s) 23 (6s) 24 (7s) 25 (8s) 26 (9s)
      Jihai 27 (East) 28 (South) 29 (West) 30 (North) 31 (White) 32 (Green) 33 (Red)
    • For example, if the hand is 123m245779p13555z, define the array as follows.

      std::array<int, 34> hand = {
         1, 1, 1, 0, 0, 0, 0, 0, 0, // Manzu
         0, 1, 0, 1, 1, 0, 2, 0, 1, // Pinzu
         0, 0, 0, 0, 0, 0, 0, 0, 0, // Souzu
         1, 0, 1, 0, 3, 0, 0        // Jihai
      };
  2. Calculate the shanten number. Each method returns a value of shanten number + 1.

    • General Form (m melds and a pair):
      int Calsht::calc_lh(const std::array<int, 34>& t, int m, bool three_player = false) const
    • Seven Pairs:
      int Calsht::calc_sp(const std::array<int, 34>& t, bool three_player = false) const
    • Thirteen Orphans:
      int Calsht::calc_to(const std::array<int, 34>& t) const
    • Standard Form:
      std::tuple<int, unsigned int> Calsht::operator()(const std::array<int, 34>& t,
                                                       int m,
                                                       unsigned int mode,
                                                       bool check_hand = false,
                                                       bool three_player = false) const

Note

Normally, set m to the number of tiles divided by 3.

Note

mode specifies which winning patterns to calculate shanten numbers for. Use 1 for General Form, 2 for Seven Pairs, and 4 for Thirteen Orphans. When calculating shanten numbers for multiple winning patterns, specify their bitwise OR.

Note

This method returns the shanten number + 1, and the mode. The mode indicates which winning pattern (General Form, Seven Pairs, or Thirteen Orphans) gives the minimum shanten number.

Note

If you set check_hand to true, the hand is validated. If you set three_player to true, the shanten number is calculated for three-player mahjong.

As an example, the following code calculates the shanten number for the hand defined above.

#include <array>
#include <filesystem>
#include <iostream>
#include <mahjong/calsht.hpp>

int main()
{
   // Set the location of shanten tables
   mahjong::Calsht calsht(std::filesystem::current_path());

   std::array<int, 34> hand = {
      1, 1, 1, 0, 0, 0, 0, 0, 0, // manzu
      0, 1, 0, 1, 1, 0, 2, 0, 1, // pinzu
      0, 0, 0, 0, 0, 0, 0, 0, 0, // souzu
      1, 0, 1, 0, 3, 0, 0        // jihai
   };

   const auto [sht, mode] = calsht(hand, 4, 7);

   std::cout << sht << std::endl;
   std::cout << mode << std::endl;

   return 0;
}

Output:

3
1

Example

  • Randomly generate hands and calculate the frequency of each shanten number and the expected shanten number.
$ ./example 14 100000000 0
  -1         278    0.000278
   0       69553    0.069553
   1     2334287    2.334287
   2    19502040   19.502040
   3    43925782   43.925782
   4    28516861   28.516861
   5     5496101    5.496101
   6      155098    0.155098
Number of Tiles         14
Number of Hands         100000000
Expected Value          3.155940

License

GNU Lesser General Public License v3.0.

Footnotes

  1. https://github.com/Cryolite/nyanten

  2. https://www.slideshare.net/slideshow/a-fast-and-space-efficient-algorithm-for-calculating-deficient-numbers-a-k-a-shanten-numbers-pptx/269706666

About

A tool for calculating the shanten number in Japanese mahjong.

Topics

Resources

License

Stars

Watchers

Forks

Contributors