効果は微々たるもの

     前回の記事で書いたChatGPTからのアドバイス(駒種判定のためのメソッド呼び出しをやめた件)をCoffeeScript(JavaScript)版にも取り入れて少しは速度アップ(README.mdの例で1781ミリ秒掛かっていた処理が1279ミリ秒、約25%アップ)しましたが体感できるほどではありません(masterのlistPiecesタグ)。
     そこで、その最新バージョンを元に将棋盤を配列として扱う形に変更して、Pieceオブジェクトで座標管理するのをやめてみました(arrayBoardブランチ)。そして、取り敢えず速度の比較が出来るところまで作り込んだだけで全然未完成なのですが、取り敢えず気になっていたことを確認してみました。

    何が気になっていたのか

     現行のプログラムでは将棋盤オブジェクト(Board)で全ての駒オブジェクト(Piece)のリストを管理していて、盤上の座標位置は駒オブジェクトに持たせています。普通に考えれば将棋盤クラスで座標(段・列)を管理することを考えると思いますが、駒台が必要なので駒台にある駒と将棋盤上にある駒を区別して管理するのが面倒です。作ったのはかなり昔なのでその時の動機をはっきりと憶えているわけではありませんが、着手した手を元に戻す操作を実装する際に、持ち駒を打ったのか盤上の駒を動かしたのかによって処理が分かれるので、局面を読み進める際に「指しては戻し、打っては戻し、取った相手の駒を駒台から盤上に戻す、という操作を繰り返しながら整合性を保つのは大変だ、絶対バグる」と考えたのだと思います。Pieceオブジェクトで座標を管理していれば、持ち駒も盤上の駒も区別なくPieceオブジェクトが持つ座標を書き換えるだけで済むというメリットがあります。
     マンカラアプリの解説記事でも書いていますが、マンカラで着手した一手を元に戻すのは「横取り」のルール等もあって非常にややこしいので、マンカラの先読み過程では一手毎にマンカラの盤ごとコピーして破棄するというやり方で実装しました。着手を元に戻すという処理をしていません。マンカラの場合は豆の数が入った単なる一つの配列なのでコピーしても負荷は小さいですが、将棋盤オブジェクトとそこにある駒オブジェクトの局面ごとコピーするのはかなりの負荷なので、将棋プログラムでマンカラと同じやり方で実装すると実行速度アップは望めません。
     なので、マンカラほど複雑ではないとはいえ、頑張って着手を元に戻す処理(revert処理)さえ正確に実装すれば将棋盤と駒台が分かれていても速度アップできるのかな?と考えてそれを確かめるためにarrayBoardブランチを作って試してみたわけです。
     前回の記事で「ChatGPTが将棋盤を配列にしろ」と言ってましたが、Grokに聞いても同じアドバイスをされました。どうやら生成AIにとっては「これが正解」という将棋プログラムのクラス設計がはっきりしているということかもしれません。速くなるのなら独自のやり方に拘るつもりもないので、将来的にはGrokが示すやり方で仕上げてみようかとも思ってます。

    具体的な変更箇所

     やったことを簡単に言えばPieceクラスから座標を管理するための@posiメンバーを削除して、Boardクラスを配列クラスの継承クラスにしただけなのですが、これをすることによって

    dest = (v for v in @pieces when v.posi? && v.posi[0] == d_posi[0] && v.
    posi[1] == d_posi[1])[0]
    

    このように全ての駒を走査してその場所に存在する駒を取得していた処理が

    dest = @[d_posi[0] - 1][d_posi[1] - 1]
    

    とBoardオブジェクトの配列を参照する処理だけで済みます。
    現在リリースしているアプリも今回の改良版(master)でも、最も頻繁に呼び出されるであろう着手可能かどうかを判定するメソッド(check_move)内でこの作業を毎回やっていて、流石にこれは冗長だろうと考えてPlayer.think内ではわざわざ盤面用の2元配列を用意して(Player.think内のsrc変数)Pieceオブジェクトをその配列に配置し直して駒のリストを全探索しないで済むように改良した経緯があります。
     そんなこと(駒オブジェクトで管理している座標を元に将棋盤の配列を生成)しているぐらいなら、元からBoardクラスを配列にしていた方が速くなるのかな?と考えて今回実験してみたのですが、結果は?

    arrayBoardブランチの実験結果

     README.mdの対局例を実行した結果は1700ミリ秒ぐらいかかって、現在リリースしているバージョンとほぼ変わりませんでした。現在リリース中のアプリより若干改良高速化した後での結果ですから、Boardクラスを配列にしただけでは却って遅くなったと言えます。結局、将棋盤上の駒を取得する処理が軽くなっても指し手のrevert処理は複雑になってしまいましたし、トレードオフの関係にあるのでしょう。
     とはいえBoardクラスを配列にすると他にも高速化の手法がありそうなので今後もarrayBoardブランチを育てていくかもしれませんが、取り敢えずはここで打ち切ろうと思ってます。
     それと今回やった作業は駒の数が少ない3三将棋だから効果が薄かったのかもしれませんので、7七将棋でも試したいと思ってますが、現状のarrayBoardブランチはまだまだやり足りないことがいっぱいなので、完成するのはかなり先の話になると思います。
     そして完成したからといって速くなってる保証もありません:sweat_smile:ただ、そのソースを元にC++に書き換えたら速くなる、なんてことになるような気がします。

    今後のアプリの予定

     冒頭で書いたように現在リリースしているものより若干は速くなったのでmaster(listPiecesタグ)の内容を反映して、将棋アプリもチェスアプリも順次リリースしていこうと思ってます。ついでに、最近はハイスペックなスマホも増えているので、どうせならAIのレベルを一手づつ読む深さを深くしてリリースしてみたいと思っているのですが、そうすると最強レベルだと現在以上に指し手が遅くなりますので、アプリを使う気が無くなるぐらい遅くなるかもしれません。でも、AIのレベルを下げれば今まで通りの指し手になるわけですから、あってもいいんじゃないかと思ってます。 全然ハイスペックではありませんが、私自身つい先日スマホを買い替えた(Pixel10Ⅶ)ので、それで試してから決めようと思ってます。一手深く読めば指し手がどのように変わるのか楽しみですよね?私は楽しみです:smile:
     いずれにしても私のアプリを使う人は指し手を気長に待てる人にしか向いてないと思います。