shogi64 v0.0.3
shogi64.js
将棋の局面をShogi64にエンコード/デコードするライブラリ。
About Shogi64
Shogi64とは局面データをバイナリに変換し、さらにBase64urlに変換するまでを形式化したものである。
Base64url
Base64urlはBase64をURLで利用しやすくしたエンコード方式である。
- 64文字 * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_
- パディング無し
- 可変長
- 空白・改行無し
- 行の最大長はアプリケーション依存
詳しくは以下のURLを参照。
Position Data Format
プログラム上での局面データのフォーマットは以下の通り。
Position {
- turnboolean
- boardarray
- handsobject blackobject FUnumber KYnumber KEnumber GInumber KInumber KAnumber HInumber whiteobject FUnumber KYnumber KEnumber GInumber KInumber KAnumber HInumber
}
- turnboolean 手番 先手がtrue、後手がfalse
- boardarray
* 盤上の駒
- 盤面のマスは1次元配列の9×9の81とし、空白と駒は対応する数値で表す
- handsobject 持ち駒 先後共に歩から飛まで必ずプロパティに含めて表す
Piece Table
上記のPosition.boardプロパティで扱う駒や空白は数値に変換して扱う。それぞれ対応する数値は以下の通りである。
| 駒種 | 先手 | 後手 |
|---|---|---|
| 空白 | 0 | 0 |
| 歩 | 1 | -1 |
| 香 | 2 | -2 |
| 桂 | 3 | -3 |
| 銀 | 4 | -4 |
| 金 | 5 | -5 |
| 角 | 6 | -6 |
| 飛 | 7 | -7 |
| 玉 | 8 | -8 |
| と | 9 | -9 |
| 成香 | 10 | -10 |
| 成桂 | 11 | -11 |
| 成銀 | 12 | -12 |
| 馬 | 13 | -13 |
| 龍 | 14 | -14 |
Example Position Data
以上の仕様を用いて書かれた初期局面のコードを紹介する。
var position = {
'turn': true,
'board':[-2,-3,-4,-5,-8,-5,-4,-3,-2,
0,-7,0,0,0,0,0,-6,0,
-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,
0,6,0,0,0,0,0,7,0,
2,3,4,5,8,5,4,3,2],
'hands': {'black': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0},
'white': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0}}
};Binary Data Format
局面データのコードをハフマン符号で構成されたバイナリに変換する際にShogi64では2通りのエンコードモードがあり、Normal ModeとMixed Modeが存在する。
Normal Mode
基本的にはNormal Modeのフォーマットでバイナリに変換される。
| 手番 | モード | 先手玉の位置 | 後手玉の位置 | 先手歩の位置 | 先手歩の位置 | その他の駒 | 先手持ち駒 | 後手持ち駒 |
|---|---|---|---|---|---|---|---|---|
| 1 bit | 1 bit | 7 bit | 7 bit | ? bit | ? bit | ? bit | ? bit | ? bit |
Mixed Mode
Normal Modeのフォーマットで変換できない局面(ルール上問題があるが、玉が複数あったり二歩であるといったケースなど)はこちらのフォーマットで変換される。
| 手番 | モード | 全ての駒 | 先手持ち駒 | 後手持ち駒 |
|---|---|---|---|---|
| 1 bit | 1 bit | ? bit | ? bit | ? bit |
Turn(手番)
1bit固定長で、手番が先手であれば1、後手であれば0とする。
Mode(モード)
1bit固定長で、Mixed Modeであれば1、Normal Modeであれば0とする。
King Coordinate(玉の位置)
7bit固定長で先手と後手で合計14bitとなる。盤面左上(配列の最初の要素)から右下(配列の最後の要素)までを1〜81として、これを2進数に変換した0000001〜1010001を使って表される。0(0000000)は玉が無いことを意味する。
| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 筋/段 |
|---|---|---|---|---|---|---|---|---|---|
| 00000001 | 0000010 | .. | .. | .. | .. | .. | .. | .. | 一 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 二 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 三 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 四 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 五 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 六 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 七 |
| .. | .. | .. | .. | .. | .. | .. | .. | .. | 八 |
| .. | .. | .. | .. | .. | .. | .. | 1010000 | 1010001 | 九 |
Pawn Coordinate(歩の位置)
9筋から1筋にかけて歩が出現する位置(段)を符号化して順に並べられたデータとなる。こうすることで符号の並び順で筋、符号で段を表す仕組みとなっている。歩が存在しない筋も符号化されるが、一段(後手なら九段)は歩が置けないのであらかじめ除かれる。
それぞれ対応する符号は次の表の通りで、0段は歩が存在しないことを意味する。
| 先手(段) | 後手(段) | ハフマン符号 |
|---|---|---|
| 七 | 三 | 0 |
| 六 | 四 | 10 |
| 0 | 0 | 110 |
| 五 | 五 | 1110 |
| 四 | 六 | 11110 |
| 八 | 二 | 111110 |
| 三 | 七 | 1111110 |
| 九 | 一 | 11111110 |
| 二 | 八 | 11111111 |
Ohter Piece(その他の駒)
玉と歩を除いた全ての駒と空白を盤面左上(配列の最初の要素)から順に符号化して並べられたデータとなる。それぞれ対応する符号は以下の表の通り。
| 駒種 | ���値 | ハフマン符号 |
|---|---|---|
| 空白 | 0 | 0 |
| 歩 | 1 | 無し |
| 香 | 2 | 100 |
| 金 | 5 | 101 |
| 桂 | 3 | 1100 |
| 銀 | 4 | 1101 |
| 玉 | 8 | 無し |
| 飛 | 7 | 1110 |
| 角 | 6 | 11110 |
| 馬 | 13 | 1111100 |
| 龍 | 14 | 1111101 |
| と | 9 | 1111110 |
| 成桂 | 11 | 11111110 |
| 成銀 | 12 | 111111110 |
| 成香 | 10 | 111111111 |
- ※1 変換する際に先手は1、後手は0を符号の末尾に付け加える
- ※2 ハフマン符号はこちらを参考
All Piece(全ての駒)
全ての駒と空白を盤面左上(配列の最初の要素)から順に符号化して並べられたデータとなる。Mixed Modeではこちらの表を用いて符号化される。
| 駒種 | 数値 | ハフマン符号 |
|---|---|---|
| 空白 | 0 | 0 |
| 歩 | 1 | 10 |
| 香 | 2 | 1100 |
| 金 | 5 | 1101 |
| 桂 | 3 | 11100 |
| 銀 | 4 | 11110 |
| 玉 | 8 | 111010 |
| 飛 | 7 | 111011 |
| 角 | 6 | 111110 |
| 馬 | 13 | 11111100 |
| 龍 | 14 | 11111101 |
| と | 9 | 11111110 |
| 成桂 | 11 | 111111110 |
| 成銀 | 12 | 1111111110 |
| 成香 | 10 | 1111111111 |
- ※1 変換する際に先手は1、後手は0を符号の末尾に付け加える
- ※2 ハフマン符号はこちらを参考
Hands(持ち駒)
持ち駒の数を歩、香、桂、銀、金、角、飛の順に符号化して並べられたデータとなる。
Pawn(歩)
| 数 | ハフマン符号 |
|---|---|
| 0 | 00 |
| 1 | 01 |
| 2 | 10 |
| 3 | 110 |
| 4 | 1110 |
| 5 | 11110 |
| 6 | 111110 |
| 7 | 1111110 |
| 8 | 11111110 |
| 9 | 111111110 |
| 10 | 1111111110 |
| 11 | 11111111110 |
| 12 | 111111111110 |
| 13 | 1111111111110 |
| 14 | 11111111111110 |
| 15 | 111111111111110 |
| 16 | 1111111111111110 |
| 17 | 11111111111111110 |
| 18 | 11111111111111111 |
Minor Piece(香、桂、銀、金)
| 数 | ハフマン符号 |
|---|---|
| 0 | 0 |
| 1 | 10 |
| 2 | 110 |
| 3 | 1110 |
| 4 | 1111 |
Major Piece(角、飛)
| 数 | ハフマン符号 |
|---|---|
| 0 | 0 |
| 1 | 10 |
| 2 | 11 |
Encode Example
エンコードの流れを初期局面を使って大まかに紹介する。
var position = {
'turn': true,
'board':[-2,-3,-4,-5,-8,-5,-4,-3,-2,
0,-7,0,0,0,0,0,-6,0,
-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,
0,6,0,0,0,0,0,7,0,
2,3,4,5,8,5,4,3,2],
'hands': {'black': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0},
'white': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0}}
};これを手番、モード、玉の位置、歩の位置、その他の駒、持ち駒の順に符号化してバイナリ形式に変換する。
101001101000010100000000000000000010001100011010101010101101011000100
001110000000111100000000000000000000000000000001111010000011101010011
10011101110111011110111100110010000000000000000このバイナリをわかりやすいよう区分すると、
| 手番 | モード | 先手玉 | 後手玉 | 先手歩 | 後手歩 | その他の駒 | 先手持ち駒 | 後手持ち駒 |
|---|---|---|---|---|---|---|---|---|
| 1 | 0 | 1001101 | 0000101 | 000000000 | 000000000 | 100011000110101010101011010110001000011100000001111000000000000000000000000000000011110100000111010100111001110111011101111011110011001 | 00000000 | 00000000 |
となる。次に、バイナリをBase64url形式に変換する。変換の方法についてはこちらを参照。
poUAACMaqtYhwHgAAAAPQdTnd3vMgAA以上の流れで局面データはエンコードされる。デコードについてはこの逆をするだけなので省略する。
Usage
Browser:
<script src="shogi64-x.x.x.min.js"></script>
<script>
var position = {
'turn': true,
'board':[-2,-3,-4,-5,-8,-5,-4,-3,-2,
0,-7,0,0,0,0,0,-6,0,
-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,
0,6,0,0,0,0,0,7,0,
2,3,4,5,8,5,4,3,2],
'hands': {'black': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0},
'white': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0}}
};
// encode
// encodeResult => poUAACMaqtYhwHgAAAAPQdTnd3vMgAA
var encodeResult = shogi64.encode(position);
// decode
var decodeResult = shogi64.decode('poUAACMaqtYhwHgAAAAPQdTnd3vMgAA');
// true
console.log(JSON.stringify(position) === JSON.stringify(decodeResult));
</script>Node:
installation
npm install shogi64 --saveexample
var shogi64 = require('shogi64');
var position = {
'turn': true,
'board':[-2,-3,-4,-5,-8,-5,-4,-3,-2,
0,-7,0,0,0,0,0,-6,0,
-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,
0,6,0,0,0,0,0,7,0,
2,3,4,5,8,5,4,3,2],
'hands': {'black': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0},
'white': {'FU':0, 'KY':0, 'KE': 0, 'GI': 0, 'KI': 0, 'KA': 0, 'HI': 0}}
};
// encode
// encodeResult => poUAACMaqtYhwHgAAAAPQdTnd3vMgAA
var encodeResult = shogi64.encode(position);
// decode
var decodeResult = shogi64.decode('poUAACMaqtYhwHgAAAAPQdTnd3vMgAA');
// true
console.log(JSON.stringify(position) === JSON.stringify(decodeResult));Licence
MIT