ただスクラッチ開発なだけの将棋ソフトってそんなに偉いんですか?
コンピュータ将棋界隈の一部には紛うことなく一つの信仰が存在する。
世界コンピュータ将棋選手権には近年フロムスクラッチ表彰が導入された*2し、第28回世界コンピュータ将棋選手権ではライブラリ使用の参加者とライブラリ不使用の参加者に一悶着あった*3ことからも、スクラッチ開発信仰が存在することは明らかである。
フルスクラッチ/フロムスクラッチ開発って何?
一般的には既存のパッケージを用いない開発をスクラッチ開発、あるいはフルスクラッチで開発するなどというのだが、コンピュータ将棋界隈における「フルスクラッチ」あるいは「フロムスクラッチ」と呼称される開発方式は少々趣が異なるようである。
Stockfishという超強豪のオープンソースチェスエンジンの構造をほぼそのまま流用し、せいぜいそこに駒打ちの処理を書き、駒の種類、指し手生成、ビッドボード、プロトコルと評価関数を将棋用にしたくらいのプログラム*4、さらに言えばStockfishのコメントがそのまま残っていたりするレベルの将棋ソフトがコンピュータ将棋界隈ではフルスクラッチになるのである。Stockfishをベースとしたソフトウェアのアピール文書に「フルスクラッチ」と書かれていたりするし、実際にそれらのソフトがフロムスクラッチ表彰を受けていたりするので、間違いない。
つまりコンピュータ将棋界隈におけるフルスクラッチとは、他の将棋ソフトをコピペしてないですよ、くらいの意味である。上にも書いたとおりチェスソフトのコピペはOKである。
もちろん、チェスエンジンのコードの流用もせずに書き上げられた将棋プログラムも存在するし、そちらのほうが多数派でもある。
フルスクラッチ至上主義
そしてこの「フルスクラッチ」*5こそが至高であると考えるコンピュータ将棋参加者が一定数存在し、ライブラリ使用の参加者が「ライブラリを使わないでコードを書くのは面倒」と発言しただけで、ライブラリ不使用の参加者が「正気を疑う。その程度のやる気しかない人に選手権に参加されるのは不愉快」と強い怒りを顕にしたこともある。
これを受けてコンピュータ将棋界隈でフルスクラッチ論争が巻き起こり、フルスクラッチを他人に強要するのはよくないけど、フルスクラッチ開発はとっても難しいしとっても偉い!誇りに思っていいことだ!という結論に落ち着いたようだった。
ただフルスクラッチなだけのソフトの何が偉いんですか?
しかし私は思うのである。スクラッチ開発は著作権やライセンスの問題に対応するため、あるいは教育的目的のために行うといった、ただの開発手法の一つであって、そこに偉いも何もないだろうと。
おまけにである。多くのフルスクラッチの将棋プログラムには何一つアイディア的な新規性がないのである。既存の将棋プログラムの手法のうち一部のこれこれを自分でがんばって(ボナンザややねうら王から性能を大幅に低下させて)実装しましたといった具合に。完全に新規性・独自性とただの苦労を履き違えているようにしか見えない。
フルスクラッチを標榜するソフトの多くが、「本当にただフルスクラッチなだけ」*6のソフトである。
そもそもが、ただルール通り指せるだけの将棋ソフトを作るだけのことがそんなに難しいなどということがあるだろうか? *7
ただフルスクラッチなだけの将棋ソフトを作ることがそんなに難しいんですか?
というわけで、ただのフルスクラッチなだけの将棋ソフトを実際に自分で作ってみて、その難しさを体感してみることにした。以下時系列順に考えたこと、やったことを雑にまとめる。
ルール
将棋所*8で投了までルール通り指せるプログラムを作る。できれば少しだけ思考させる。
他の将棋・チェスプログラムのソースコードを見ない、使わない。ブログなどはソースコードが書かれた部分を見るのは禁止。手法を解説した部分はOK。
事前準備
名前を決める。フロムスクラッチだから適当にFSshogiに。
将棋所と将棋エンジンの通信プロトコルがわからないといけない。「将棋所 プロトコル」でググるとUSIという名前であることがわかる。
USIでググるとQiitaの記事が見つかる。将棋の局面はsfenという形式で読むらしいことがわかる。
実装(一日目)
夕方から始める。
まずは駒の定義が必要だから書く。名前を決める。sfen形式が歩をpawn、香車をlance、桂馬をknight、銀をsilver、金をgold、飛車をrook、角をbishop、王をkingとしてるから安直にそれにする。成りとかもある。駒を成らせるpromotion関数とかも書く。
つぎに局面のクラスを書かねばならない。盤は9x9の配列で持つ。先手後手の手駒を持つ。
そしたら試しにsfen文字列をプログラムに読み込んで局面に変換して、そのまま局面をsfen文字列に再変換して出力させてみる。動く。正しく同じものが再出力されている。
そしたら次に将棋の指し手を作る。ルールはどんな感じだっけ?駒を動かした後で王手になっていてはダメ。一段目の歩、香車がいたらダメ。二段目に桂馬がいたらダメ。あとなんかあるっけ?とりあえずそれで書く。駒を動かす関数も必要なので書く。
初期局面から指し手を生成してみる。30通り。駒の動きはあってそう。一局面で将棋の指し手って最大何手あるんだ?「将棋 合法手 最大」などでググると593らしい。合法手が最大になる局面で合法手を生成してみる。なんか合わない。
sfenの読み方をミスってた。Qiitaの記事だと持ち駒の表記が"駒の種類+枚数"と書いてあるが別の解説記事だと"枚数+駒の種類"じゃん。直す。593通りと出た。
ここらで夕飯を作る時間になったので終了。夕飯後は別の用事。
実装(二日目朝)
朝から開始。
昨日二歩と打ち歩詰めを忘れてたことに気づいたので追加。
別のQiitaの記事いわく合法手593手の局面から2手進めると105677通りになるらしい。合わない。初期局面から三手進めると25470通りになるらしい。合わない。半分くらいになる。
先手30C2通り*後手30通りで13000くらいになると思うんだが。どうやらこの数え方は合流して同一局面数になるものを一つと数えず、それぞれ別に数えていそう。そう書くと一致。
初期局面から5手まで進めると19861490通り。一致。最多局面から2手進めると105677通り。一致。3手進めると53393368通りで一致。指し手生成は大体あってんだろうからこの辺にする。
千日手は今回は実装しなくていいや。
この辺で3時間くらい経ち昼過ぎになったのでしばらく外出。帰宅して再開。
実装(二日目夕方)
次にプロトコル部分を書く。
usiだとかisreadyだとかそんなコマンドがあるらしいので実装していく。今回のところoptionとかはガン無視でよし。ルール通り指せればよい。
で、まずは指し手はなし。即投了するようにする。
将棋所で読ませると対局開始できた。歩をついただけで相手が即投了し先手の勝ち。
次に合法手からランダムに一個選ぶようにして対局。相手がきふわらべのような手を指してくる。
途中で対局が止まる。出力ミスってたようなので直す。
また対局が途中で止まる。エンジンに止まった局面のsfenを食わせてデバッグしてみる。持ち駒を打つと落ちるようだ。
Qiitaの記事のsfenフォーマットの持ち駒を打つ場合の説明が間違ってる。先手の場合駒を大文字、後手の場合小文字で書きますとかあるが、別の解説だと常に大文字とある。このQiitaの記事間違い多いな!!
それを直すと投了まで普通に指せた。
ランダムに指し手を選ぶものをルール通り指す将棋プログラムと言い張るのはさすがにイヤなので思考部を少しだけまともにする。
評価関数を作る。歩は100点、飛車は1200点みたいにすごく適当に点数をつける。持ち駒になったらちょっと点数を高くしておく。できた。
そしたら探索。枝刈りはベータカットだけの単純なアルファベータ探索を書けばよい。
5手読みとかで。あ、遅すぎてだめだ……4手読みで*9大体5秒以内に指す。
というわけで完成。何度か指してみても普通に動く。
足掛け二日、総作業時間は9時間くらいか。
まとめ
合法手生成が面倒だった。通信プロトコルの嘘解説記事のせいで少しデバッグに時間がかかった。手間なだけで何が難しいのか理解できなかった。ただフルスクラッチなだけの将棋プログラムの何が偉いのか一切理解できなかった。*10なので、来週の週末にでも自分に勝てるくらいまでには強くしてみる。初段くらいあれば十分か。
私事だが自宅で使ってるマシンが古すぎてVisual Studioさえカクついてまともに動かなかったので全部テキストエディタでコード書いた。いい加減買い換えるべき。
おまけ
ランダムプレイヤーのFSshogiと深さ4*11アルファベータ探索のFSshogiを対局させてみた。
# Generated by Shogidokoro
手合割:平手
先手:fs_shogi_random
後手:fs_shogi_depth4
手数----指手---------消費時間--
1 9六歩(97) (00:01 / 00:00:01)
2 9二香(91) (00:01 / 00:00:01)
3 9七角(88) (00:01 / 00:00:02)
4 6二銀(71) (00:01 / 00:00:02)
5 9五歩(96) (00:01 / 00:00:03)
6 7一金(61) (00:01 / 00:00:03)
7 8六角(97) (00:01 / 00:00:04)
8 5二金(41) (00:01 / 00:00:04)
9 7五角(86) (00:01 / 00:00:05)
10 2四歩(23) (00:01 / 00:00:05)
11 6六角(75) (00:01 / 00:00:06)
12 1二香(11) (00:01 / 00:00:06)
13 8六歩(87) (00:01 / 00:00:07)
14 1四歩(13) (00:01 / 00:00:07)
15 8五歩(86) (00:01 / 00:00:08)
16 4二玉(51) (00:01 / 00:00:08)
17 7五角(66) (00:01 / 00:00:09)
18 9四歩(93) (00:01 / 00:00:09)
19 同 歩(95) (00:01 / 00:00:10)
20 同 香(92) (00:01 / 00:00:10)
21 同 香(99) (00:04 / 00:00:14)
22 4四歩(43) (00:01 / 00:00:11)
23 9三香成(94) (00:02 / 00:00:16)
24 1三香(12) (00:01 / 00:00:12)
25 8二成香(93) (00:01 / 00:00:17)
26 3二銀(31) (00:01 / 00:00:13)
27 8一成香(82) (00:04 / 00:00:21)
28 9一歩打 (00:01 / 00:00:14)
29 1二飛打 (00:07 / 00:00:28)
30 3一角(22) (00:01 / 00:00:15)
31 9一成香(81) (00:03 / 00:00:31)
32 8二金(71) (00:01 / 00:00:16)
33 2三桂打 (00:08 / 00:00:39)
34 8四歩(83) (00:01 / 00:00:17)
35 3一桂成(23) (00:02 / 00:00:41)
36 3四歩(33) (00:01 / 00:00:18)
37 3二飛成(12) (00:05 / 00:00:46)
38 5一玉(42) (00:01 / 00:00:19)
39 4一龍(32) (00:08 / 00:00:54)
40 投了 (00:01 / 00:00:20)
まで39手で先手の勝ち
アルファベータ版がきちんと相手玉を詰ませて終了。
*1:一般的な用語としては、スクラッチ開発とは既存のパッケージ等を使用せずにソフトウェアを開発することである。ただしコンピュータ将棋界隈では少し意味が異なるようである。後述。
*2:第29回世界コンピュータ将棋選手権より。ただし第29回では「ライブラリ不使用者表彰」であった。
*3:twitterやブログ等を観測すればわかるのだが、具体的出典を出すのは差し控えたい。
*4:一番実装が重い探索部は微調整だけがなされほぼそのまま流用される。スレッド周りや時間制御もほぼ流用である。
*5:コンピュータ将棋界隈における独自の定義のほうであることに注意。
*6:場合によってはチェスソフトのコードを多くコピペしフルスクラッチですらない。
*7:反則負けを連発し、ルール通りに指すことそれすらもできないソフトも多く存在する。
*8:将棋エンジンを登録して指せるGUIのアプリケーション。
*9:後から気づいたが探索の一番外側を数えてなかったので5手読みだった。
*10:将棋を指すプログラムを書いて動くのが楽しいというのはわかるが。
*11:後から気づいたが実は深さ5だった。