つぶやきとプログラミング

アメトーーク好きなWebエンジニア芸人

Mリーガーのレート・ランキングを天鳳・MaruJan・MJの3パターンで算出してみた!

  1. 概要
  2. 算出方法
  3. 結果
  4. まとめ
  5. dbテーブル構造

1.ランキングを出したい!

Mリーグの予選結果から算出しました。
試合数: 135
tym19851002.com

1.1. データの形式を整える

上記サイトの予選結果をテキストファイルAに張り付けコピー、
正規表現処理を行って形式を整えたテキストファイルBを生成しました。

赤坂ドリブンズ(園田賢 42900点 +58.0P)
ユーネクストパイレーツ(小林剛 38400点 +18.4P)
チーム雷電(萩原聖人 16700点 ▲23.3P)
セガサミーフェニックス(魚谷侑未 2000点 ▲58.0P)
re.match('(.+)(([^ ]* )(.+)点[  ]([▲++][^P]*)P', line)
1,園田賢,42900,58.0
2,小林剛,38400,18.4
3,萩原聖人,16700,-23.3
4,魚谷侑未,2000,-58.0

1.2 整形データからレーティングの算出

1.1で整形したデータをdbテーブルに入れて、試合結果に基づきレーティングを算出しました。
dbテーブル構造はブログの一番下に掲載。

2.算出方法

2.1.天鳳

Rの変動=試合数補正×(順位基準点+補正値) 
試合補正数:400試合未満 1-試合数×0.002   400試合以上 0.2 
順位基準点: 1位 +30 2位 +10 3位 -10 4位 -30 
補正値   :(卓平均R-自分のR)÷40(50に変更との噂あり)
www22.atwiki.jp

スコアをレーティング評価に含めず、順位、平均R、自分Rを引数にして評価しています。
400試合未満であるが簡単にするために試合補正数に0.2を用いました。

def tenhou(self, aveRate):
    ranking_point = 0
    if self.rank == 1:
      ranking_point = 30
    elif self.rank == 2:
      ranking_point = 10
    elif self.rank == 3:
      ranking_point = -10
    elif self.rank == 4:
      ranking_point = -30
    else:
      exit(8)

    self.rateChange = int(0.2 * (ranking_point + (aveRate - self.ratePre) / 40))
    self.ratePost = self.ratePre + self.rateChange

2.2.MaruJan式

(順位点+対局者による変動値) ×0.1
順位点: 四麻 1位 +100 2位 +20 3位 -40 4位 -80
対局者による変動値: (同卓者の平均Rt - 自分のRt)÷80
www.maru-jan.com

天鳳と同様に順位から算出している。

def marujan(self, aveRate):
    ranking_point = 0
    if self.rank == 1:
      ranking_point = 100
    elif self.rank == 2:
      ranking_point = 20
    elif self.rank == 3:
      ranking_point = -40
    elif self.rank == 4:
      ranking_point = -80
    else:
      exit(8)
    
    self.rateChange = int((ranking_point + (aveRate - self.ratePre) / 80) * 0.1)
    self.ratePost = self.ratePre + self.rateChange

2.3.MJ式

変動値 = 0.24 * (SCORE + HC)
HC = (卓平均R - 自分のR) / 40
www.sega-mj.com

天鳳・Marujanと違うのが順位ではなく、スコアからレーティングを算出するということです。

def mj(self, aveRate):
    self.rateChange = int(0.24 * (self.score + (aveRate - self.ratePre) / 40) )
    self.ratePost = self.ratePre + self.rateChange

3.結果

名前 tenhou marujan mj
多井隆晴 1538 1568 1623
佐々木寿人 1517 1530 1561
滝沢和典 1517 1526 1575
朝倉康心 1517 1525 1540
黒沢咲 1509 1523 1521
近藤誠一 1508 1519 1530
前原雄大 1507 1514 1507
園田賢 1506 1507 1533
勝又健志 1503 1506 1507
二階堂亜樹 1502 1501 1489
鈴木たろう 1500 1500 1507
松本吉弘 1499 1497 1504
茅森早香 1498 1491 1487
萩原聖人 1497 1490 1485
小林剛 1495 1486 1487
村上淳 1490 1485 1462
石橋伸洋 1490 1476 1447
魚谷侑未 1483 1474 1443
白鳥翔 1482 1470 1447
高宮まり 1478 1464 1436
瀬戸熊直樹 1473 1457 1406

f:id:crittoo96:20190317193026p:plain
レート比較(tenhou,marujan,mj)

4.まとめ

たかはるぅぅぅつんぇぇ...

順位からレートを出すtenhou式とmarujan式の順位はほぼ同一のものとなりました。

ただ、marujan法においては、総合得点が滝沢よりも100弱低い寿人の方が高い評価を得ました。
marujanでレートを重視するのであれば、トップラスの「攻めダルマ打法」をした方が良いということがわかりました。

スコアからレートを出すmj式は二つと異なる結果となりました。
mj式は、一定値が0.24かつ順位ではなくスコアを引数に取るため、試合数が少なくてもレートの上下幅が大きいです。
仲間内のセット麻雀で誰が一番強いかを決める際には、大きな値が出やすいmj式がよさそうです。

個人的には順位ではなく、スコアを重要視しているMJのレート評価を気に入りました。

自分なりにイロレーティングを調整してオリジナルレーティング算出手法を提案したりするのも面白そうです。

5.dbテーブル構造

mysql> desc mleaguers;
+-------------+-------------+------+-----+---------+----------------+
| Field       | Type        | Null | Key | Default | Extra          |
+-------------+-------------+------+-----+---------+----------------+
| id          | int(11)     | NO   | PRI | NULL    | auto_increment |
| team_id     | int(11)     | YES  | MUL | NULL    |                |
| name        | char(16) | YES  | UNI | NULL    |                |
| alternative | char(16) | YES  |     | NULL    |                |
| rating      | int(11)     | YES  |     | 1500    |                |
| total_score | double(6,1) | YES  |     | 0.0     |                |
| total_point | int(11)     | YES  |     | 0       |                |
+-------------+-------------+------+-----+---------+----------------+
7 rows in set (0.01 sec)

mysql> desc mleague_teams;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | char(32) | NO   | UNI | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> desc mleague_matches;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| date  | date | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> desc mleague_match_details;
+-------------+-------------+------+-----+---------+-------+
| Field       | Type        | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| match_id    | int(11)     | NO   | MUL | NULL    |       |
| mleaguer_id | int(11)     | NO   | MUL | NULL    |       |
| point       | int(11)     | YES  |     | 0       |       |
| score       | double(4,1) | YES  |     | 0.0     |       |
| rank        | int(11)     | YES  |     | NULL    |       |
+-------------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

すべてInnoDB