Skip to content

Repository files navigation

Majiang Algorithm

High-performance Mahjong winning-hand detection & AI discard algorithm based on lookup tables, supporting multiple wildcard tiles (jokers). One algorithm, three implementations — Java / Go / C++ — kept behavior-identical by shared cross-language tests.

中文文档


Features

  • Win detection: Millisecond-level check for winning hands, supports any number of wildcard tiles
  • Waiting-hand calculation: Quickly lists all tiles that complete the current hand
  • AI discard: Score-model-driven auto decision for discarding, ponging, and konging
  • Lookup table: Offline pre-computation; runtime does hash lookups only — extremely fast
  • Full tile coverage: Characters (Wan), Circles (Tong), Bamboo (Tiao), Wind tiles (East/South/West/North), Arrow tiles (Zhong/Fa/Bai)
  • Three implementations: Java, Go and C++17 load the same lookup tables under data/; 2000+ fixed-seed deals are replayed by every CI to pin identical behavior (including bit-exact scores)

Repository Layout

java/    Java implementation (Maven project, published to Maven Central)
go/      Go implementation (Go module, behavior-aligned with the Java version)
cpp/     C++17 implementation (CMake, behavior-aligned with the Java version)
data/    Pre-computed lookup tables + the cross-language parity fixture, shared by all implementations
deploy/  Deployment scaffolding for the live demo server (systemd unit + script)

Both implementations load the same table files under data/ and are kept behaviorally in sync by tests: the algorithm unit tests are ported 1:1 between JUnit, go test and C++ tests, and data/parity_cases.txt holds 2000+ fixed-seed deals whose hu/ting/AI results are replayed and asserted by every language (java/.../ParityFixtureTest.java, go/parity_test.go and cpp/test/parity_test.cpp).


Quick Start

Maven Dependency

<dependency>
    <groupId>com.github.esrrhs</groupId>
    <artifactId>majiang_algorithm</artifactId>
    <version>1.0.18</version>
</dependency>

Win Detection / Waiting Hand

// Load pre-computed tables
HuTable.load(Files.readAllLines(normalTablePath));
HuTableFeng.load(Files.readAllLines(fengTablePath));
HuTableJian.load(Files.readAllLines(jianTablePath));

// Check if hand is a winning hand
boolean isHu = HuUtil.isHu(cards, gui);

// Query which tiles complete the hand
List<Integer> tingCards = HuUtil.isTing(cards, gui);

AI Discard

// Load AI scoring tables
AITable.load(Files.readAllLines(normalTablePath));
AITableFeng.load(Files.readAllLines(fengTablePath));
AITableJian.load(Files.readAllLines(jianTablePath));

// Decide which tile to discard
int card = AIUtil.outAI(cards, gui);

// Decide whether to pong / kong
boolean isPeng = AIUtil.pengAI(cards, gui, pengCard, 0.0d);
boolean isGang = AIUtil.gangAI(cards, gui, gangCard, 0.0d);

Go

go get github.com/esrrhs/majiang_algorithm/go
package main

import (
	majiang "github.com/esrrhs/majiang_algorithm/go"
)

func main() {
	// Load pre-computed tables (looked up in ., ./data, ../data)
	majiang.Load()

	cards := majiang.StringToCards("1万,2万,3万,东,东")
	gui := majiang.StringToCard("东")

	// Check if hand is a winning hand
	isHu := majiang.IsHu(cards, gui)

	// Query which tiles complete the hand
	ting := majiang.IsTing(cards, []int{gui})

	// AI discard / pong / kong
	out := majiang.OutAI(cards, []int{gui})
	isPeng := majiang.PengAI(cards, []int{gui}, pengCard, 0)
	isGang := majiang.GangAI(cards, []int{gui}, gangCard, 0)
}

Run the Go test suite (from go/, replays the same cases as the Java pipeline):

cd go && go test ./...

C++

cd cpp
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
./build/majiang_tests   # or: ctest --test-dir build --output-on-failure
#include "majiang/api.h"
#include "majiang/def.h"
#include "majiang/hu_util.h"
#include "majiang/ai_util.h"

// Load pre-computed tables (looked up in ., ./data, ../data)
majiang::Load();

std::vector<int> cards = majiang::StringToCards("1万,2万,3万,东,东");
int gui = majiang::StringToCard("东");

bool isHu = majiang::IsHu(cards, gui);                 // Check if hand is a winning hand
std::vector<int> ting = majiang::IsTing(cards, {gui}); // Waiting tiles
int out = majiang::OutAI(cards, {gui});                // AI discard
bool isPeng = majiang::PengAI(cards, {gui}, out, 0.0);
bool isGang = majiang::GangAI(cards, {gui}, out, 0.0);

Table Generation

To regenerate the lookup tables with either implementation, run from the output directory:

# Java: gen() writes majiang_clien_*.txt / majiang_server_*.txt / majiang.db / majiang_ai_*.txt
# Go:   HuGen() writes majiang_clien_*.txt + majiang_server_*.txt, AiGen() writes majiang_ai_*.txt

Interactive Web Platform & Algorithm Playground

🌐 Live Demo Online: 👉 http://majiang.esrrhs.xyz (now powered by the Go build)

An interactive web platform and algorithm laboratory modeled after Tencent Mahjong:

  1. 4-Player Mahjong Battle (1 Human vs 3 AI / 4 AI Spectator):
    • Green felt table, 3D tiles, and full tile set (Wan, Tong, Tiao, Winds, Dragons).
    • Wildcard (gui / laizi) support: Random flip indicator, specified wildcard, or clean hand.
    • Draw, Discard, Chow (Chi), Pong (Peng), Kong (Gang), and Winning Hand (Hu).
  2. Real-time Ready-Hand (Ting) Detection:
    • Shows winning tiles and remaining count in the game whenever you are in Ting.
    • Hover over hand tiles during discard to preview winning targets if discarded.
  3. 💡 AI Recommendation:
    • One-click best discard recommendation using AIUtil.outAI with expected score.
    • 4-AI auto-play spectator mode with variable speeds (1x ~ 10x).
  4. 🧪 Algorithm Playground:
    • Test any hand (1-14 tiles) with wildcards.
    • Measures isHu, isTing, and outAI execution times in microseconds (µs).

Start Web Server

cd java
./mvnw exec:java
# or with custom port:
./mvnw exec:java -Dexec.args="--port=8080"

The same web platform also ships as the Go build (single static binary, frontend embedded) — this is what the live demo runs as a systemd service (deploy/gq/):

cd go
go run ./cmd/majiangserver --port=8080        # web server
go run ./cmd/majiangserver --cli              # CLI 4-AI simulation benchmark

Visit in your browser: 👉 http://localhost:8080

CLI 4-AI Simulation Benchmark

cd java && ./mvnw exec:java -Dexec.args="--cli"

Algorithm Documentation

Document Content
Win Detection Algorithm Wildcard encoding, table structure, full win-detection & waiting-hand flow
AI Algorithm Hand scoring model, discard / pong / kong decision logic

Related Projects

Project Description
texas_algorithm Texas Hold'em algorithm
teenpatti_algorithm Teen Patti algorithm

About

High-performance Mahjong win detection, waiting-hand calculation and AI discard algorithm based on lookup tables, with behavior-identical Java / Go / C++ implementations and a live web demo.

Topics

Resources

Stars

481 stars

Watchers

23 watching

Forks

Releases

Packages

Used by

Contributors

Languages