Currently, the mjai format has become the de facto standard replay format used by many Mahjong AI projects. Therefore, adopting the mjai format in Mahjong AI projects is highly beneficial for improving interoperability with other Mahjong AI projects. Additionally, when exchanging replays between online Mahjong game platforms like Mahjong Soul, Tenhou, and Mahjong Ichibangai, which use their own unique replay formats, or between Mahjong AI projects like Kanachan, which also use unique replay formats, there is a significant advantage in implementing only conversions to and from the mjai format. By doing so, we can achieve compatibility with various replay formats through the mjai format as an intermediary. In other words, the mjai format can serve as a "hub format" at the center of various replay formats. This is similar to how Unicode serves as a central standard for converting between different character encodings.
Currently, the mjai format specification is somewhat vague. The original page describing the mjai format specification does not comprehensively cover all cases. Moreover, many Mahjong AI projects have added their own extensions to the mjai format. This could potentially hinder the conversion and interoperability of replays via the mjai format.
Considering the above, the objective of this project is to standardize the mjai format specification and enhance interoperability between various replay formats. Specifically, the goals are as follows:
- To officially incorporate existing extensions added to the mjai format into the standardized specification.
- To expand the mjai format specification to accommodate various Mahjong rules.
- To implement converters between the standardized mjai format and the replay formats of major online Mahjong game platforms, such as Mahjong Soul, Tenhou, and Mahjong Ichibangai.
There are two aspects to the use of the mjai format. One is its use as a format for exchanging information during a game, and the other is its use as a format for recording the game (known as a game record or "牌čś"). The format used for exchanging information during a game allows only the information visible to a specific player to be seen, while other information remains hidden. Additionally, it serves the role of communicating the actions chosen by that player to the game host. The format used for recording the game (game record) makes all information visible. The former is called the "in-game mode" and the latter the "replay mode".
In in-game mode, messages have two directions: host-to-player and player-to-host. Host-to-player messages notify a player of game events from the game host. Player-to-host messages are used to notify the game host of the player's choices during the game.
(TODO)
A none
message is used to notify the game host from the player that they chooses to "do nothing." For example, this message is sent when a player decides to skip the option to declare chi, pon, or open kong at the appropriate timing, or to inform the game host that no action can be taken during a line-by-line mode when no valid actions are available.
Player-to-host.
{"type":"none"}
(TODO)
A hello
message is used by the game host to notify a player of the start of communication. The game host MAY specify any protocol name in the protocol
field. Additionally, the game host MAY specify the protocol version in the protocol_version
field as a non-negative integer.
Host-to-player.
{"type":"hello","protocol":"mjsonp","protocol_version":1}
- Join (player-to-host)
A join
message is sent by a player who has received a hello
message to notify the game host of the start of communication. The player MAY specify a string representing their name in the name
field for identification purposes. Additionally, if the game host is hosting multiple games simultaneously, the player MAY specify a string in the room
field to indicate which game they is joining.
Player-to-host.
{"type":"join","name":"shanten","room":"default"}
- Start of Game (host-to-player)
A start_game
message is sent by the game host to notify all players of the start of the game after receiving join
messages from all participating players. The game host SHOULD send a start_game
message to each player after receiving join
messages from all participating players. The game host MAY specify an integer from 0
to 4
in the id
field to represent each player's seat order. Additionally, the game host MAY specify strings in the names
field to identify each player. The strings listed in the names
field SHOULD correspond to the strings in the name
fields of the join
messages from the players, arranged in seat order.
A player who has received a start_game
message SHOULD send a none
message to the game host.
After receiving none
messages from all players in response to the start_game
message, the game host SHOULD send a start_kyoku
message to each player.
Host-to-player.
{"type":"start_game","id":1,"names":["shanten","shanten","shanten","shanten"]}
- None (player-to-host)
Host-to-player.
{"type":"start_kyoku","bakaze":"E","kyoku":1,"honba":0,"kyotaku":0,"oya":0,"dora_marker":"7s","tehais":[["?","?","?","?","?","?","?","?","?","?","?","?","?"],["3m","4m","3p","5pr","7p","9p","4s","4s","5sr","7s","7s","W","N"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"]]}
(TODO)
Host-to-player.
{"type":"tsumo","actor":0,"pai":"?"}
- None
- Dahai (Tile Discard)
- Hora (Winning)
- Reach (Riichi)
- Ankan (Concealed Kong)
- Kakan (Add Kong)
- Ryukyoku (No Game)
Host-to-player and player-to-host.
{"type":"dahai","actor":1,"pai":"7s","tsumogiri":false}
Host-to-player and player-to-host.
{"type":"chi","actor":1,"target":0,"pai":"6s","consumed":["5sr","7s"]}
(TODO)
Host-to-player and player-to-host.
{"type":"pon","actor":1,"target":0,"pai":"C","consumed":["C","C"]}
(TODO)
Host-to-player and player-to-host.
{"type":"daiminkan","actor":2,"target":0,"pai":"5p","consumed":["5pr","5p","5p"]}
(TODO)
Host-to-player and player-to-host.
{"type":"kakan","actor":3,"pai":"S","consumed":["S","S","S"]}
(TODO)
Host-to-player and player-to-host.
{"type":"ankan","actor":1,"consumed":["N","N","N","N"]}
(TODO)
Host-to-player.
{"type":"dora","dora_marker":"8p"}
(TODO)
Host-to-player and player-to-host.
{"type":"reach","actor":1}
(TODO)
Host-to-player.
{"type":"reach_accepted","actor":2}
(TODO)
Host-to-player and player-to-host.
(TODO)
(TODO)
(TODO)
Host-to-player and player-to-host.
(TODO)
(TODO)
(TODO)
Host-to-player.
{"type":"end_kyoku"}
(TODO)
Host-to-player.
{"type":"end_game"}
(TODO)