機械学習のための”ごいた”の棋譜の保存形式の設計

放課後さいころ倶楽部 3 (ゲッサン少年サンデーコミックス)
まだ考え中で、確定ではありません。コメント募集中。

背景

2015年1月から、ごいたのコンピュータ対戦プログラムを書いていたが、約1ヶ月が経過したところで手続き型コーディングによる改善に限界を感じるようになった。その後に半月ほど、総当りプログラムができないものかと思考していたが、これも計算困難だと判断した。このため抜本的な改善のために、教師データを収集して機械学習をするべきとの考えに至った。

機械学習用の教師データを収集するために、ごいたの棋譜をプログラミングと親和性の高い形式で記録する必要性がある。本稿では、機械学習のためのごいたの棋譜データの保存形式を提案する。

モデルゲーム

棋譜の定義の前に、説明のためのモデルゲームを示す。

モデルゲームA(最短)
player hand
0. Alice(dealer) 王玉香香香香しし
1. Bob 飛飛金金金金しし
2. Carol 角銀銀銀銀ししし
3. Dave 角馬馬馬馬ししし
turn Alice Bob Carol Dave
1st ☗し☖香 なし なし なし
2nd ☗し☖香 なし なし なし
3rd ☗香☖香 なし なし なし
4th ☗王☖玉      
モデルゲームB(最長)
player hand
0. Alice(dealer) 王玉飛香香香しし
1. Bob 飛金金金金銀しし
2. Carol 角銀銀銀馬ししし
3. Dave 角馬馬馬香ししし
turn Alice Bob Carol Dave
1st ☗王☖香 なし なし なし
2nd ☗玉☖香 なし なし なし
3rd ☗し☖香 なし なし ☖香☖馬
4th なし なし なし ☗し☖馬
5th なし なし なし ☗し☖馬
6th なし なし ☖馬☖銀 なし
7th なし なし ☗し☖銀 なし
8th なし なし ☗し☖銀 なし
9th なし ☖銀☖金 なし なし
10th なし ☗し☖金 なし なし
11th なし ☗し☖金 なし なし
12th なし ☗金☖飛    

Aliceの手駒は王1枚以上香3枚し1枚であるため、実は配駒時に勝利が確定しているのだが、勘違いしてこのような棋譜になったとする。

定義

駒:piece

次のように、0-9までの数値で保存する。(仮に手入力をする場合であっても、テンキーのみでタイプができる方が効率が良いと判断したため。)王と玉は、機械学習においては違いが意味をなさないため、同じ値として扱う。

1:王 or 玉, 2:飛, 3:角, 4:金, 5:銀, 6:馬, 7:香, 8:し
9:裏
0:なし
プレイヤー番号:player number

順に0, 1, 2, 3とする。0の対面は2。相手チームは0の次の番のプレイヤーが1、残りのプレイヤーが3となる。通常のゲームでは、親はプレイヤー0から始まる。

0:Alice(dealer), 1:Bob, 2:Carol, 3:Dave

Machine-readableなごいたの棋譜

ごいたは不完全情報ゲームであるため、対戦プロトコル棋譜とで別の定義をする必要がある。ここでは棋譜を定義する。

JSONを利用する。

形式の宣言:declaration(MUST)

棋譜なのか、対戦プロトコルなのかを明示するため、先頭行に記載する。

【考え中】
対局の名前:match name(MAY)
"title":"◯×大会予選1回戦第1局"
開始/終了日時:start/end time(MAY)

ISO 8601に従う。開始日時もしくは終了日時の片方のみの記載も可。

"start_time":"2004-04-01T12:00Z"
"end_time":"2004-04-01T12:00+09:00"
プレイヤー名:player name(MAY)

プレイヤー番号順に記入する。

"players":["Alice", "Bob", "Carol", "Dave"]
棋譜:record of a round(MUST)

数字を連結して表現する。ダブルクオートで囲う。可視性を高めるために"-"を適宜挿入してもよい。ごいたのルールを考慮すると、ゲーム終了の棋譜は、最短で17個、最大59個の数字の連結となる。モデルゲームAを表現すると次のようになる。

"record":"87000870007700011"
もしくは、
"record":"87-0-0-0-87-0-0-0-77-0-0-0-11"

モデルゲームBを表現すると次のようになる。

"record":"17000170008700760008600086006500085000850054000840008400042"

勝敗の決していない途中の局面も可。なおゲーム開始時の状態であれば次のようになる。

"record":""
配駒:hands of 4 players(MUST)

8個の数字の連結とする。親から順に4人分の駒を記載する。ダブルクオートで囲う。モデルゲームAであれば、

"hands":["11777788", "22444488", "35555888", "36666888"]

モデルゲームBであれば、

"hands":["11277788", "24444588", "35556888", "36667888"]

となる。必須ではないが、昇順にソートしておくのが望ましい。

親:dealer(SHOULD)

親のプレイヤー番号。省略された場合には自動的に0とする。

"dealer":0
スコア:score(SHOULD)

ゲーム開始前の得点。

"score":[120, 90]
勝者:winner of a round(SHOULD)

その局に勝利したプレイヤーの番号。親が勝利した場合は、

"winner":0

となる。まだ勝負が決していない途中の局面の棋譜の場合は、0,1,2,3以外の値を持つ。省略された場合も、勝負が決していないとする。

"winner":-1
5し:goshi(SHOULD)

5しを宣言したプレイヤーの番号。最大2個まで。なお6し、7し、8しが発生したとしても、ここには記載しない。省略された場合には5しのプレイヤーはいなかったものとする。

"goshi":[] #5しはいない
"goshi":[0] #親のAliceが5し
"goshi":[1, 2] #BobとCarolが5し 

棋譜の例

モデルゲームA(が2回連続で発生した場合)
{
    "title":"モデルゲームA",
    "start_time":"2015-04-01T12:00+09:00",
    "end_time":"2015-04-01T12:20+09:00",
    "players":["Alice", "Bob", "Carol", "Dave"],
    "round":{
        "dealer":0,
        "score":[0, 0],
        "hands":["11777788", "22444488", "35555888", "36666888"],
        "record":"87000870007700011",
        "winner":0,
        "goshi":
    },
    "round":{
        "dealer":0,
        "score":[100, 0],
        "hands":["11777788", "22444488", "35555888", "36666888"],
        "record":"87000870007700011",
        "winner":0,
        "goshi":
    }
}
モデルゲームB
{"round":{"hands":["11277788","24444588","35556888","36667888"],"record":"17000170008700760008600086006500085000850054000840008400042","winner":0}}

考え中のこと

  • 形式の宣言。バージョン情報などを書きたいが、ほんとうにいるのか考え中。いきなり複雑な形式を定義してしまうと、実装が大変になってしまうため、まだ迷っている状態。
  • 反則とか起きた時はどうするんだ?
  • 対戦プロトコルをどうするか。対戦の場合、敵味方の手や裏返っている駒は分からないため。アイディアはあるが、棋譜との親和性をどこまで残すかを考え中。