Data Structure of Tien-Gow Tiles
GAME

Data Structure of Tien-Gow Tiles

November 16, 2025
gogonva gogonva

Data Structure of Tiles in Japanese-Style Tien-Gow

In November 2023, I released a game on Steam called Japanese-Style Tien-Gow.
This article is a rather niche one that introduces the tile data structure implemented for Japanese-Style Tien-Gow.
To give a small spoiler: the game uses a slightly tricky method that maps combinations of multiple tiles to a single integer.

What Is Tien-Gow?

Please Google for full details, but here’s the minimum you need to know for this article.
Tien-Gow is a four-player tile game similar to Mahjong.
Although it looks like Mahjong at first glance, the rules are closer to President (Daifugō)—the basic idea is that you play a tile stronger than the previous player’s.

Tile Data Structure

Tien-Gow uses tiles called Tienjiu tiles.
There are two kinds: Civil tiles and Military tiles.
The full set consists of 22 Civil tiles (11 types × 2 copies each) and 10 Military tiles, for a total of 32 tiles.
These 32 tiles are dealt to four players, so a hand contains at most 8 tiles.
Additionally, some combinations allow up to 4 tiles to be played simultaneously.

Similar to playing cards, the tiles have ranks and suits (Civil / Military).
However, unlike in playing cards—where suit + rank uniquely determines a card—Tien-Gow includes duplicate, indistinguishable copies of certain tiles.
For example, the strongest Civil tile “Tien” exists in 2 copies, and they are visually identical.

As in President, you can play pairs of the same tile, and some special multi-tile combinations also exist.

Taking all this into account, I needed a suitable data structure to represent the tiles.

One straightforward way is something like this:

public enum NaiveTile:
    NONE = 0,
    銅錘六 = 2,
    高脚七 = 3,
    紅頭十 = 5,
    ...
2 = 67,
1 = 71,
2 = 73,

You assign a sequential integer ID to each distinguishable tile and store hands as arrays of these enums.

Honestly, this is perfectly fine.
But chess engines use a heavily optimized structure called a bitboard, and I wanted something similarly optimized for Japanese-Style Tien-Gow.

The Approach Used in Japanese-Style Tien-Gow

I also use an enum—but instead of consecutive integers, I assign prime numbers.

public enum ActuralTile:
    NONE = 0,
    銅錘六 = 2,
    高脚七 = 3,
    紅頭十 = 5,
    ...
2 = 67,
1 = 71,
2 = 73,

And here’s the key idea:
A combination of tiles is represented as the product of their assigned primes.

For example, combining “BronzeSix = 2” and “TallSeven = 3” results in the value 6 (= 2 × 3).
If you’re into math, you may already see why primes were chosen.

In Tien-Gow, differently patterned tiles are distinct, but the order of tiles within a combination does not matter.
This is true for many games—e.g., in President or Mahjong, [1,2,3] is the same as [2,1,3].

This “order does not matter” property fits perfectly with multiplication: 2 × 3 equals 3 × 2.
Instead of storing a combination as [2, 3], you can represent it as the single integer 6, clean and compact.
Because the game rules do not depend on order, no information is lost.

It might not seem like a big deal, but imagine storing hand information for every turn in a database.
With arrays, you’d need eight columns (the maximum hand size), and after the first turn many entries would be NULL or NONE. Very wasteful.

Uniqueness of Prime Factorization

Multiplication is clean—but why primes?

Because of the uniqueness of prime factorization.

Suppose RedHeadTen were assigned 4 instead of a prime.
If you hold BronzeSix = 2 and RedHeadTen = 4, the product is 8.
Factor 8:

8 = 2 × 2 × 2
8 = 2 × 4
8 = 8

You get three patterns!
Even considering BronzeSix appears at most twice, ambiguous cases still remain.

With primes:

BronzeSix = 2
RedHeadTen = 5
Product = 10 → 10 = 2 × 5 (and only that)

A number expressible as a product of primes is a composite number, and composite numbers have a unique prime factorization.
Thus, representing tiles as primes and combinations as their products guarantees you can reconstruct the exact original tiles.

Exercise
Factor 68231.
Answer: 31 × 31 × 71
In Japanese-Style Tien-Gow, this corresponds to the combination [Tien][Tien][Nine].

Checking Whether a Hand Contains a Specific Combination

The game frequently checks whether a hand (max 8 tiles) contains a specific combination.
With the current data structure, this is extremely easy:

Just check whether the hand value is divisible by the combination value.

 if (Hand % Tiles == 0)
 {
    // exist!

 }
 else
 {
    // none

 }

If you stored hands as arrays, you’d need loops.

Can This Method Be Applied to Other Games?

The weakness of this method is that the numbers grow quickly due to multiplication.
Fortunately, in Tien-Gow the maximum played combination is 4 tiles (fits in 32-bit int), and the hand size is 8 tiles (fits in 64-bit long).
I also assigned larger primes to Military tiles to help keep values smaller.

But Mahjong has many more tile types and larger hand sizes, so even 64 bits would overflow.
Thus, this technique only works for games with few tile types and small hand sizes.
And realistically, such games usually don’t need optimization this extreme anyway.

Still, if you find another use case, please let me know.

Conclusion

In online multiplayer, players must exchange data.
Sending a single integer instead of an array made implementation extremely simple.
This data structure may be niche, but for Japanese-Style Tien-Gow it fit perfectly.
And most importantly, it was fun to build.
When I realized that multiplication captures order-independent sets and allows presence checking, I knew this was the answer.

Such an explanation-required data structure might be hard to justify in professional work, but it’s one of the joys of small-scale development.
Sometimes we just want to enjoy programming…