PHPで将棋のUSIプロトコルに挑戦

## はじめに

PHPで将棋のUSIプロトコルに挑戦します。[→JScript版はこちら](https://qiita.com/economist/items/83badfdde88333a56d7b)
将棋ソフトは各自用意してください。

## USIプロトコルの例

USIプロトコルの例です。これをPHPで書いていきます。

将棋ソフトと通信を開始し、初手76歩とした局面を1秒間検討し、評価値や読み筋を取得するのが目的です。
``>``で始まる行はコマンド送信、それ以外は受信となります。



~~~
>usi
id name NNUE-v1.0 64SSE2 (based on YaneuraOu 2018 Otafuku 4.82)
id author by yaneurao, extended by ynasu87
option name Threads type spin default 4 min 1 max 512
option name Hash type spin default 16 min 1 max 1048576
option name MultiPV type spin default 1 min 1 max 800
option name WriteDebugLog type check default false
option name NetworkDelay type spin default 120 min 0 max 10000
option name NetworkDelay2 type spin default 1120 min 0 max 10000
option name MinimumThinkingTime type spin default 2000 min 1000 max 100000
option name SlowMover type spin default 100 min 1 max 1000
option name MaxMovesToDraw type spin default 0 min 0 max 100000
option name DepthLimit type spin default 0 min 0 max 2147483647
option name NodesLimit type spin default 0 min 0 max 9223372036854775807
option name Contempt type spin default 2 min -30000 max 30000
option name ContemptFromBlack type check default false
option name EnteringKingRule type combo default CSARule27 var NoEnteringKing var CSARule24 var CSARule27 var TryRule
option name EvalDir type string default eval
option name SkipLoadingEval type check default false
option name NarrowBook type check default false
option name BookMoves type spin default 16 min 0 max 10000
option name BookIgnoreRate type spin default 0 min 0 max 100
option name BookFile type combo default standard_book.db var no_book var standard_book.db var yaneura_book1.db var yaneura_book2.db var yaneura_book3.db var yaneura_book4.db var user_book1.db var user_book2.db var user_book3.db var book.bin
option name BookEvalDiff type spin default 30 min 0 max 99999
option name BookEvalBlackLimit type spin default 0 min -99999 max 99999
option name BookEvalWhiteLimit type spin default -140 min -99999 max 99999
option name BookDepthLimit type spin default 16 min 0 max 99999
option name BookOnTheFly type check default false
option name ConsiderBookMoveCount type check default false
option name PvInterval type spin default 300 min 0 max 100000
option name ResignValue type spin default 99999 min 0 max 99999
option name nodestime type spin default 0 min 0 max 99999
option name Param1 type spin default 0 min 0 max 100000
option name Param2 type spin default 0 min 0 max 100000
option name EvalSaveDir type string default evalsave
option name ConsiderationMode type check default false
option name OutputFailLHPV type check default true
usiok

>isready
readyok

>usinewgame
>position startpos moves 7g7f
>go byoyomi 1100
info depth 1 seldepth 1 score cp -84 nodes 82 nps 41000 time 2 pv 8c8d
info depth 2 seldepth 2 score cp -60 nodes 121 nps 40333 time 3 pv 8c8d 2g2f
info depth 10 seldepth 12 score cp -41 nodes 41683 nps 150480 time 277 pv 3c3d 2g2f 4a3b 5i6h 5a4b 4i5h 8c8d 6i7h 2b8h+
bestmove 3c3d ponder 2g2f

>quit
~~~

``info``で始まる行にて、評価値や読み筋を取得できます。
``score cp``に続く数字が評価値、``pv``に続く文字列が読み筋です。

## PHPでの記述例

PHPでは``proc_open()``と``fgets()``と``fwrite()``の3つを使用します。
もっと良い方法があると思いますが、分かりません。

```php
<?php
$process = proc_open('YaneuraOu.exe', [['pipe','r'],['pipe', 'w']], $pipe);
if (!is_resource($process)) {
    exit;
}

fwrite($pipe[0], "usi\n");

while(1){
    $line = fgets($pipe[1]);
    print $line;
    if(preg_match('/^usiok/', $line)){
        break;
    }
}

fwrite($pipe[0], "isready\n");
print fgets($pipe[1]);

fwrite($pipe[0], "usinewgame\n");
fwrite($pipe[0], "position startpos moves 7g7f\n");
fwrite($pipe[0], "go byoyomi 1100\n");

while(1){
    $line = fgets($pipe[1]);
    print $line;
    if(preg_match('/^bestmove/', $line)){
        break;
    }
}

fwrite($pipe[0], "quit\n");
proc_close($process);
```

続けて2手目(34歩)を検討するには、``quit``の前に次のようなコマンドを送信します。
指し手を2つ書くだけなので簡単です。

```
>position startpos moves 7g7f 3c3d
>go byoyomi 1100
```

``7g7f``などの指し手の表記方法については、以下の説明と参考サイトを参考にしていください。

```
筋に関しては１から９までの数字で表記され、段に関してはaからiまでのアルファベット（１段目がa、２段目がb、・・・、９段目がi）というように表記されます。
位置の表記は、この２つを組み合わせます。５一なら5a、１九なら1iとなります。
そして、指し手に関しては、駒の移動元の位置と移動先の位置を並べて書きます。７七の駒が７六に移動したのであれば、7g7fと表記します。（駒の種類を表記する必要はありません。）
駒が成るときは、最後に+を追加します。８八の駒が２二に移動して成るなら8h2b+と表記します。
持ち駒を打つときは、最初に駒の種類を大文字で書き、それに*を追加し、さらに打った場所を追加します。金を５二に打つ場合はG*5bとなります
```

## 参考サイト

http://shogidokoro.starfree.jp/usi.html
https://qiita.com/tag1216/items/aa4ddc9354c83c66d1b4