1file match(仮)の参考資料4(ネガアルファ法)

1file matchというのは下記の経緯で私が考案した初級者歓迎部門の新設案です。

1file match(仮) - 48's diary

1file match(仮)の参考資料 - 48's diary

1file match(仮)の参考資料2(数行でレートを1300以上上げる) - 48's diary

1file match(仮)の参考資料3(駒得評価関数) - 48's diary

1ファイルマッチ体験会 - 48's diary

 

思い付きで弄ってましたが短いサンプルプログラムを作るのは好きな方でプチ実験的なものは多数作っています。

 

前回、駒得評価関数を実装しましたがその際Min-Max法のサンプルは沢山あるとコメントしてますが適当なものを探しておきました。

 

Algorithms with Python / ミニマックス法 (nct9.ne.jp)

参考文献に松原先生の著書がある辺りがミソです。

 

で、自分で実装したものが以下です。

MIN_VALUE = -32000
MAX_VALUE = 32000
SEARCH_DEPTH = 4
 
# 参考:ネガアルファ法 http://www.nct9.ne.jp/m_hiroi/light/pyalgo25.html
def negaalpha(depth, board, alpha, beta):
    global nodes, start
    if board.is_game_over(): # 負け局面は即リターン
        return -30000, "resign"
    if board.is_nyugyoku(): # 勝ち局面も即リターン
        return 30000, "win"
    if m := board.mate_move(3): # 三手詰みも即リターン
        return 30000, move_to_usi(m)
    if depth <= 0: # 残り探索深さがなくなれば評価値を返す
        # global nodes
        nodes += 1 # 評価した局面数をカウント
        v = eval(board)
        return v, ""
    #
    value = alpha # MIN_VALUEでもいいんだけど
    move = 0 # 以下のループが全部すり抜けたとき用の初期化
    pvm = ""
    legal_moves = list(board.legal_moves) # いわゆる合法手リスト
    for m in legal_moves:
        board.push(m)
        if draw := board.is_draw():
            v = [0,0,-28000,28000,-28000,28000][draw]
            pv = ""
        else:
            v, pv = negaalpha(depth - 1, board, -beta, -value) # depthを一つ減らしてαβを符号を変えて入れ替えるのがミソ
            v = -v
        board.pop() # 将棋はループ用に手戻しするが,ゲームによっては盤面コピーして毎回捨てるほうが速い場合も
        if value < v: # ネガマックス法 : 大きな値を選ぶ
            value = v
            move = m
            pvm = pv
            if depth == SEARCH_DEPTH:
                lap_time = time() - start + 1e-6
                print('info nps {} time {} nodes {} score cp {} pv {}'.format(
                    int(nodes / lap_time), int(lap_time * 1000), nodes, value, move_to_usi(move)+" "+pvm), flush=True)
        if value >= beta: break # ネガアルファ法 : 規定値外があれば打ち切る
    return value, move_to_usi(move)+" "+pvm

def go():
    if board.is_game_over():
        return 'resign'
    if board.is_nyugyoku():
        return 'win'
    if not board.is_check():
        if (matemove:=board.mate_move_in_1ply()):
            print('info score mate 1 pv {}'.format(m:=move_to_usi(matemove)))
            return m
    global nodes, start
    nodes, start = 0, time()
    value, move = negaalpha(SEARCH_DEPTH, board, MIN_VALUE, MAX_VALUE)
    lap_time = time() - start + 1.0e-6 # 0除算エラー対策で微小値を足してある
    print("info time", int(lap_time * 1000), "depth", SEARCH_DEPTH, "nodes", nodes, "nps", int(nodes / lap_time), "score cp", int(value), "pv", move)
    return move.split()[0]
 
実装したのはアルファベータ法の亜種と言うか実装では主流になっているネガアルファ法です。評価値を返す際にアルファベータも含めて符号を変えているのがミソですね。
 
ちょっと工夫しているのは探索途中の読み筋を表示してみたりしました。
そのために評価値と読み筋という二つの値を再帰的に渡しています。
また、探索ノード数や時間当たりのノード数なんかも慣例的に表示させているので同様の機能のためにglobalでノード数および時刻を保有しています。
今までは対局中GUIが味気ない感じでしたが、少しは探索過程が見られて楽しくなります。
 
---
追記:
先月山岡さんの法もアルファベータ法のサンプルを出されていましたので、ちょっと独自性を積むまでこちらは保留しておりました。
同様に御参考にしてみて下さい。こちらも実装はネガアルファ法の形です。
 

1ファイルマッチ体験会

電竜戦の方で9月24日21:00より1ファイルマッチ体験会を行います

電竜戦

体験会ですので,参加費もありませんし表彰もありません。

ただ,対戦してうまく動くことを確認して貰ったり本戦などの準備に使って頂ければ充分です。

勝ち負け気にせずに棋譜を残したという体験をして頂ければと思います。

 

1file matchというのは下記の経緯で私が考案した初級者歓迎部門の新設案です。

1file match(仮) - 48's diary

1file match(仮)の参考資料 - 48's diary

1file match(仮)の参考資料2(数行でレートを1300以上上げる) - 48's diary

1file match(仮)の参考資料3(駒得評価関数) - 48's diary

 

半日あれば強い弱いは度外視すれば参加は可能かと思います。

皆さんよろしくお願いします。

 

私の方は賑わしとして色々と準備をしており以下のようなエントリーです。

 

1.地ビール

2018年末くらいからフルスクラッチ開発しているGo言語の将棋エンジンおよびそれを使った簡易的な対戦プログラム。

約1600行。

第29回世界コンピュータ将棋選手権では改良型Multi Ponderシステムのコア部分として採用。

電竜戦の体験会で謎のVTuber相手に勝利を修めたり,floodgateでYSSに勝利したり個人的な満足がモチベーション。

 

2.sample4-5a

1file match参考資料用に作られたサンプルプログラムの派生バージョン。

おいおい公開予定。

開発言語はPython

cshogiやnumpyを用いて全体で150行程度の簡易なプログラムだがLesserKaiには勝利する。

 

3.shogi686_sdt5(招待枠)

第5回電王トーナメントで当時から1ファイル開発として個人的に注目していたプログラム。

製作者にお願いして今回招待枠としてエントリー,操作は私が行います。

C++の標準ライブラリのみを用い,尚且つ1ファイル構成と言う潔さ。

GitHub - merom686/shogi686_sdt5

第5回 将棋電王トーナメント | ニコニコ動画

 

勝った負けたより戦ったことがあるという体験にこそ価値があると思います。

是非御参加下さい。

 

ーーー

追記:

今なら自作プログラムで「すいしょう」に勝ったと言えるビッグチャンスかもしれません。

 

 

APUでDirectML

APUと言うのはCPUパッケージ内にGPUを搭載したものをAMDがそう呼称してから始まった。2011年である。

Intel互換CPUを扱っていたAMDRadeonなどのGPUを扱うATI社を買収したことから生まれた。同タイミングでIntel社もそれまでチップセット側に搭載していた簡便なGPU機能をCPUパッケージ側に移動した。所謂iGPUである。そして現在まで続く。

 

個人的には2012年の日本AMD本社でのブロガー勉強会が印象に残っている。私も古くからPVの少ないブロガーではあるのでエントリーさせて頂いた。土産にAPUと聞いていたがマザーボードも付いてきた。(対応マザーがまだ少ないので入手できないと意味が無いから付けたとのことでした)

bleu48.hatenablog.com

 

その昔に3DNowやらMMXやらを使ってMP3を扱うような遊びをしていたので、こいつも取り扱えるかと思いきやとてもハードルが高く結局ソフトウェア開発には繋がらなかった。

 

で、昨今のAPUであるが今はOpenCLやVulkanで叩きやすくなっている。

今回はさらにMS社が扱いやすくしてくれているDirectMLから使ってみることにする。

といってもPythonから呼ぶライブラリが変わるだけでなんてことはなかった。

 

1.Onnxruntime

onnxruntime-directml · PyPI

なんてことはなくPyPIからpipコマンドでインストールして動く。

CPU動作のonnxruntimeやonnxruntime-gpuとわずかにオプションの扱いが変わる程度である。

具体的にはonnxruntimeではその実行バックエンドのことをproviderと呼ぶがそれを指定する以下の部分である。

providers=['DmlExecutionProvider']

 

2.PyTorch

torch-directml · PyPI

こちらはβ版であるので少し慎重に扱う。自分でビルドすれば最新版が扱えるがβ版のバイナリは特定バージョンのみで供給されている。そのうちPyTorch本体に取り込まれる可能性もあるとのこと。

また、ソースレベルでインポートする宣言

import torch_directml

やデバイス指定など

    device = torch_directml.device(torch_directml.default_device())

は変更する必要があるが概ねそれくらいで大概のプログラムは動く。

 

で、重要なのが実行速度であるが、これは同じAPUで扱う限りCPU動作より1~3倍くらい速くなった。速くなるためにはCPU‐GPU間の連携がうまくいかないといけないが小さな計算を高頻度で切り替えるとオーバーヘッドが大きくなって旨味が無い。こういうったアクセラレータはそのハードウェアに合わせたある程度の規模で行うことが重要である。もちろん、本格的なGPUを使うと100倍とか速くなるので本件ちょっとしたものでしかない。

 

ところで、昨今生成系AIと呼ばれる大型の推論モデルを動かすには巨大なGPUメモリが必要とされている。APUはメインメモリ内にビデオ用のメモリを確保するため専用GPUより遅いが、設定如何では大きなビデオメモリを確保することが可能である。(そもそもメインメモリがビデオメモリより仕様上随分遅い。)確保量もマザーボード側の設定が可能かどうかに依存する。(起動後に動的に変更できないのか気にはなる)

gigazine.net

 

こういうのも動くという曲芸であって速度的には非常に遅いのであまり期待しない方がいい。上記のとおりAPUだと精々CPUの数倍しか出ない。

 

ということでAPUで少し遊んでみた。一応無いよりマシといったところである。

毎度の注意点であるが、CPUパッケージ内の簡易なビデオ出力機能であるのでここに100%の負荷をかけるのは恐らく設計外の利用方法になる。昨今オーバーヒートでクロックを下げる仕組みはあるがこの部分の対応が弱い印象があり、つまりフリーズする。過剰に期待せずちょっと使えば少し幸せになるかもしれないくらいの機能と思った方がいい。

ーーー

追記:

現在最強のAPUがデスクトップではRyzen7 5700Gである。2万5千円くらいでZen3の8コアだから普通のCPUとしてみてもコストパフォーマンスが高い。

ノートPC用のZen4のAPUが出つつあって7840HSとか7940HSとかである。この辺はまだ高額過ぎて触れていないが前世代より若干強そうである。7840Uは早く普通のPCに搭載して頂きたい。

デスクトップ用のZen4にも2コアだけGPUが搭載されていてAPU的に使えるがこれは無いよりマシ程度なもので更に期待してはいけない。8コアくらい積んだ上に廉価化するのを期待する。

ーーー

追記2:

某書籍で参考にされることが多いpython-dlshogi2ですが

GitHub - TadaoYamaoka/python-dlshogi2

こいつもonnxruntime-directmlで動きます。

onnx_player.pyのここだけ変更すれば終わりです。

DirectMLに関してはiGPUとdGPUの両方があれば選択的に使えるのでオプション有効にしてあります。(それとCPUも)

    # モデルのロード
    def load_model(self):
        if self.gpu_id >= 0:
            self.session = onnxruntime.InferenceSession(self.modelfile, providers=['DmlExecutionProvider'], provider_options=[{'device_id': self.gpu_id}])
        else:
            self.session = onnxruntime.InferenceSession(self.modelfile, providers=['CPUExecutionProvider'])

温故知新(3年ぶりNaN回目,gpsfish計測編)

温故知新シリーズと言うのが一時期続いておりました。

まぁ教育用の資料は別に作ってあるので本日記は備忘録に近い。

もしかしたら1file matchの準備をする人には役立つこともあるかもしれない。

温故知新 - 48's diary

温故知新(2) - 48's diary

温故知新(3) - 48's diary

温故知新(4) - 48's diary

Go言語将棋の進捗 - 48's diary

温故知新(ビットボード) - 48's diary

温故知新(Bonanza) - 48's diary

温故知新(番外編) - 48's diary

温故知新(テストデータ編) - 48's diary

温故知新(ProbCut) - 48's diary

 

ところで,何かというとあの高名な竹部女流には参戦しなくなったプログラムには勝ったと言って良いとする煽り文句があります。初参加の時かな?生で聞いたことがあります。

 

これ実際参戦しなくなったプログラムはどんなものかと言うと技術的に古いので新しいPCを使ったところで全然強くならないってのが上の方の温故知新のシリーズでも確認していたと思います。つまり,マシンパワー差が出るのは同世代近いレート同士だけって話です。

 

この辺をこの週末確認してみました。大きめにfloodgateの表を切り出しておきます。

 

gpsfish_i5_1235Uというのがレート2789となっています。PCは本日記でも再三登場している今年買ったミニPCです。白ビールで4000強でしたっけ?

そう言えばfloodgateのレート基準がgikou2_1cの前がgpsfishで2800とされていました。

マシンスペック関係なく同じくらいのレートになることが確認されました。以前も一回同じような計測をやった記憶があるのを思い出しました。

実は当時も技巧2で多コアのハイエンドPCを使ったものを流しており3600台であった記憶があります。たまたま今7950X3Dを名乗る技巧がおりそのレート帯ですね。詐称ではなさそうです。

 

え~っといいPC使ってもGPSはレート上がらないのに技巧は上がるのかって話です。これは並列探索のアルゴリズムかそれの最適化程度が異なるのではないかと思います。技巧はLazy SMPが熟成した後の世代ですので並列化効率は高そうです。GPSは恐らくLazy SMP導入前のStockfishを参考にしているのではないかと推察します。実際に探索速度の変化が大きいことからもLazy SMPではないと思われます。恐らくYBWCですね。

YSSの山下さんも当時は並列化効率が悪くてデスクトップもノートPCも結果的にパフォーマンス差があまりなかったと仰っていました。もちろん今は大差です。

 

ついでですが,壊れたPCの供養にここでネタにしておきます。

Core2Duoの2コアで合わせても500knps満たない程度の探索速度で上記レート表にもあるようにKristallweizenが3700超です。並のPCなら4000超えますからね。

 

ここで話題にしている「ぽんぽこ」は第5回将棋電王トーナメントの優勝ソフトで一般公開されているものです。当時のPCスペックでレート3600台でした。同年春の世界選手権優勝のelmoを上回ります。

第5回 将棋電王トーナメント | ニコニコ動画

Release tanuki-sdt5-2017-11-16 · nodchip/tanuki- · GitHub

 

公開されているというのが重要でこれが誰でも比較検討に使える基準になります。もちろん,同大会で知られているようにPonanzaより明確に強いものです。

ですから,15年前の白いポリカのMacBookがあれば白ビールはデスクトップPCの全盛期のPonanzaより強いと言えます。プロ棋士や新聞記者が白ビールを利用して不満が無いと仰るのはこの辺が体感的に理解されているからでしょう。

 

最後におまけですが,sample3-4やsample3-5は今1file match用のサンプルプログラムとして作っているものです。Pythonで100行前後なのでさくっと読めると思います。インタプリタ処理ですから探索速度が桁違いに遅いので最終盤では探索数が多いエンジンに歯が立ちませんが結構健闘していると思います。

 

で,冒頭の竹部先生の言葉ですが,古いプログラムは結局その時点で止まってますので日進月歩で伸びる技術をキャッチアップしている人なら比較的簡単に上回ることができます。コンピュータ将棋の世界選手権では上位から中堅クラスの方がそれにあたります。もちろん新参で勉強不足であっても努力をすればそのうち少しずつ強くなっていくものと思います。

100行くらいのプログラムでGPSや技巧に勝つのって凄くないですか?

---

追記:

当時のfloodgateレートを集計されている方をみつけたのでリンクを貼っておきます。

マシン的には高価な多コア機があったりするんですが,やはりソフトウェアの世代差ですね。

lfics81.techblog.jp

1file match(仮)の参考資料3(駒得評価関数)

将棋AIの大会である電竜戦に新規参入者を増やそうとする試みとして準備しつつある1file matchですが,個人的に盛り上がってシリーズ化の勢いです。

 

1file match(仮) - 48's diary

1file match(仮)の参考資料 - 48's diary

1file match(仮)の参考資料2(数行でレートを1300以上上げる) - 48's diary

 

すると山岡さんが呼応するように1fileのサンプルを出して下さいました。

cshogiのサンプルプログラム(MinMax探索) - TadaoYamaokaの開発日記

 

ランダムプログラムとMin-Max法による探索のサンプルです。Min-Max法自体は1950年代からある手法で今更解説というまでもない気がしますので他に任せます。(私のスライドや動画もネット上のどこかにあるでしょう。)

 

Min-Max法には局面評価が必須になるのですが、将棋の場合は古典的に「駒得」という考え方があります。簡単に言うと将棋は取った相手の駒を自分の駒として使えるので、任意の局面で駒の総和が保存されますが自分と相手の駒の差が生じます。この差のことを駒得といいます。序盤においては歩一枚でも歩得と言われるほど繊細なものです。

森下卓九段の名言に「駒得は裏切らない」との言葉があるように、迷ったときに駒を得する方針で指していくことが失敗しづらいとされています。もちろん必ずしも正解であると言えないのが将棋の面白いところです。

 

上記山岡さんのプログラムを一行だけ引用しました。

    value = sum([PIECE_VALUES[piece] for piece in board.pieces])

この一行で盤面の駒の価値を集計するものです。

board.piecesはcshogiの機能で盤面(board)上の駒(piece)を81マス分並べた配列が得られます。

for ○○ in ×× はpythonでよく使われる「リスト内包表記」ですね。

今回は81マス分のpieceです。このpieceは0が駒無しマス、1が先手の歩、2が先手の香車・・・そして31が後手の竜です。

PIECE_VALUES[piece]は各駒の価値で固定値で読み出し以前に初期化されています。

PIECE_VALUES[0] が 0 であることが重要です。

そしてこれらが大括弧で囲まれており、その値がList化されます。

sumの引数としてこのListが与えられますので盤面81マス分の駒の価値(PIECE_VALUES)の総和となるわけです。

もちろん普通のfor文で回して足していくことも可能ですが簡潔に書ける上、速度も速いことが知られています。

 

material_c = [0,90,315,405,495,855,990,540,0,
    540,540,540,540,945,1395,0,0,
    -90,-315,-405,-495,-855,-990,-540,0,
    -540,-540,-540,-540,-945,-1395,0,0,]
material_h = [90,315,405,495,540,855,990,]

def eval(board): # 駒の価値
    eval_mat = sum( material_c[p] for p in board.pieces if p > 0 )
    pieces_in_hand = board.pieces_in_hand
    eval_mat += sum( material_h[p] * (pieces_in_hand[0][p] - pieces_in_hand[1][p]) for p in range(7) )
    if board.turn == cshogi.BLACK:
        return eval_mat
    else:
        return -eval_mat

私の方は以前はnumpy.whereを使ってちょっと小技を利かせていたのですが、山岡さんのを参考に以上のように書き換えてみました。大きなデータだとnumpyの方が速いのですが本件くらいのサイズはこちらの方が高速でした。

 

material_h は持ち駒の価値ですが、この数値の由来はAperyが機械学習で算出したものと記憶しています。

material_c はこれを盤面用に先手後手と並べ替えた値であることは容易に分かると思います。山岡さんのPIECE_VALUESと同じ意味のものです。

 

次にこの一行ですが、ほぼ山岡さんと同じですが僅かに異なります。

    eval_mat = sum( material_c[p] for p in board.pieces if p > 0 )

board.piecesの後ろにif文があります。81マスにはpが0の部分が大半なので、これを除外するイテレータとなります。要するに駒のあるマスしか数えないってことです。

material_c[0] に何が入っていても関係なくなります。

また、上記山岡さんのものと比較して大括弧が無いことが分かると思います。[]があるとリスト内包表記としてメモリ上にListが作成されます。無い場合は「ジェネレータ式」と呼ばれる表現になり、実態はジェネレータオブジェクトです。リスト内包表記はジェネレータ式をList化(実体化)したものと理解しましょう。

sumはListも引けますが、ジェネレータ式を引いた場合Listを実体化することなく合計だけを求めます。つまりListを実体化する分のメモリ利用も減りますし実行速度も上がります。(今回は僅かですが、大量のデータでは差が付きます)

 

詳しくはクラスメソッドの方がいい記事を書かれていますので御参照下さい。

Pythonのreduceと内包表記/ジェネレータ式を比較してみた | DevelopersIO

Pythonにもreduceあるんですね。知りませんでした。

 

    eval_mat += sum( material_h[p] * (pieces_in_hand[0][p] - pieces_in_hand[1][p]) for p in range(7) )

こちらは持ち駒の集計ですね。

board.pieces_in_hand で得られる持ち駒の配列を一旦ローカルに入れてから集計しています。Pythonではオブジェクト参照のコストも馬鹿にならないので、こういったことをすることもあります。(Python本体のバージョンが上がったら無駄な行為となるのでしょう。)

 

最後に今まですべて先手側から見た評価でしたので、後手番の場合は符号を変えて返すことにします。

 

以上で駒得評価関数の実装サンプルでした。

短い中にも細かいテクニックがあり、それが効果的であることは手を動かして確認して頂けるとPython初級者にも身に付くと思います。

 

numpy.sumもジェネレータ式引けてベクトル演算できたら嬉しいなとか思いました。

---

追記:

あっという間に,山岡さんの実装も更新されてほぼ同じになってた。

実質contributorですね。

 

github.com

 

ちなみに随分昔に他の評価関数のPython実装も公開してある。

今よりコーディングが下手なのが分かるので上手に書き直すのもできそう。

 

github.com

 

1file match(仮)の参考資料2(数行でレートを1300以上上げる)

将棋AIの大会である電竜戦に新規参入者を増やそうとする試みとして準備しつつある1file matchですが,個人的に盛り上がってシリーズ化の勢いです。

 

1file match(仮) - 48's diary

1file match(仮)の参考資料 - 48's diary

 

前回ランダム指しと言うプログラムを提案しましたが,わずか40行くらいなので初級者でもさっと読めたと思います。ただ,動かすと全く勝てない。弱いですね。

ランダム同士だと何しているのか分からないくらい無駄な時間を感じます。

 

ただ,ランダムって手法自体は古典的で結構有用な方法です。例えば最近ChatGPTなる対人支援AIが流行っておりますが,そんなものより昔からずっと有料で99%以上の粗利を稼ぐ「おみくじ」と言う対人支援AIがランダム選択と言うアルゴリズムで成功を修めています。

 

そういえば前回numpyという豪華なライブラリをimportしてnumpy.random.choiceだけを使うと言う富豪プログラミングをしてしまいましたが,普通の人はimport randomでrandom.choiceを使えば本件では十分です。numpy.random.choiceは重みを付けたり重複の有無を指定して複数サンプリングができたり高機能です。

 

で,今回はこのランダムモデルからレート1300以上上げるのが目標です。

界隈でレートと言えばイロレーティングなのですが,簡単には計算サイトがあります。

イロレーティングのレート差と勝率の相互変換 - 高精度計算サイト

基本的には絶対値に意味はなく「差」だけが意味を持ちます。ただし,基準値が固定されれば絶対値に意味が生じます。(現在のfloodgateではgikou2_1cが3300と固定されています。)

 

せっかくですので,ちょっと考えてみましょう。藤井竜王名人が並のプロ棋士に9割勝つとします。イロレーティングでは大凡400差となります。並のプロ棋士がアマ高段者に9割勝つとします。これもイロレーティングが400差となります。これで藤井さんとアマ高段者の差が800と計算されます。期待勝率は99%ですね。

アマ高段者がアマ初段に9割勝つとすれば,これまたレート差が400です。これで藤井さんとのレート差が1200,期待勝率が99.9%となります。1200と言うのがこういう感じです。

同様に見ていくと恐らくアマ初段と初級者の関係もレート差1200くらい,期待勝率99.9%くらいになると思われます。実際はもう少しは大きいでしょうか。

これで藤井さんと初級者のレート差が2400で期待勝率が99.9999%と概算されます。藤井さんに初級者と1000000回対局してもらうのは無理ですが,適当な相手を置いた対戦を組んでそれぞれ相対レートを求めることが出来れば概算できると言う仕組みです。

結果人間の棋力ってのは2500~3000くらいのレート幅で整理できることが分かります。

将棋指しの方ならプロ相手に二枚落ちでアマ初段,アマ初段相手に二枚落ちで初級者レベルと言った方が伝わるでしょうか。

 

前置きは長くなりましたが,前回のランダム相手に99.95%以上勝つものを作ります。1999勝1敗でこの数字なのですが,実際の計測は2000戦全勝ですのでこれ以上ということでレート差1300以上とします。(気づいていると思われますが,これから作るものが強いのではなく前回のランダムが弱いのです。)

 

まず,一手詰めです。これを逃しては将棋ではありません。

級位者では一手詰めが概ねできれば8級認定だそうです。真面目な話をすると王手をかけて,相手にその王手を解除する手が無ければ詰みです。しかしながら,cshogiには便利な関数が既にありmate_move_in_1plyを呼べば一手詰みの手があれば返ってきます。気を付けるのは自玉に王手がかかっていないことを事前確認するだけです。理屈が分かれば,この関数を使わなくても自力で実装するのもそんなに難しくないはずです。

 

次に駒を取る手です。

人間の場合,ルールを覚えたら真っ先に見える手と言う感じでしょう。

将棋では駒の移動先に相手の駒があれば取れるわけですが,cshogiでは合法手リストを作成したときに既に駒を取る指し手であるかどうかわかっています。

https://github.com/TadaoYamaoka/cshogi/blob/master/src/move.hpp

 

ここですね。0b00000000111100000000000000000000の部分が取る駒の駒種を表しています。ビット演算でANDを取れば駒を取る手のみ正の値,それ以外は0となります。

 

成る手です。これも人間の入門者が大好きな一手のはずです。人間では全ての合法手リストを作成するまでもなく指し手候補になると思います。

駒を取る手と同様に駒を成る手は0b00000000000000000100000000000000とAND演算すれば成る手のみが正の値を持ちます。

 

合わせた0b00000000111100000100000000000000でANDを取るとどうなるか考えてみて下さい。

駒を取る手も成る手も無ければ全部0ですね。

そのときはランダムにしましょう。

ということで効率的に行うためにまず合法手をすべてランダムで並べ替えて,上記フィルタでANDを取った値が最も大きいものを見つけるという手段を取ります。

 

以上の改造を前回のものに加えたのがgoのところだけ数行ですが以下のようになります。

def go():
    if board.is_game_over():
        return 'resign'
    if board.is_nyugyoku():
        return 'win'
    if not board.is_check():
        if (matemove:=board.mate_move_in_1ply()):
            print('info score mate 1 pv {}'.format(cshogi.move_to_usi(matemove)))
            return cshogi.move_to_usi(matemove)
    legal_moves = list(board.legal_moves)
    random.shuffle(legal_moves)
    move = max(legal_moves, key=lambda x:x & 0b111100000100000000000000) # 取る駒,成るフラグの部分をフィルタして最大値を取る
    return cshogi.move_to_usi(move)

 

今回はnumpyを使いませんでしたので

import random

もしておいて下さい。

Python入門者はゆっくりどういう意味かじっくり読んでみて下さい。

ちょっとした技をつかっていることが分かると思います。

 

難しければ質問など頂ければ可能な限り対応しますが,読む努力をしないと自分で作れるようにはなりませんので時間をかけて頑張ってみて下さい。

---

ちなみに:

これくらいではコンピュータ将棋界最初の壁と呼ばれるLesserKaiには勝てません。

LesserKaiのレートがfloodgate基準で700だとか1000だとか言われていますのでまだまだと言うことです。

floodgate近況(2023年7月)

前回が5月でした

bleu48.hatenablog.com

 

tanuki-WCSC33が強そうってことで,ミニPCのi5 1235Uで投入しておりました。比較するのは2週間レート

 

 

1スレッドで4201,2スレッドで4301ってところですか。結構強いですね。

13900Kで4600級も納得でしょう。

このミニPC冷却がそこそこ優秀で2スレッドまで4GHz維持していまして,ほぼ理想的な性能が出ます。

ノートPCではそうもいかないのですよね。ってのが次の話題

 

以前,Ryzen5 5625搭載ノートPCでハイパースレッディングを使わない方がいいという話がありました。

ハイパースレッディング考察2022 - 48's diary

6スレッドでも12スレッドでも3900台半ばってところでした。

 

今回は更にスレッド数を減らした実験です。

 

 

1スレッドで4029,2スレッドで3991となりました。前回とは対戦相手が異なりますので直接比較の精度は低いですが6スレッドより強い可能性はあります。

前回12スレッドでは2.3GHz付近まで落ちるのに6スレッドでは3GHz近くで動くので優秀とのコメントを入れておりましたが,これ本来4GHzを超えられるCPUです。実際1スレッドでは超えてきますし,2スレッドでも1割弱くらい下回る辺りでふらふらします。

まぁ,熱ですね。1スレッドでないと最高クロックで動かないくらいに今のノートPCは熱設計が厳しくなっています。

 

それに比べて上記のミニPCの優秀なこと。

こいつの性能は期待通りですが,ノートPCの方が想定外に熱設計が甘いですね。8コア買っていたらどうなっていたことやら。

ミニPCは小さいとはいえノートPCに比べ厚さが稼げる分冷却設計に余裕があるんでしょうか。省電力ですしfloodgate連続投入などの実験向きですね。

ということで,5月にも触れたW@nderERさんの方も今後ミニPCで計測していきます。

 

おまけ:

上記レートでarcがIntel Arc A380での二番絞りです。Ryzen7 5700G内蔵GPUよりマシですがまぁ計測しなくても分かる帯域ですので連続運転して安定していることを確認した程度です。

---

追記8/8:

w@nder_2tの計測中,うちの回線が定期的に切れる状況になって継続的な測定ができないと断念しました。レート4000以上あることは間違いないですね。

また,floodgateの仕様上@以降は無視され,@以前の名前でレート計算が統合されることを思い出した。

 

近頃1file match用のサンプルプログラムを少々弄っていましたが,LesserKaiに完勝しfloodgateのレート計測が可能な程度には強くなってきました。この辺までは段階を踏んで公開する予定にしています。