Vibe Codingで将棋のUSI通信を行うAPIサーバーを作ってみた。

以前のブログに将棋の盤面を渡して、最適手筋をかえしてくれるようなAPIのサービスがあったらありがたいと書いた。 実際にオンラインでコンピューター将棋を実現しているサイトはどんな手段をつかっているのだろうか?

ネットでいろいろ見聞きしてみて大まかに二つの方法があるらしいことが分かってきた。

一つはクライエントUIから盤面情報を送り、それに基づいて、指し手を供給するサーバーを使う方法。

もう一つはブラウザーに将棋エンジンの実行コードを送ってしまい、ブラウザー上で将棋エンジンを実行させてしまう方法。

どちらも一長一短がありそうだ。

サーバーにやねうら王のような本来一つの入出力で動作するエンジンを常駐させて、ここからhtttpリクエストにこたえる方法ではhttp接続のクライエントが複数になることを考えると、position と go コマンドをセットにして処理する必要がある。 それにgameover などのコマンドは意味をなさなくなる。本当に多数のマルチクライエントに対応するためにはロードバランサーの背後にいくつものサーバーインスタンスを置くことになるのだろう。自分の能力も予算も超えてしまうのである。

一方のブラウザーで将棋エンジンを実行させてしまうというのは、何なの?と思うかもしれないが、要はブラウザに実装されるJavaScriptのエンジンで将棋AIを走らせましょう、ということである。 JavaScriptのマシン語とも言えるWeb Assemblyというバイナリーを実行することができる。 専用のコンパイラがあり、C++やRUSTのソースコードからWASMモジュールへのコンパイルが可能なTool Chainが存在する。 実際にYaneuraouのソースコードにはWASMをコンパイルするためのScriptもメンテナンスされている。YaneuraouのWASMmodule自体は圧縮すれば300キロバイト以下のようで、これにnn.binを追加しても今の一般のネット環境ではサイズ的は気にしなくてもよさそうだ。あまり大きなペタショックのような定跡ファイルを転送するのはさすがに憚る。性能はブラウザが走るデバイスによるところが大きそうだ。

liShogiのサイトでは用途に応じて両方を使っているっぽいのである。この将棋サイトはソースコードがGithubで公開されていて、眺めていると面白い。

実際にどんな使い心地なのか自分でもためしてみたかったので、まずはブラウザ上でWasmエンジンとお話できるコンソール的なものを作ってみた。 このときはじめてAIにコーディングを本格的に手伝ってもらった。使ったのはBrave blowserについているLeoというAgentだが、用途に応じてAIエンジンが切れ変わっていた。コーディングにはAntrhopicのHaikuを使っていた模様。 この時は自分で書いたオリジナルコードをAIに確認してもらい、機能の追加や、モジュール化、その他云々を生成してもらった。 一応Proof of Conceptだったので、コンソール上でコマンドを送り、それに対して解答をもらうようなところまで確認できたところで終了。、 いつかはこれをもとに将棋盤を描画するWeb UIも作ってみようと思うわけである。
ソースコードはこちら

で、昨日ふと、サーバーサイドでエンジンを動かすほうもコンセプトだけでも試してみたくなり、 今回プログラムを書くにあたって、最初からAIに書かせることにした。人間側は指示だけしてAIがコード生成しながらプログラムを仕上げていくのをVibe Codingというのだそうである。 という訳で自分はプロジェクトのコンセプトだけ考えてテキストに書きだし、これをAIに提出してコード生成をお願いしてみた。

テキスト内容はこちら。

 

Shogi API server.
Use nodejs expressjs framework.  We will add authentication and security through middleware in the future.
the server need to communicate with executable binary on the server.  It’s default path should be ./engine/engine but
should be able to be configured through environmental variable process.env.  for that we will include dotenv library as well.
node process should be spawning binary and connect to stdin/stdout.
engine uses USI protocol.   If unfamiliar with USI protocol,  I will provide the spec.
write source code in typescript for easy maintenance. breakup file modules in logical order.
API points
1.  get ‘/’ route should return health check.
2. get/api/usi_command will issue corresponding command. Do not implement points for ‘go’,’go mate’ ‘, ‘position’, ‘setoption’,’quit’
3. usi_command that does not expect any return value should resolve immidately..
4. get/api/setoption/<name>/<value>  to implement setOption name <name> value <value>
5  post /app/analyze/<waittime>  implement successive sequence of  ‘position sfen <sfen>’,  ‘go [waittime]’ sequence, (this to avoid multi-client racing condition so thatpostion information will no be overwritten by other client)
    body should contain {“sfen”:”<sfen>”} that can be used to send position sfen <sfen> command.  then send ‘go waittime’ and wait for ‘bestmove’ and return the output
if <waittime>(integer, representing milliseconds) is omitted, just send ‘go’ command.
if <waittime> is 0 then issue ‘go infinite’ command and monitor stdout response and send ‘stop’ command when there is no output for 10 seconds, wait for besstmove and return teh output.
1. engine initialize routine should do the following.
 a. spawn a process.
 b. send ‘usi’ command and wait for ‘usiready’
 c. send setoption name <name> value <value> using parameters prepared by config.json
 d. send ‘isready’ and wait for ‘readyok’
 example of config.json
 {
   USI_Hash : 2048,
   FV_Scale : 24
 }
2. since engine.exe is a single thread in/out process, next command will not be processed the current command is executed. the command should be quced.
3. in case of unexpected crash of binary, restart the engine with up to 3 retries within 3 minutes.
4. development server should use port 3000

英語でやっているのはこのほうがプログラム言語との相性が良いと思っているから。

使ったAIはClaude DesktopからSonnet4.6(規定値)
10分くらいでプロジェクトのセットアップからコードベースまで全部出力してくれた。

テストをしてみて、一部動かないところが判明したので現象をAIに説明(例えば config 命令に対し、データとして空のアレイが返されてきた。 YaneuraOuのConfig データ出力では最初の一行がブランク行出力されることを確認してこれをAIに報告)トラブルシューティングをしてもらい、原因を究明(例の場合、空行出力を出力終了の判定に使用)して、コード修正(同、中身があるデータが出力されるまで非判定のフラグを立てる)。さらに使って見て気づいた仕様の変更と追加を指示するなどの工程を数回まわし、一応満足できるものができたので、そこを目途にReadme.mdの作成を指示。

これもすらすら書いてくれたが、Overviewが無かったので、 Overviewの追加も指示。

このOverviewを見て笑った。 間違ってはいないのだが機能の説明が大風呂敷広げた感満載なのだ。実に立派そうなプログラムである。 仕事に応募してくるアメリカ人のレジメを見ているようだ。 自分が欲しい機能は sfen文字列を送って、その盤面に対する指し手を返してもらいたいだけなのだが、ほかにもいろいろできたっけ。

そのまま公開するのでこちらからご覧ください。

このサーバー、エンジンをインストールするとちゃんと動くがスケーラビリティがほとんどないので用途は限定されます。
ただ、全体にかかった時間が3時間ほどであり、Weekend programmer である自分のコーディングスピードを考えると驚異的な効率でプログラミングできたことになる。

AIによるプログラミング意外と使えるなあと思った次第。

 

String.replaceで知らなかった件

User がノート欄にやたら長いリンク先をそのまま張り付けて、SharePointのリストの表示が著しく損なわれるという現象が自分の管理するサイトコレクションで何件か発生している。 ユーザー教育を行ってリンクの説明を別途短文入力してください、というのは簡単だが、だまって従ってくれるような従業員ばかりではない。 そこで長いリンクを見つけたら強制的に短い文字列に置き換えてしまう、という仕掛けをJavaScriptで書いてしまえばよいのだと思いつき、 試してみた。 結果、以下のような関数を記述し、これを描画時に呼び出す形で解決した。

function shortenAnchor(text) {

    if (text===null) {
        return "";
    }
    let testPattern = /(<a.*?href=.+?>)(.*?)(<\/a?>)/g;

    function replacer(match, p1, p2, p3) {
        if((p2.length)>30) {
            p2 = p2.slice(0, 25) + '...';
        }
        return [p1, p2, p3].join('');
    }

    return text.replace(testPattern, replacer);
}

このコードで何をやっているか。 まずtestPatternを正規表現(RegExp)で記述する。 RegExpで a tag elements をグローバルにトラップする。トラップしたエレメントはタグの前の部分、中身のテキスト部分、タグの後ろの部分にグループわけされ、それぞれの文字列は$1,$2,$3として利用可能になる。( a tag element 全体のマッチは$&)。 そして、あとは String.replaceを使ってマジックをおこすわけだが、Implementationを試行錯誤している最中に 二つ目のパラメーターが実は関数でもよいのだ、というのを本日初めて知ったわけで、それを使ってうまく書くことができた。 ここに関数を使うと、以下の引数が この順番で使えるようになる。 まずは TestPatternそのもののマッチ $&, それぞれグループ分けした部分のマッチ $1,$2,$3。 よって match,p1,p2,p3として利用可能にしておく。実はこの後ろにIndexなどのパラメーターも続くのが、今回は必要がないので無視。 
この replacer という関数ではこの中身の文字列$2(p2)の長さが30文字以上あった場合、最初の25文字以下を切り捨て点三つ…を最後に追加するというもの。 この関数自体を二つ目の引数として使う。 Testしてみたら一発で完動したので感動(おやじギャグです)

普通はString.replaceというと

"this is a pen".replace("this","that") //=>"that is a pen"

という簡単な使い方は知っていたし、 最初のパラメーターを正規表現にすれば $& $1 etc., などのパラメーターを使ってかなり柔軟な置き換えなどができることも知っていて使ってはいたのだが、まさか関数まで使えるとは思っていなかった。 これは素晴らしい、と思った次第

TypeScript その2

年末の休暇を利用してtypeScriptの演習を続行中。 現在まで理解できたところをとりあえず列挙。
nodejs が導入されている必要あり。

npm install typescript -g

これで tscコマンドが使えるようになる。

tsc example.ts

そして、これでexample.ts から example.jsがトランスパイルされる。

プロジェクトフォルダー内で

 tsc init

とやると、コンパイラー設定用のtsconfig.jsonが作成され規定値が設定される。例えば、出力のJavaScriptのレベルが

<pre>”target”:”es5″</pre>

などと記述されている。またコードをトランスパイルしたときのエラーの出力設定などもできる。今のところ全く変更の必要のないレベルでトライアル中。

TypeScript は 基本的には JavaScriptのsuper setなのだが、 ’let’, ‘const’, ‘arrow function ()=>’, ‘ … spread operator’,’Template strings’ などes2015の書式が既にサポートされている。 なのでexample.tsではこれらの言語機能を使ってプログラムを書き、tscでトランスパイルすると、これらの表記をまだサポートしていない現行のブラウザでも動くようなJavaScriptに書き換えてくれる。上のConfig例ではes5レベルのコードに置き換わる。 つまりBabelと同じような使い方ができる、。

type safeなので 異なったタイプの変数へのアサインは論外としてもその可能性が生じそうなコードにはエラー表示が鬼のようにでる。例外処理とか、Interface定義を記述して対処すると満足して何も言わなくなってくれるので、バグの可能性のあるコードを書く可能性が低くなる。

SharePoint online :: modifying “New item or Edit this list” to “Edit this list”

This is my first “SharePoint Online” related javaScript.(I am still experimenting with nuance of SP online)
This script changes “New item or Edit this list” links to simpler “Edit this list link.


/**
* Created by A2life on 3/24/2016.
* Modify new or edit div to "edit this list" only
* modify "New items or edit" elements on entire page (not just webPart this is attached to)
* */
(function () {

var thisContext = {};
thisContext.OnPostRender = modifynewEdit;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(thisContext);

})();

function modifynewEdit() {
// jQuery library is required in this sample
// Fallback to loading jQuery from a CDN path if the local is unavailable
(window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.3.min.js"><\/script>'));

jQuery("td.ms-list-addnew:contains('new')").each(function (index) { //only respond to "New" elements
var edit = $(this).find('a:contains("dit")'); // because I am looking for "[E|e]dit"
edit = edit.text("Edit").add("<span> this list</span>"); // reconstruct link with proper words
$(this).html(edit);
});
}

attach this to list webPart as jsLink parameter. If uploaded to Site Assets folder as “modifyEdit.js” , it should look like “~site/SiteAssets/modifyEdit.js” . “~site” is a token for the site that sharePoint uses to resolve the url reference.

Note on this code.

  • The document.write line dynamically writes a script tag for jQuery. This appears to be more reliable way of loading jQuery rather than referencing to the file within script tag.
  • The code creates a context override for onPostRender SP event for the webPart (of item list view) being attached. This event seems to fire even when other list view on the same view is changed  (and the code invoked will affect other list views on the same page as expected) so the function modifynewEdit is attached to this event.

Python3 の文字列 覚書

Python3ではstring = unicode

string をアレーとして考えてslice するときもマルチバイト文字を気にする必要がない。

>>> s = 'pythonに、どっぷりつかる'
>>> len(s)
15
>>> s[8:]
'どっぷりつかる'
>>> s[:6]
'python'
>>> s[:7]+s[8:12]
'pythonにどっぷり'
>>> 

ただ、よいことばかりではなく、fileなどからのIO処理では読み込まれるのがバイト列になるため変換をしてあげる必要がある。 Python 2.7では必要なかったのでPython2.xのプログラムを移植するときに注意が必要。encode()としてunicodeのバイト列表示、decode()でUnicodeのバイト列をUnicodeの文字列表示

>>> s.encode()
b'python\xe3\x81\xab\xe3\x80\x81\xe3\x81\xa9\xe3\x81\xa3\xe3\x81\xb7\xe3\x82\x8a\xe3\x81\xa4\xe3\x81\x8b\xe3\x82\x8b'
>>> b'python\xe3\x81\xab\xe3\x80\x81\xe3\x81\xa9\xe3\x81\xa3\xe3\x81\xb7\xe3\x82\x8a\xe3\x81\xa4\xe3\x81\x8b\xe3\x82\x8b'.decode()
'pythonに、どっぷりつかる'
>>> 

最初のバイト列がUnicode以外の文字列の場合はencodingを指定

>>> chara = b'\x63\x6c\x69\x63\x68\xe9'
>>> print(chara)
b'clich\xe9'
>>> print(chara.decode('latin-1'))
cliché

IIS のurls rewrite を使ってmodxのfriendly url を有効にする。

たとえIISサーバーを使っていてもHelicon Ape というツールをIISに組み込めば、modxについてくる.htaccess をそのまま使っのfriendly url を活用することはできているわけだが、今回はIISのURL rewrite module (IIS 7 の場合は別途ダウンロードで組み込む)を使って同じことをやってみた。

IISのGUIでルールを作る作業になるが、.htaccess の記述を参考にしてやってみたら動くようになった。

modx に付属する.htfile でfurl に関連するところは 以下の部分と思われる

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

これを解釈すると
条件として、要求されているファイル名がファイルとして存在しない、かつ
フォルダーとしても存在しない場合、それはつまり動的に生成されるHTMLページなので、
以下の書き換えルールを適用する。
書き換えルール: 渡された文字列$1を以下のパターンにして加工する
“index.php?q=$1”
さらに 後ろにクエリーがついている場合はそのまま渡し、 下流の処理を行わない。

IISのGUI上のRuleでは これを Inbound rule として追加するが、その内容は以下のごとくなる。

Matches Pattern, “Regular expression”
“^(.*\.html)$” <= RewriteRule の最初の部分*1 Conditions : "Matches All" {REQUEST_FILENAME} "file does not exist"  {REQUEST_FILENAME} "Directory does not exist" Action type "rewrite" index.php?q={R:1} <= RewriteRule index.php?q=$1 に匹敵 Append ques : yes <= [QSA] に匹敵 Stop Processing: yes <= [L] に匹敵 当たり前ながら、同じ条件を記述しているので、それほど迷わずにできた。 はまりそうになったところはRegular Expression の部分で.htmlを明示している部分。これをやらないとloopしてしまう。 ほかのところの条件付けでもっと綺麗に記述できるかもしれない。 とりあえず、これでOK

HP 15C 復刻版 limited edition 到着

とりあえずそういうことで

玄関に届いたFEDEXのパッケージ

 

 

少しよれているが、中身は大丈夫か? すくなくとも封筒に入ってこなくて良かった!

中身は無事

 

化粧箱(Gift box)のフタをあけたところ

化粧箱(Gift box)のフタをあけたところ

 

Manualは288頁の厚さ。CDにはエミュレータープログラムがついてくる

Manualは288頁の厚さ。CDにはエミュレータープログラムがついてくる

 

裏面には使用方法のアルミパネル

電池蓋を外すと2枚のセルの中間下方に6ピンの接続パッド。HP20B、30Bと同一仕様

結構若いシリアル番号だった

結構若いシリアル番号だった

付属してきたポーチに入れるとこんな感じ。若干きつめ

 

FキーとGキー以外はキーボードもしっかりしている。 けれど、もっとキータッチは固かったような(他のメーカーの計算機に比べればこれでも十分固い)

それでは週末にでも時間を見つけてすこしいじってみましょう。

 

 

MyBook LiveというNASでWEBサイトをホストしてみた。実践編その3

一昔前と違い、WordPressやJoomla!あるいはDrupalとかModXなど Webサイトを作るのに
Content Management System (CMS)を使うのが当たり前のようになっている昨今、 Apacheサーバーにはデータベースサービス(例えばmysql)とこのデータベースとウェッブページをつなぐツール(例えばPHP)が必要だ。 最初から何も実装されていなければ、lamp(linux Apache mysql php)などという便利なパッケージもあるが、すくなくともapacheサーバーは実装されているのでlamplをインストールするわけにもいかない。

Mybook Liveで動いているApache2サーバーはすでにPHPも実装されている。 UIの画面自体、PHPベースのCakeというフレームワークで作成されているようだ。

<?php phpinfo(); ?>
という一行を phpinfo.php というファイル名でWEB folder上に保存し、(前回の例では/stores/Public/WWW) ブラウザでアドレスを mblwebsite/phpinfo.phpと打ち込むと、PHP情報が表示されるはずだ。
これを見るとMysql用のインターフェースも実装されている。 PHP側からmysqlをアクセスする準備は整っているわけだが、 残念ながらMBLはmysqlのサーバーは実装していない。
そこでMysqlサーバーを個人のリスクでインストールすることになる。
Debian上でのインストールはいたって簡単で、
#aptitude update
でパッケージリストを更新したのち、
#aptitude install mysql-server
または
#apt-get install mysql-server
インストールの準備が整うと、本当に実行しますか?と聞いてくるのでYesと応えるときちんと実行される(はず)
途中でパスワードを作るように催促されるのでMysqlのroot 用のパスワードを適当に考えて入れてやる。(覚えておきましょう)
インストールの終わりにはMysqlサーバーを起動してくれるので、 これをアパッチ側にも認識させるために アパッチサーバーを再起動
/etc/init.d/apache2 restart
これでApache +Mysql + PHP の環境が整った。
また、Mysqlの管理用にphpMyAdmin あるいは sqlbuddyなどの管理ツールを用意しておくと楽である。 これらはいずれもパッケージをダウンロードし、Web用のフォルダーにサブフォルダーを作り、解凍しておくだけで、すぐにブラウザーから使えるようになる。 詳細はそれぞれのパッケージのReadme を見てください。