将棋評価値バーを作る（第４回）

前回からの続きです。

https://qiita.com/TETSURO1999/items/e256125419b636738485

# プレイヤー名の表示方法について

評価値バーで複数対局を同時に表示すると，これはどの対局なのか区別がつきにくいという課題があります。評価値バーをフルスクラッチから C# で作ろうと思い立った理由の一つでもあります。ShogiGUI では対局者（プレイヤー）の名前を設定できるので，この情報を評価値バーにも表示してやれば一目瞭然でしょう。ただ，その実装はいろいろ大変だったというお話です。

## (a)案：USI プロトコルを利用する
USI プロトコルはいわゆる将棋 GUI（ShogiGUI，将棋所など）と将棋エンジンの間でやり取りする情報を定義したものですが，将棋 GUI で設定した対局者の名前を将棋エンジン側に送る仕様がありません。そもそも将棋エンジンはプレイヤー名を知る必要がないからです。当然といえば当然でしょう。

ということで，(a)案は断念しました。

[USIプロトコルとは（将棋所）](http://shogidokoro.starfree.jp/usi.html)

## (b)案：評価値バー独自のオプションを設定する
将棋エンジンは起動直後，将棋 GUI に固有のオプションリストを送ります。評価値バーはこれらのリストにプレイヤー名（先手・後手）のオプションを追加してやり，将棋 GUI がこれらのオプションを設定すると，設定値が送られてくるので，この中からプレイヤー名の情報を抜き取ってやればいい，という方法を考えました。なおプレイヤー名の情報は評価値バー独自のオプションなので将棋エンジンには送らず，それ以外のオプション設定値は将棋エンジンに漏れなく送ってやる必要があります。以下は PlayerName という評価値バー独自のオプションを新設した場合のシーケンスです。

```mermaid
---
title: 評価値バー独自のオプションを設定する
---
sequenceDiagram
将棋 GUI ->> 評価値バー:usi
評価値バー ->> 将棋エンジン:usi
将棋エンジン ->> 評価値バー:option name *
将棋エンジン ->> 評価値バー:usiok
評価値バー ->> 将棋 GUI:option name *
opt
評価値バー -->> 将棋 GUI:option name PlayerName
end
評価値バー ->> 将棋 GUI:usiok
将棋 GUI ->> 評価値バー:setoption name *
opt
将棋 GUI -->> 評価値バー:setoption name PlayerName
end
評価値バー ->> 将棋エンジン:setoption name *
```
この方式は二つの課題があります。
* 将棋 GUI でプレイヤー名を二か所（対局設定とオプション）で入力するのが面倒。
* USI プロトコルでは半角英数字のみを規定しており，漢字を送れるかどうか怪しい。

ということで，(b)案も断念しました。

## (c)案：評価値バーでプレイヤー名を入力できるようにする
これも(b)案と同じく，入力が面倒だと思い断念しました。評価値の計算は将棋 GUI の検討モードを使用していると思いますが，検討を中断すると将棋エンジンの計算を止めるため，評価値バーも消えます。検討を再開したとき，もう一度プレイヤー名を入力し直さなくてはならないとしたら超面倒でしょう。ただ，評価値バーの親プロセスの ID とプレイヤー名を保存しておけば，再起動時に親プロセスの ID を確認することでプレイヤー名の再入力を省略できます。ただ，親プロセスの情報を取れるのなら次の方法のほうがずっと簡単です。

## (d)案：親ウィンドウのタイトルバー文字列を読み出す
ShogiGUI のウィンドウをよく見てみましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/c9e5a3e5-749d-ebbe-7595-47a06c35c689.png" alt="ShogiGUIの画面">

先手・後手のプレイヤー名を設定すると，ウィンドウのタイトルバー文字列に

<b>藤井聡太竜王名人 対 三枚堂達也七段 2023/06/19 11:01:53 - ShogiGUI</b>

と先手・後手，そして対局開始の日時が表示されています。この情報を読み出せばいい！ということに気づきました。※将棋所でも同じことができるかどうかは確認していません。

なお，この二人のプレイヤー名は評価値バーの画面サイズに収まりきるかどうか調べるため，長そうな名前の人を選びましたがちょっと選定が甘かったかもしれません。※カロリーナ・フォルタン女流二段だと溢れます。

# 評価値バーでの実装方法
評価値バーの起動時に以下の処理を呼び出します。
```C#
static	public	string	playerName1 = "先手";			// 先手プレイヤー名
static	public	string	playerName2 = "後手";			// 後手プレイヤー名

//--------------------------------------------------------------------------
// 先手・後手プレイヤー名の取得
//
// ・親プロセスのウィンドウのタイトルバー文字列より取得する
// ・親プロセスがプレイヤー名を設定していない場合は何もしない
// ・プレイヤー名（姓と名と段位）には空白を入れないこと
//--------------------------------------------------------------------------
static	void	GetPlayersName() {
	Process	proc = Process.GetCurrentProcess();
	string	query = string.Format( "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {0}", proc.Id );
	var		search = new ManagementObjectSearcher( "root\\CIMV2", query );
	var		collect = search.Get();
	var		element = collect.GetEnumerator();
	if( !element.MoveNext() ) return;

	var		result = element.Current;
	int		id = (int)(uint)result["ParentProcessId"];
	Process	parent = Process.GetProcessById( id );
	string	title = parent.MainWindowTitle;
	Match	match = Regex.Match( title, @"(\S+) 対 (\S+)" );
	if( !match.Success ) return;

	playerName1 = match.Groups[1].Value;
	playerName2 = match.Groups[2].Value;
}
```

なお，下記サイトの情報が大変参考になりました。
[【C#】親プロセスの情報を取得する - Tumbling Dice（はてなブログ）](https://outofmem.hatenablog.com/entry/2013/11/01/104718)


長くなり過ぎたので次回に続きます。

https://qiita.com/TETSURO1999/items/e708393013b9da575235