みちのいに!!

自分のメモと、他にもハマる人がいそうなことを書く

天鳳牌譜 mjlog形式について

牌譜解析するにあたって、mjlog形式の仕様がよくわからないので調べた。 2010年ごろの記事は多いんだけど、リンクが切れてたりなんだかんだでアレなので書きます。

なにか気づき次第追記していきます。

目次

参考文献

先人たち

麻雀牌譜解析のすすめ byほしきゅー

【开坑】天凤牌谱文件格式试解析【天凤麻雀吧】_百度贴吧

天鳳の牌譜形式 麻雀日和

公式のコード

http://tenhou.net/1/script/tenhou.js
http://tenhou.net/img/tehai.js

牌譜の入手方法

プレミアムだと簡単に自分の分は保存できるらしい。

牌譜IDを入手する

Flash版クライアントの[メニュー]->[牌譜の管理]->[バックアップ]に

http://tenhou.net/0/?log=2011020417gm-00a9-0000-b67fcaa3&tw=1

こんな感じのURLがある。このlog=の後の、正規表現でいうところの

[0-9]{10}gm-[0-9a-f]{4}-[0-9]{4}-[0-9a-f]{8}

な部分を牌譜IDと以降呼ぶ。 これは、

{日付時刻}gm-{対局形式}-{ロビー}-{乱数?} 

という構造である。
また、tw=1の部分は自分がどのユーザかを示す(後述)。

大量の牌譜を入手したい場合は、鳳凰卓のみ公開されている。
http://tenhou.net/sc/raw/

また天鳳位の一人ひとりの牌譜も公開されている。
http://tenhou.net/ranking.html

mjlogファイルの入手

http://tenhou.net/0/log/?2011020417gm-00a9-0000-b67fcaa3 のように入手できる。

観戦用リンクは /0/?log={ID}&tw={Who} に対し、牌譜リンクは /0/log/?{ID} であるので注意すること
このリンクは

などにリダイレクトされるが、正直よくわからない

mjlogファイルがgzip圧縮されているという記述をたまに見かけるので留意すること。 おそらく古いファイルのみで、私はあまり古いファイルを解析しないので遭遇していない。

ファイル構造

mjlogファイルはXML形式で記述されている。mjloggmタグ以下は階層構造を作っていない。

<mjloggm ver="2.3">
  <SHUFFLE seed="略" ref=""/>
  <GO type="169" lobby="0"/>
  <UN n0="%2D%72%6F%6E%2D" n1="%41%53%41%50%49%4E" n2="%E3%81%86%E3%81%8D%E3%81%A7%E3%82%93" n3="%E8%B6%85%E3%83%92%E3%83%A2%E3%83%AA%E3%83%AD" dan="16,19,16,18" rate="2135.55,2260.11,2018.07,2198.52" sx="M,M,M,M"/>
  <TAIKYOKU oya="0"/>
  <INIT seed="0,0,0,2,2,112" ten="250,250,250,250" oya="0" hai0="48,16,19,34,2,76,13,7,128,1,39,121,87" hai1="17,62,79,52,56,57,82,98,32,103,24,70,54" hai2="55,30,12,26,31,90,3,4,80,125,66,102,78" hai3="120,130,42,67,114,93,5,61,20,108,41,100,84"/>
  <T107/>
  <D39/>
  <U47/>
  <E70/>
  <V14/>
  <F125/>
  (中略)
</mjloggm>

麻雀牌について

それぞれの牌には0~135のIDが割り当てられている。
0~3は1m,4~7は2mといった具合である。順序は萬子→筒子→索子→東南西北白發中である。Unicodeの配置順とは異なるため注意すること。
赤ありの場合、赤はmod4で0となる牌(16,52,88)に割り当てられている

hai = ["一", "二", "三", "四", "五", "六", "七", "八", "九", #萬子
       "①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧", "⑨", #筒子
       "1", "2", "3", "4", "5", "6", "7", "8", "9", #索子
      "東", "南", "西", "北", "白", "發", "中"]
return hai[id >> 2]

mjloggm

<mjloggm ver="2.3">

rootタグ。verは2.3

SHUFFLE

牌山について

<SHUFFLE seed="mt19937ar-sha512-n288-base64,pu4S9w/yELLYjkzj略" ref="" />

refは不明

seed

http://tenhou.net/man/に記述がある。

Q) 乱数種から山を生成する方法を教えてもらえませんか?
ツモ/配牌/王牌などなどは次の方法で乱数種から再現可能です
■2009年7月22日以降
牌山生成手順 http://blog.tenhou.net/article/30503297.html
牌山生成方法の検証用データ http://blog.tenhou.net/article/174202532.html
牌山生成乱数種のハッシュ公開β http://tenhou.net/stat/rand/

■2009年7月22日以前
unsigned long seed[n]; // INITのshuffleから生成
mt.init_by_array(seed,n);
for(i=0;i<136;++i) yama[i]=i;
for(i=0;i<136-1;++i) swap(yama[i],yama[i + (mt.genrand_int32()% (136-i))]); // サンマは108
※yama[135,134,133,132]が親の最初の配牌4枚、yama[0]が1つ目の嶺上牌

私はまだ検証していない

GO

対局形式について

<GO type="169" lobby="0"/>

type

対局形式を表す
http://tenhou.net/1/script/tenhou.js を読めば分かる。

BIT HEX FLAG=1 FLAG=0
1 0x001 対人戦 対コンピュータ戦
2 0x002 赤ナシ 赤アリ
3 0x004 喰ナシ 喰アリ
4 0x008 東南 東風
5 0x010 三麻 四麻
6 0x020 特上
7 0x040 5+10秒
8 0x080 上級
9 0x100
10 0x200
11 0x400 雀荘
12 0x800 技能

※特上と上級のフラグが両方立っているときは鳳凰、両方立ってないときは一般

(w&0x0020)>>4 | (w&0x0080)>>7; // 0=一般 1=上級 2=特上 3=鳳凰

例の169は10101001より、鳳南喰赤とわかる。

lobby

対局ロビーを表す。段位戦は0

UN

対局者について。
対局開始前に有るが、再接続時なども呼ばれる。再接続時はその人の名前のみ 三麻は三人分しか入ってない(4人目は、名前は"“、段位やレートはデフォルト値、性別はコンピュータ)。

四麻

<UN n0="%2D%72%6F%6E%2D" n1="%41%53%41%50%49%4E" n2="%E3%81%86%E3%81%8D%E3%81%A7%E3%82%93" n3="%E8%B6%85%E3%83%92%E3%83%A2%E3%83%AA%E3%83%AD" dan="16,19,16,18" rate="2135.55,2260.11,2018.07,2198.52" sx="M,M,M,M"/>

三麻

<UN n0="%E3%83%84%E3%83%BC%E3%82%A2%E3%82%A6%E3%83%88" n1="%E3%81%82%E3%82%8B%E3%81%B5%E3%81%83%E3%81%BF%E3%81%83" n2="%40%EF%BC%8D%E8%89%B2" n3="" dan="17,19,16,0" rate="2210,2440,2126,1500" sx="M,F,F,C"/>

再接続

<UN n0="%2D%72%6F%6E%2D"/>

n0,n1,n2,n3

対局者の名前がパーセントエンコーディングされている。観戦機能で匿名表示した時に順にAさん、Bさん、Cさん、Dさんと表示される。起家はAさんとなる。

dan

段位 Aさんから順にカンマ区切りで整数値が入っている。整数値の意味は以下

var DAN=[  
    "新人","9級","8級","7級","6級","5級","4級","3級","2級","1級",  
    "初段","二段","三段","四段","五段","六段","七段","八段","九段","十段",  
    "天鳳","RESERVED..."  
];  

rate

レート Aさんから順にカンマ区切りで整数値が入っている。

sx

性別 Aさんから順にカンマ区切りで1文字入っている。M:男性、F:女性、C:コンピュータ

BYE

<BYE who="2" />

who

切断したユーザを表す

TAIKYOKU

対局開始

<TAIKYOKU oya="0"/>

oya

0 固定 起家がAさんであることを表している

INIT

局開始

<INIT seed="0,0,0,0,3,33" ten="350,350,350,0" oya="0" hai0="74,124,51,60,3,36,100,107,123,108,121,111,127" hai1="130,91,56,96,112,117,93,97,2,109,126,79,69" hai2="110,118,52,133,63,62,61,44,49,88,114,59,101" hai3=""/>

seed

この局について カンマ区切りで整数値が入っている。

i seed[i]
0 東一局~北四局 0-3が東一-東四、4-7が南場、8-11が西場
1 本場
2 リーチ棒の本数
3 一つ目のサイコロの目-1
4 二つ目のサイコロの目-1
5 ドラ表示牌

ten

点数 Aさんから順にカンマ区切りで整数値が入っている。100倍すること。

oya

親の人を表す

hai0,hai1,hai2,hai3

配牌を表す 牌を表す整数値がカンマ区切りで入っている

[T-W][0-9]*

ツモを表す
TならばAさん、UならばBさん、VならばCさん、WならばDさんのツモ
その後の数が牌を表す

<V94/>

[D-G][0-9]*

打牌を表す
DならばAさん、EならばBさん、FならばCさん、GならばDさんの打牌
その後の数が牌を表す

<D39/>

REACH

立直を表す

<REACH who="1" step="1"/>
<E115/>
<REACH who="1" ten="250,240,250,250" step="2"/>

who

立直をした人を表す

step

1のとき立直宣言をする。その後打牌をし、ロンされなければstep=“2"が呼ばれる。

ten

リーチ棒を除いた後の点数を表す

N

鳴きを表す

<N who="3" m="42031" />

who

鳴いた人を表す

m

鳴きの形を表す 16bitの整数値
http://tenhou.net/img/tehai.js に詳しい

鳴き FLAG
順子 m&0x0004
刻子 m&0x0008
加槓 m&0x0010
北抜き m&0x0020
大明槓・暗槓 otherwise

上記の表に従って上から順に判定し、鳴きの形を決定する

順子
BIT HEX 内容
1-2 0x0003 食われた人 上家なので3
3 0x0004 順子フラグ 1
4-5 0x0018 最小の数牌のID mod 4
6-7 0x0060 真ん中の数の数牌のID mod 4
8-9 0x0180 最大の数牌のID mod 4
10 0x0200 空き
11-16 0xfc00 下記

11-16bit目の値をtとする
1m,…,7m,1s,…,7s,1p,…,7pの21枚の中で floor(t/3)番目のものを最小の数牌とする。
floor(t/3)+t%3の数牌が鳴かれた牌

刻子・加槓
BIT HEX 内容
1-2 0x0003 食われた人 下家1,対面2,上家3
3 0x0004 空き
4 0x0008 刻子フラグ 刻子なら1
5 0x0010 加槓フラグ 加槓なら1
6-7 0x0060 未使用牌ID mod4
8-9 0x0180 空き
10-16 0xfe00 下記

10-16bit目の値をtとする
1m,…,9m,1s,…,9s,1p,…,9p東南西北白發中の34枚の中で floor(t/3)番目のものを鳴いた牌とする。
未使用牌を除いて昇順に並べた時、t % 3番めの牌が鳴かれた牌

北抜き
BIT HEX 内容
1-5 0x001f 空き
6 0x0020 北抜きフラグ
7-8 0x00c0 空き
9-16 0xff00 牌ID

大明槓・暗槓
BIT HEX 内容
1-2 0x0003 食われた人 暗槓0,下家1,対面2,上家3
3-8 0x00fc 空き
9-16 0xff00 鳴いた牌ID

DORA

槓ドラ 明槓・加槓はツモの後、暗槓の場合は鳴きの後

<DORA hai="8" />

hai

槓ドラ表示牌のID

AGARI

誰かが和了したことを示す。ダブロンなど、2つ発生することもある。

<AGARI ba="2,2" hai="17,22,26,68,70,74,77,81,84,91,94" m="44618" machi="91" ten="30,2000,0" yaku="12,1,52,1" doraHai="73" who="1" fromWho="1" sc="215,-7,285,46,328,-7,152,-12" />

ba

場に出ている点棒を表す カンマ区切りの整数で、ba[0]が百点棒(本場)、ba[1]がリーチ棒を表す。

hai

和了した時の手牌。和了牌も含まれている。 カンマ区切りの整数で牌IDを表す。

m

副露があるときのID カンマ区切りの整数でNのmに同じ

machi

和了

ten

点数に関する情報 カンマ区切りの整数で、ten[0]が符、ten[1]が和了点を表す。
ten[2]は和了ランクを表し、以下

ten[2] 内容
0 なし
1 満貫
2 跳満
3 倍満
4 三倍満
5 役満

yaku

役について
[役A,役Aの翻数,役B,役Bの翻数,役C,役Cの翻数]と言った具合である。 役満はyakuman属性に記述される。

var YAKU=[
    //// 一飜
    "門前清自摸和","立直","一発","槍槓","嶺上開花",
    "海底摸月","河底撈魚","平和","断幺九","一盃口",
    "自風 東","自風 南","自風 西","自風 北",
    "場風 東","場風 南","場風 西","場風 北",
    "役牌 白","役牌 發","役牌 中",
    //// 二飜
    "両立直","七対子","混全帯幺九","一気通貫","三色同順",
    "三色同刻","三槓子","対々和","三暗刻","小三元","混老頭",
    //// 三飜
    "二盃口","純全帯幺九","混一色",
    //// 六飜
    "清一色",
    //// 満貫
    "人和",
    //// 役満
    "天和","地和","大三元","四暗刻","四暗刻単騎","字一色",
    "緑一色","清老頭","九蓮宝燈","純正九蓮宝燈","国士無双",
    "国士無双13面","大四喜","小四喜","四槓子",
    //// 懸賞役
    "ドラ","裏ドラ","赤ドラ"
];

tenhou.jsより

yakuman

役満の種類 複合役満の場合、カンマ区切りの整数 役満のときのみ存在

doraHai

ドラ牌 複数ある場合はカンマ区切りの整数

doraHaiUra

裏ドラ牌 複数ある場合はカンマ区切りの整数 存在しないときは省略される

who

誰が和了したか

fromWho

誰が放銃したか ツモ和了の場合whoと一致する

sc

点数 カンマ区切りの符号付き整数
[Aさんの点数, Aさんの変動,Bさんの点数,Bさんの変動,……,Dさんの変動]
この点数は変動が反映される前の点数となっている

owari

終局を示す
点数 カンマ区切りの符号付き整数
[Aさんの点数, Aさんのスコア,Bさんの点数,Bさんのスコア,……,Dさんのスコア]
スコアにはウマが含まれている

RYUUKYOKU

流局を示す

<RYUUKYOKU ba="1,2" sc="200,15,270,15,343,-15,167,-15" hai0="8,9,15,19,20,24,25,26,29,33,41,47,50" hai1="27,30,52,53" />

ba

場に出ている点棒を表す カンマ区切りの整数で、ba[0]が百点棒(n本場)、ba[1]がリーチ棒を表す。

sc

点数 カンマ区切りの符号付き整数
[Aさんの点数, Aさんの変動,Bさんの点数,Bさんの変動,……,Dさんの変動]
この点数は変動が反映される前の点数となっている

hai0,hai1,hai2,hai3

流局によって手牌が公開される場合の牌。カンマ区切りの整数
副露したものは示されない。
聴牌したプレイヤーもしくは九種九牌のプレイヤーのみ表示

type

流局の種類 通常の流局以外の場合存在

type 流局
yao9 九種九牌
reach4 四家立直
ron3 三家和了
kan4 四槓散了
kaze4 四風連打
nm 流し満貫

owari

終局を示す
点数 カンマ区切りの符号付き整数
[Aさんの点数, Aさんのスコア,Bさんの点数,Bさんのスコア,……,Dさんのスコア]
スコアにはウマが含まれている