第22回世界コンピュータ将棋選手権出場記

■はじまりから直前まで プログラムの話

 第21回大会の時点で、ライブラリ使用はほとんどがBonanzaになっていた。しかし、白砂は今年度もれさぴょんを使おう、と決めていた。理由は単純で、Cのソースに手が出せるほどプログラムに精通しているわけではないことと、あと、これが一番大きいのだが、2次進出のライブラリ制限に引っかかると思ったからである。同じBonanza使いであれば負ける自信があった。そんな自信を持ってどうする、という話ではあるのだが。
 というわけでれさぴょんを使うことは決めていたのだが、現実問題としてれさぴょんはBonanzaに比べるとかなり遅い(と思う)。なので、深くたくさん読ませるための手段をどうしようと考えていた。
 幸い、Sunfishsimkなど、ソースを公開していらっしゃる方がいたので、うまいことパクれないか(をい)とソースを読み込んでいろいろ研究してみた。指し手のオーダリングをちゃんとしたり、NullMoveやFutilityCutなども入れた方がいいのかなぁ……と、この時はまぁいろいろ構想だけは練っていて、こういう時がある意味一番楽しい時期なんでしょうね。

 ところが、仕事の方はH23.10をピークに忙しく(9月議会で条例改正を上程したため)、加えて年が明けてからはプライベートでも大変忙しくなってしまい、全然プログラミングをする余裕がなかった。いや、時間はあったのだが、精神的にそういうことをできる環境になかった。そうしてのんべんだらりと過ごしているうちに年度が明け、同じ職場にもう4年もいるんだしそろそろ異動だよな……と思っていたら異動もなく(笑)、それでも業務内容は新しくなったりしているうちに、とうとうGWに突入してしまった。

■4月28日

 いいかげんちゃんとやらないと……ということで、「娘(狼)」から離れる(をい)。
 基本的には前年と一緒で、DLLをK-shogiで動かせばいいよなぁ。そういえば3月終わりにHDDがイッてOSを7に入れ替えたから(実話)、コンパイラもインストールしなくちゃいけない。
 てことで例によってBCCをDLして、インストールを……
このOSにはインストールできません
なんですとぉ!?

 さすがにコンパイラが古すぎた。Borland好きだったのに……orz。
 ここで意地を張ってTurboC++という手もないわけではないけれども、そこまでしなくてもいいだろうと考えてVC++2010をインストールした。本音を言うと、れさぴょんは公式にはBCCとVC++対応なので、余計なことを考えずにもう一択の選択枝を選んだだけなのだが。

 せっかくVCにしたので、せっかくだったらGUIは将棋所にしようか、と考えた。連続対戦なんかもできるらしいし、読み筋のグラフ表示とかも出るみたいだし(これはK-shogiでもできる)。
 というわけで、将棋所に対応するべく、今までのDLL版を捨てて1から作成することにした。

 とはいっても、IO関係はLesserKaiを参考にできたので、対応そのものはすぐにできた。
 そのあと、れさぴょんについて公開されているバグ取りをいくつか。
 たとえば、http://lesserpyon.bbs.coocan.jp/?m=listthread&t_id=25にある、pin判定のバグ。
void Kyokumen::MakePinInf(int *pin) const
{
	int i;// ピン情報を設定する
	for (i = 0x11; i <= 0x99; i++) { // 0はピンされていない、という意味
		pin[i] = 0;
	}
	if (kingS) { //自玉が盤面にある時のみ有効
		for (i = 0; i < 8; i++) {
			int p;
			p = search(kingS, -Direct[i]);
			if ((ban[p] != WALL) && !(ban[p] & ENEMY)) { //味方の駒が有る ←ここの部分
				if (controlE[p]&(1<<(16+i))) {
					pin[p]=Direct[i];
				}
			}
		}
	}
	……
}
「味方の駒」なんだからここはENEMYではなくSELFのはず。
 というわけでSELFに修正。
 その他、時間による読みの打ち切りなども以前のソースから持ってくる。
 ここまでやったところで、念のためLesserKaiと対戦させて様子を見る。

……バグってるorz

 第1図がその局面。
 この局面で▲7七桂と指し、△同角成に▲8四玉と訳のわからない手を指して反則負けしている(「*Illegal move 8e8d」と出てる)。何故だ……orz。

 賢明な方はもうおわかりだろう。
 さきほど、pin判定のところで、味方の駒なんだからとENEMYをSELFに変えた。変更したソースがこれ。
void Kyokumen::MakePinInf(int *pin) const
{
	int i;// ピン情報を設定する
	for (i = 0x11; i <= 0x99; i++) { // 0はピンされていない、という意味
		pin[i] = 0;
	}
	if (kingS) { //自玉が盤面にある時のみ有効
		for (i = 0; i < 8; i++) {
			int p;
			p = search(kingS, -Direct[i]);
//			↓hakusa 20120428修正
//			http://lesserpyon.bbs.coocan.jp/?m=listthread&t_id=25
//			if ((ban[p] != WALL) && !(ban[p] & ENEMY)) { //味方の駒が有る
			if ((ban[p] != WALL) && !(ban[p] & SELF)) { //味方の駒が有る
//			↑hakusa 20120428修正
				if (controlE[p]&(1<<(16+i))) {
					pin[p]=Direct[i];
				}
			}
		}
	}
	……
}

「味方の駒である」にしたいんだから、
×if ((ban[p] != WALL) && !(ban[p] & SELF)){   ←これだと「味方の駒じゃない」になっちゃう
○if ((ban[p] != WALL) && (ban[p] & SELF)) {   ←これが「味方の駒である」
 にしないといけなかった。うぅ……(泣)
 ここを修正したらちゃんと動いた。
 あんまりバカバカしい間違いにやる気が失せて、というか実はこれだと判るのに1時間近くかかってしまい疲れてしまったので、ここで終了した。

■4月29日

 MakeOuteを自前のものにする(れさぴょんでは、合法手生成をしたあと、王手がかかっているものを王手、としているから遅い)。
 これは以前から作っていたものなので、Makeoute.cppをプロジェクトに入れてコンパイル。それだけ。楽勝じゃn……
1>d:\project\2012\hshogi\makeoute.cpp(1317): fatal error C1010: プリコンパイル ヘッダーを検索中に不明な EOF が見つかりました。'#include "StdAfx.h"' をソースに追加しましたか?
なにこれ!?

 VC++だとこんなのが必要なのか。←ホントになんにも知らない
 まぁ、わかったからいいや、ということでStdAfx.hをソースに追加してコンパイル。今度は無事通過した。
 よし、じゃあ詰将棋を解かせてホントに速度が上がったかテストしてみよう……ということで問題を盤に並べて解図させてみる。将棋所はこういうところが便利だ。

バグ発生。

なんか詰まさない。

 判らないので、とりあえずprint文を乱発して調べてみたら、

<1:Hash:7fc3144bff4d1104 Hand:6a3331d33105d2c4 Kyokumen:15f02598ce48c3c0
<1:Mochigoma:角02金03銀桂02香03歩15
<1:  09 08 07 06 05 04 03 02 01 
<1:+---------------------------+
<1:| ・ ・ ・v飛 ・ ・ 全 ・v王|01
<1:| ・ ・ ・ ・ 龍 ・ ・ ・v香|02
<1:| ・ ・ ・ ・ ・v銀v銀v歩v歩|03
<1:| ・ ・ ・ ・ ・ ・v歩 ・ ・|04
<1:| ・ ・ ・ ・ ・ ・ ・ ・ ・|05
<1:| ・ ・ ・ ・ ・ ・ ・ ・ ・|06
<1:| ・ ・ ・ ・ ・ ・ ・ ・ ・|07
<1:| ・ ・ ・ ・ ・ ・ ・ ・ ・|08
<1:| ・ ・ ・ ・ ・ ・ ・ ・ ・|09
<1:+---------------------------+
<1:Mochigoma:金桂02
<1:num:1
<1:11 壁打  ←←←←←←←←←←!!!!!!!!!!

11壁打ってなんだよorz。

 自前の王手生成を入れた結果こんなことになったんだから、単純に考えれば自前の王手生成がおかしいはず。そう考えてどこがおかしいのかソースをチェックしたのだがどうしても判らない。
 更にprint文を乱発してみたところ、なぜかAntiCheckに入ってしまっていた。
	// 王手されていたら、それを受けないとしかたない。
	if (SorE==SELF && controlE[kingS]!=0) {
		printf("s-anti\n");←←←←←←←←←←←←←←←←←←←←ここ
		return AntiCheck(SorE,teBuf,pin,controlE[kingS]);
	}

 なんでだ!?
 これはもう、自前のソースとかいう問題じゃないんじゃあ……。

 本当に判らなかったので、仕方なくサンプルでちゃんと動作しているLesserKaiのソースを見てみた。
int Kyokumen::MakeLegalMoves(int SorE,Te *teBuf,int *pin)
{
	int pbuf[16*11];
	int teNum=0;
	if (pin==NULL) {
		MakePinInf(pbuf);
		pin=pbuf;
	}
	//if (SorE==SELF && controlE[kingS]!=0) {
	//	return AntiCheck(SorE,teBuf,pin,controlE[kingS]);
	//}
	//if (SorE==ENEMY && controlS[kingE]!=0) {
	//	return AntiCheck(SorE,teBuf,pin,controlS[kingE]);
	//}
	↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓これ
	if (SorE==SELF && kingS != 0 && controlE[kingS]!=0) {
		// 先手玉があるかどうかという条件を追加。(詰将棋などで先手玉がないなら入らない)
		return AntiCheck(SorE,teBuf,pin,controlE[kingS]);
	}
	if (SorE==ENEMY && kingE != 0 && controlS[kingE]!=0) {
		// 後手玉があるかどうかという条件を追加。(詰将棋などで後手玉がないなら入らない)
		return AntiCheck(SorE,teBuf,pin,controlS[kingE]);
	}

 なるほど。
 CSA将棋では詰将棋ができなかったけど、将棋所では詰将棋ができる。そのため、「盤上に玉があるか」をチェックしないといけないというわけだ。
 ここを直したら「11壁」はなくなった。

 ついでに、ひとつ賢くなったこと。
 VC++には、itoaという関数(?)が用意されていて、2進数をそのまま表示できる。
 文字列を用意しておいて、int型の変数を○進数の文字列に変換、とできる。

char b_str[50];
itoa(controlE[kingS], b_str, 2);  ←controlE[kingS]を2進数に変換してb_strに代入する
printf("controlE[kingS]:%s  ",b_str);

 バグ取りのときに利きのチェックまでしちゃったので、こんな知恵がついた(泣)。

 しかし、「11壁」はなくなったものの、まだ詰まさない。
 なにがおかしいんだろう……。

 原因がわかった。
 自前のMakeOuteで、王手生成が足りなかった。

 第2図の局面で、▲4一龍とか▲6一龍が生成されていなかった。
 調べてみると……、

// 龍がこの筋に乗れるか?(乗れたら王手になる)
chkSRYyori(to,1,outeNum,teBuf,pin);
chkSRYyori(to,3,outeNum,teBuf,pin);
chkSRYyori(to,4,outeNum,teBuf,pin);
chkSRYyori(to,6,outeNum,teBuf,pin);

これ、0257だろー!!!!!!!

 単純なtypoだったかorz。

■4月30日


 なんとかちゃんと動作するようになったので、LesserKai相手にスパーリング。
 しかし、なんかおかしい。

 第3図で、最善手が▲2三歩△8四歩▲7六歩(!)としている。
 なぜ▲2二歩成としない……orz。
 こういうのを調べるためにも、あと、ログを残しておくためにも、ファイルにログを出力できるようにする。
 そして「検討(▲2三歩△8四歩と進めた局面で)」をさせてみて(こういうところ本当に将棋所は便利だ)、ログを見てみる。
k.EvaluateTe(SorE,teNum,teBuf);
for(i=0;i<teNum;i++) {
	printf("  v0:%3d:%7d ",i,teBuf[i].value);
	teBuf[i].Print2();
	printf("\n");
	if (teBuf[i].value<-3000 && i>0 && retval>-INFINITEVAL) {
		break;
	}
……
このタイミングでログを出してみると……
<1:  v0:  0:      3 68王(59) 
<1:  v0:  1:      3 58金(49) 
<1:  v0:  2:      1 46歩(47) 
<1:  v0:  3:      1 76歩(77) 
<1:  v0:  4:      1 96歩(97) 
<1:  v0:  5:      1 69王(59) 
<1:  v0:  6:      1 16歩(17) 
<1:  v0:  7:      1 56歩(57) 
<1:  v0:  8:      1 66歩(67) 
<1:  v0:  9:      1 86歩(87) 
<1:  v0: 10:      1 36歩(37) 
<1:  v0: 11:      0 28銀(39) 
<1:  v0: 12:      0 38銀(39) 
<1:  v0: 13:      0 48銀(39) 
<1:  v0: 14:      0 68銀(79) 
<1:  v0: 15:     -1 18香(19) 
<1:  v0: 16:     -1 98香(99) 
<1:  v0: 17:     -3 58王(59) 
<1:  v0: 18:     -3 48王(59) 
<1:  v0: 19:    -10 48金(49) 
<1:  v0: 20:    -10 38金(49) 
<1:  v0: 21:    -20 68金(78) 
<1:  v0: 22:   -180 28飛(24) 
<1:  v0: 23:   -180 25飛(24) 
<1:  v0: 24:   -180 26飛(24) 
<1:  v0: 25:   -185 27飛(24) 
<1:  v0: 26:  -1382 22歩(23)  ←←←
<1:  v0: 27:  -1944 22歩成(23) ←←←
<1:  v0: 28:  -2399 84飛(24)  ←←←
<1:  v0: 29:  -4100 54飛(24)  ←←←

 角が取れているのになぜか▲2二歩が低く評価されている。
 ただし、その下に▲8四飛とか▲5四飛とか、タダで飛車を捨てている手については、それはそれでをちゃんと低く評価している。
 ……てことは、「駒を取ったプラス手」を評価できてないということか? いやそんなバカな……。

 今度はEvaluteTeの内部を表示してみる。
<1:16歩(17) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:18香(19) val:   -1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:22歩成(23)val:-1944 LossS: 3355 LossE: 4455 GainS:-5670 GainE:    0 ←
<1:22歩(23) val:-1382 LossS: 2255 LossE: 2535 GainS:-4570 GainE:    0 ←
<1:25飛(24) val: -180 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:26飛(24) val: -180 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:27飛(24) val: -185 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:28飛(24) val: -180 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:14飛(24) val:-4100 LossS: 4100 LossE:    0 GainS:    0 GainE:    0
<1:34飛(24) val:-4100 LossS: 4100 LossE:    0 GainS:    0 GainE:    0
<1:44飛(24) val:-4100 LossS: 4100 LossE:    0 GainS:    0 GainE:    0
<1:54飛(24) val:-4100 LossS: 4100 LossE:    0 GainS:    0 GainE:    0
<1:64飛(24) val:-4100 LossS: 4100 LossE:    0 GainS:    0 GainE:    0
<1:74飛(24) val:-4100 LossS: 4100 LossE:    0 GainS:    0 GainE:    0
<1:84飛(24) val:-2399 LossS: 4100 LossE:  -50 GainS:    0 GainE:    0
<1:36歩(37) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:38銀(39) val:    0 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:28銀(39) val:    0 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:48銀(39) val:    0 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:46歩(47) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:48金(49) val:  -10 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:38金(49) val:  -10 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:58金(49) val:    3 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:56歩(57) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:48王(59) val:   -3 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:58王(59) val:   -3 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:68王(59) val:    3 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:69王(59) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:66歩(67) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:76歩(77) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:68金(78) val:  -20 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:68銀(79) val:    0 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:86歩(87) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:96歩(97) val:    1 LossS:    0 LossE:    0 GainS:    0 GainE:    0
<1:98香(99) val:   -1 LossS:    0 LossE:    0 GainS:    0 GainE:    0

角を「取って」いるのにマイナスってどーいうことよ。

<1:22歩成(23)nowEval:  186 newEval: 5322 val:-1944 LossS: 3355 n1:    0 n2: 3355 LossE: 4455 GainS:-5670 GainE:    0
<1:22歩(23) nowEval:  186 newEval: 3876 val:-1382 LossS: 2255 n1:    0 n2: 2255 LossE: 2535 GainS:-4570 GainE:    0
というかLossSがもうダメみたいだ。
if (te[i].from!=0) {
	// 駒が居た場所の脅威がなくなる
	LossS-=Eval(te[i].from); ←←←←←←←←←ここがn1
}
// 新しく移動した先での脅威が加わる
LossS+=_new.Eval(te[i].to); ←←←←←←←←ここがn2
ちなみにn1とn2っていうのはここのこと。

 うーん……。

 改めて状況を整理する。
 ▲2二歩(23)の局面が第4図。

 ここで22の交換値は、
 としてほしいはず。

 しかし、さきほどのn2(新しく移動した先での脅威が加わる)の評価値を見ると、2255となっている。これは、

 先手        後手
 飛を取られた-2000  飛を取った -2100
 歩を取られた -100  歩を取った  -105
 銀を取った +1050  銀を取られた+1000
---------------------------------------------
 計     -1050  計     -1205 総計 -2255

 と一致する。さきほど交換値の算出方法を言葉で書いたが、それで言えば、
 となってしまっているわけだ。
 まさかEvalがおかしいの……?

 今度はEvalを調査。
 ところが。

 またまたprint文を乱発して(ブレークポイントとかそういうのは使わない(笑))いろいろ調べている途中、

return max(v,
	EvalMin(AtackS+1,NumAtackS-1,AtackE,NumAtackE));

 この部分のそれぞれの値が知りたくて、こんな風に分けて書いてみた。

	int h1=EvalMin(AtackS+1,NumAtackS-1,AtackE,NumAtackE);
	int h2=max(v,h1);
	return h2;

 すると、どういうわけか値がまともになっている。▲2二歩成のときは。他の局面でちゃんと出るかどうかまでは不明だが。
 試しに1局指させてみたが、そんな変な手は指さない。

 後日、この原稿を書くためにこのときの「まともな評価値」のログを探してみたのだが、残念ながら見つからなかった。ログファイルを同一名にしていたため、不注意にも上書きしてしまったものと思われる。バカバカしい単純ミスではあるが、一つ弁解させていただくと、文章で書くと短いがこのことを発見するまでにかなり時間を喰っていて、実はこれが判った時には時刻は次の日になっていた。そのため注意力散漫になっていたのだろう。
 とりあえず、副作用があるのかもしれないがこの部分は分け書きでいく、ということにして、ディスプレイの電源を切った。

■5月1日

 前日までの分に、昔作っていた関数のいくつかを上乗せした。
 現状のプログラムはかなり遅いので、重いものは外して軽いものだけにした。

 指し始めにいくつか情報(現在の終盤度など)を表示するようにした。
 やっぱり指し手の履歴がないとまずいので、履歴作成。
 家での開発はここまで。明日に備えて早めに寝た。

■はじまりから直前まで プログラム以外の話

 ちょっと話を戻して、今度はプログラム以外の話を。
 一昨年は調布までレンタカーを借りて行ったのだが、調べてみたら実は自宅から90分で調布駅まで着くことが判ったので、今年は電車で行くことにした。どうせ出場はノートパソコンだし、多少荷物は重いがなんとかなるだろう、という読みである。そのノートパソコンは昨年と同じACERのASPIRE 3820-A52C。Core i5-460M(2.53GHz)、メモリ8GB、重さは1.8kgである。
 あと、LANケーブルは以前買ったような巻取り式のものを購入した。いろいろ探したのだが、5mの巻き取り式ケーブルはこれしか見当たらなかった。
 また、白砂はノドが弱いので、携帯用の加湿器も持っていくことにした。器、とはいっても、こういう水分を紙に吸い取らせて加湿するタイプのものである。
 それから、どうでもいい話だが白砂は飲み物をよく飲む。一日4リットルは飲んでいる。平日だと、職場では家からSodaStreamで作った炭酸を持っていって1リットルボトル2本半くらい飲んでいて、家でもかなり飲むのでそれくらいになってしまうのだ。以前はいろいろなものを飲んでいたのだが、ここ1年くらいは炭酸水一本である。飲み始めてからしばらくして炭酸健康法がマスコミで紹介されて、ネットショップなどの相場が軒並み上がってしまいショックを受けたこともあった。
 で、白砂は飲み物をよく飲むのだが、そのたんびに外に買いに出ていたのでは面倒くさい。ということで、朝に大量に飲み物を買い込んで、それをうまいこと冷やしながら飲めばいいんじゃなかろうか、と考え、このUSB冷却器マグカップを買った。いや、よっぽど小さい冷蔵庫でも持っていってやろうかと思ったのだが(笑)、さすがにそこまでは重いし面倒かなと。
 そんなこんなで少しだけ大荷物になってしまったが、結局のところ、着替えその他を入れた大きいバッグが一つと、PCを運ぶ肩掛けカバンだけで足りた。これだったら電車移動もさほど苦ではないはずだ。

 ホテルは一昨年と同じホテル・ツインズ調布。Webの事前予約だと6,900円になるということだったのでここにした。電通大の傍にホテルがあればいいんだけどね……。
 当日のスケジュールは、2時に最寄り駅に着き、電車で調布へ。そのあとすぐにLAN接続テストをして、ホテルで序盤定跡の辺りを導入して、あとはゆっくり寝る、というものだった。5月2日の夕食と5月3日の朝食、それと昼食はWebを漁ってアタリをつけていた。ちなみに、どうせ2次予選には進めないだろうから、夕食は食べずにそのまま帰る。

 5月2日は家を1時40分に出た。小田急線−京王線と乗り継いで調布まで。GWとはいえ一応平日の昼間だったこともあってか、全て座って移動できた。荷物も網棚に置いていたので全然気にならない。今後選手権が調布で開催される場合にはこのルートで問題なさそうだ。
 ただ、天気が雨だったことだけが痛かった。荷物を2つ持ってカサをさすというのはかなり大変だ。
 3時ちょっと過ぎに調布について、すぐにチェックイン。荷物を置くと、PC関連一式だけを持ってすぐにLAN接続チェックに出かけた。
 もうかなりの人数がいらしていて、机は1つしか空いていなかった。そこに座ってPCを広げてサーバに接続。
「すいません、Windows7でIPアドレスの変更ってどうやるんでしょうか?」
 隣の椿原将棋の方が質問してこられたので、設定方法を教えた。ちなみに、そのあと自信がなくなってなのはさんに訊いたのは内緒だ(笑)。ありがとーなのはさん。
 Q&Aの縁で、というわけではないのだが、せっかくなのでそのまま椿原将棋と対戦した。なんとかちゃんと動作はすることを確認した。
 そのあと、例の「なのは開始画面」を見たり(盤が出てくるまでが長ぇよ(笑))して、会場を後にした。

 帰りに買い出し。
 今日の夜のホテルと明日の会場で飲み食いする食料・飲料(GEROLSTEINERを10本とコーラゼロの1.5リットルを2本)を駅前の西友で購入。
 部屋に戻って持ってきた加湿器をセットし、浴槽に熱湯を貯めバスルームの扉を開け放って、プログラム開始である。

■はじまりから直前まで もう一度プログラムの話

■5月2日

 今までやっていた。勝手読み定跡等を入れる。

 ……実行すると対局中に落ちる。
 いろいろ調べたのだが、どうしてもわからない。

 こういう時はいったんプログラミングから離れるといい。そうだそうだそうしよう、というわけで、雨が降りしきる中、事前に目をつけておいた店に行って夕飯。

これ

 なんで珍しく写真があるかというと、嫌がらせに家で待つ妻に送ったから(爆)
 プログラミング? なんだっけそれ、おいしいの?

 樽生ギネスをゆっくり堪能しようと思ったのに、5月2日はFC東京とかいうサッカーチームの試合が入っていやがって、とはいってもそれ目当ての客は2組10人くらいだったのだが、それでもうるさくなりそうなので早々にホテルに引き上げてきた。実は1パイント3杯呑んだなんてナイショ。さて、プログラミングだ。

 とはいうものの、どういうわけか(<ウソです。理由は明らかです)先へ進まない。

 勝手読み定跡とは、以前の説明の繰り返しになるが「自分の指したい指し手だけ」の定跡を持っていて、それが指せれば指す、というもの。かなり乱暴な仕組みだが、7七桂戦法や3二金戦法は「形」があってそれは読みでどうこうなるレベルではないので、こうするのが一番いいのだ。ただ、なんでも指しちゃうと大損する可能性もあるので、事前に仮読みをして損にならなければ指す、という風にしている。
 で、print文を乱発して調べてみた結果、こっちは正しく(?)指し手を返すのだが、そのあとのメインループでこっちが指したと認識してくれずに相手の手番とみなされてしまうらしいことが判った。なんだかよく判らない日本語だが、指し手はちゃんと送ってるのに「次の番」の指し手をうまく受け取れてくれないらしい。

 12時頃まで粘っていたのだが、どうしても判らない。
 もう無理と判断し、勝手読み定跡等の導入は諦めた。
 というわけで、今年度の白砂将棋は、定跡を外れるとすぐに思考ルーチンに入るヘタレプログラムになってしまった。
 序盤だと思考時間を少なくするとか、せめてそういうのだけでも入れられればよかったのだが、考える余裕がなかった。それよりなにより、定跡から外れたら思考ルーチンに入るということは、「とりあえず7七桂戦法にしてこちらの理想形を作っておいて、あとは玉が固いからなんとかなるだろ」という将棋が指せないことを意味する。これは白砂将棋にとって大いに不利(7七桂戦法を選択する有利さがなくなるという点で)だ。
 このとき、7七桂戦法や3二金戦法を諦めて普通の定跡で勝負しようかとも考えた。
 が、そもそも白砂将棋のコンセプトは「白砂の分身」だったはず。ならば、目先の勝ち負けよりも「らしさ」を追求すべきだ。
 そう考えて、不利は受け入れて勝負することにした。

というかちゃんとプログラムすればいいだけなんだが……(泣)

■はじまりから直前まで 再びプログラム以外の話

 起きたのは8時半くらいだった。やはり繊細な白砂はなかなか寝られず、結局うとうとしたくらいで朝になってしまった。やっぱり空気が変わると寝られない(泣)。
 換気がてら窓を開けると、前日からの雨はまだ降っていた。
 眠気覚ましにシャワーを浴びて、GEROLSTEINERを1本飲んで、スッキリしたところで仕度をしてチェックアウトした。
 事前調査では、方向が反対になるけど駅の向こう側でモーニングを出す喫茶店があるとのことだったのでそっちに行こうかと思っていたのだが、雨なんでそんな根性は出なかった。で、結局、電通大へ向かう途中のドトールで朝食を摂った。この時期とにかく雨がすごく、イスから立ち上がるのにかなり精神力を使ってしまった。
 受付時間はほぼギリギリ。普段はせっかちで時間前行動が基本な白砂だが、どうせ開会式やらいろいろあるのはわかっていたし、そもそもノートPCなんで準備は2分もあれば終わるので大丈夫だと思っていた。案の定、というわけではないが、セッティングにトラブルがあったのか、なかなか開会式が始まらない。

やっぱ黒い黒帯のセンセイにシメてもらわないとダメだな

 開会式がまだだったので、トイレに行ってもう一度顔を洗って目を覚ましてから、「喫茶コーナー」を見てみた。そんな大げさなものではなくて、入口横にあった、ポットやらインスタントコーヒーやらジュースなどが置いてあるコーナーのことである。なんか飲もうかと思ったのだが、冷たいのがないのでやめた。ついでにカンパ箱に100円を置いといた。「いい? ある程度お金がはいってないと誰も入れてくれないものなのよ」(もっとも、良識ある方々ばかりだったようで、昼過ぎに見たときはちゃんとたくさん入ってました)。
 ちょっとだけ遅れて開会式が始まり、各種あいさつ、まったりゆうちゃんの10回参加表彰、ルール説明と進んだ。
「この部屋(会場)は基本的に飲食禁止です。ペットボトル等以外の飲食は別室で行ってください」
 USB冷却機とマグカップはタダの荷物になりましたorz。

 


初版公開:2012年6月11日
copyright © S.Hakusa