将棋エンジンを作ってみる【ルール実装編(3)】SFEN文字列

[前回の記事](https://qiita.com/samakusa/items/d68b3e450d60e2daf6de)でUSIプロトコルについて解説した。
その中で「SFEN文字列」が出てきたので、詳しく解説しようと思う。
USIプロトコルとSFEN文字列が理解できれば、将棋エンジンを作るための基礎的な知識は揃ったといえると思う。

なお、今回の記事は解説のみで実装はしない。
実際の活用の仕方は今後の記事で紹介したいと思う。

# SFEN文字列とは

前回の記事ではSFEN文字列について、
「将棋エンジン(コンピュータ)に局面および指し手を伝えるための文字列」と説明した。
これは実際にそのとおり。

コンピュータに局面図や「２六歩」といった符号を送りつけても、当然理解されない。
局面や指し手を送りつけるなら、コンピュータが理解できるよう文字列に変換する必要がある。

<img src="https://github.com/samakusa/qiita_resource/blob/master/003_%E5%B0%86%E6%A3%8B%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%90%E3%83%AB%E3%83%BC%E3%83%AB%E5%AE%9F%E8%A3%85%E7%B7%A8(3)%E3%80%91SFEN%E6%96%87%E5%AD%97%E5%88%97/%E5%B0%8E%E5%85%A5.jpg?raw=true">

SFEN文字列に関する決まりごともUSIプロトコルのページで紹介した以下のページにまとめられている。
[USIプロトコル原案](http://web.archive.org/web/20150525174702/http://www.glaurungchess.com/shogi/usi.html)
[将棋所の作者がまとめている日本語版](http://shogidokoro.starfree.jp/usi.html)

SFEN文字列は大きく、局面を示すものと、指し手を示すものがある。
決まりごと自体はそれほど難しくないと思うので、それぞれ見ていく。

# 共通の決まりごと

局面を示すSFEN文字列と指し手を示すSFEN文字列で駒の表記方法は共通している。
成り駒であることを示す1文字「+」と駒の種類を示すアルファベット１文字で表される。
先手の駒は大文字、後手の駒は小文字で表される。

言葉で説明するより、↓こうした方が理解が早いと思う。

|生駒 |先手 |後手 |成駒 |先手 |後手 |
|---|---|---|---|---|---|
|歩 |P |p |と金 |+P |+p |
|香 |L |l |成香 |+L |+l |
|桂 |K |k |成桂 |+K |+k |
|銀 |S |s |成銀 |+S |+s |
|金 |G |g |- |- |- |
|角 |B |b |馬 |+B |+b |
|飛 |R |r |龍 |+R |+r |
|王 |K |k |- |- |- |

# 局面のSFEN文字列

局面のSFEN文字列は「(盤上) (手番) (持ち駒) (手数)」の形式で表されます。
それぞれの表記方法を見ていきます。

## 盤上

盤上の配置に関する決まりごとは以下の通り。

- 1段目の左側から駒の種類(上記表参照)を表記していく。
- 段ごとの区切り文字としてスラッシュ「/」を表記する。
- 駒のない升は、連続する升の数を数字で表記する。

文字だけだとわかりにくいと思うので図に示す。

<img src="https://github.com/samakusa/qiita_resource/blob/master/003_%E5%B0%86%E6%A3%8B%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%90%E3%83%AB%E3%83%BC%E3%83%AB%E5%AE%9F%E8%A3%85%E7%B7%A8(3)%E3%80%91SFEN%E6%96%87%E5%AD%97%E5%88%97/%E7%9B%A4%E4%B8%8A.jpg?raw=true">

例えば平手初期局面の盤上のSFEN文字列は「lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL」となる。

## 手番

1文字で表記する。
先手は「b」、後手は「w」と表記する。

# 持ち駒

「(先手の持ち駒)(後手の持駒)」の形式で表記する。どちらも持ち駒がないときはハイフン(-)と表記する。
持ち駒は駒の種類+その枚数(1枚の場合は省略)で表記する。

例として先手側が銀１枚歩２枚、後手側が角１枚歩３枚であれば、「S2Pb3p」と表記する。

## 手数

次の指し手の手数をそのまま数字で記載する。
初期局面なら「1」となる。

## ここまでまとめ

参考までに各種手合における初期局面のSFEN文字列全体を示す。

|手合 |SFEN文字列 |
|---|---|
|平手 |lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1 |
|香落ち |lnsgkgsn1/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |
|角落ち |lnsgkgsnl/1r7/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |
|飛車落ち |lnsgkgsnl/7b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |
|飛車香落ち |lnsgkgsn1/7b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |
|二枚落ち |lnsgkgsnl/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |
|四枚落ち |1nsgkgsn1/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |
|六枚落ち |2sgkgs2/9/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL w - 1 |

駒落ち将棋は初期局面の手番が後手(上手)なので注意が必要だ。

# 指し手のSFEN文字列

将棋の指し手には駒移動と駒打ちのケースがある。
それぞれのケースについて解説するが、
その前に升の表記方法は駒移動、駒打ち両方に共通するため、先に解説しておく。

## 升の表記方法

SFEN文字列において、筋は1から9までの数字で、段はaからiまでのアルファベット(1段目がa、2段目がb、・・・、9段目がi)というように表記する。
これも文字列では伝わりにくいと思うので、以下に図示する。
<img src="https://github.com/samakusa/qiita_resource/blob/master/003_%E5%B0%86%E6%A3%8B%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%90%E3%83%AB%E3%83%BC%E3%83%AB%E5%AE%9F%E8%A3%85%E7%B7%A8(3)%E3%80%91SFEN%E6%96%87%E5%AD%97%E5%88%97/%E5%8D%87%E3%81%AE%E8%A1%A8%E8%A8%98%E6%96%B9%E6%B3%95.jpg?raw=true">
例えば２六の地点は"2f"となる。
(ここまでくればもはや↑こんな説明は不要だろうが)

## 駒移動指し手のSFEN文字列

駒移動指し手のSFEN文字列は「(移動元の升)(移動先の升)(成 or not)」の形式で表記する。
(成 or not)の部分は、成る場合は"+"、ならない場合はなにも表記しない。

将棋における指し手の符号は駒の種類を含めるが(「２六歩」といった具合)、
SFEN文字列では移動元の升により駒の種類が一意に定まるため表記する必要がない。

例えば初期局面から「▲２六歩」(２七の歩を２六に移動する)とする場合、
「2g2f」と表記する。
もう一例、「▲２三歩成」(２四の歩を２三に移動した上で成る)とする場合、
「2d2c+」と表記する。

## 駒打ち指し手のSFEN文字列

駒打ち指し手のSFEN文字列は「(駒の種類)*(打つ升)」の形式で表記する。

例えば先手が歩を２四の地点に打つ場合、
「P*2d」と表記する。
先程書いたとおり、後手の駒は小文字で表記する。
なので、後手が歩を２四の地点に打つ場合、先手のときと異なり、
「p*2d」と表記する。

# おわりに

USIプロトコルとSFEN文字列が理解できれば、
普段将棋ソフトウェア(ShogiGUIなど)を通して使っている将棋エンジンと会話して対局することも可能となる。

次回からは[前回の記事](https://qiita.com/samakusa/items/d68b3e450d60e2daf6de)で作成した即投了するエンジンに順次ルールを実装していこうと思う。