はじめに
コンピュータ将棋の分野では、年々ソフトウェアの棋力が向上しており、10年以内にソフトウェアが平手でプロ棋士を破る日が来るのではないかと予想されている。
しかしその一方で、人間の「直観」による高度かつ高速な計算力は、未だその詳細が明らかになっていない。
人間の意図を計算機に伝えるためのプログラミング言語の世界においても、脳の直観を最大限に活かすには、現代のプログラミング言語はいずれも単純すぎると言えるだろう。
しかし最近では、これを逆手に取って、人間同士が戦うボードゲームのルールや戦略を抽象化し、プログラミング言語の世界にフィードバックする試みが実用化され始めている。有名なところでは、Google社のプログラマの手による囲碁をモチーフにしたプログラミング言語が一般公開されたのも記憶に新しい。
ModanShogiはこのようなトレンドをいち早くキャッチし、日本のポピュラーなボードゲーム、「将棋」をモチーフにして開発されたプログラミング言語である。
ModanShogiとは即ち「モダン将棋」であり、活発な戦略研究が進む現代将棋のエッセンスをプログラミング言語に取り入れる……という意味ではなく、「モダン焼」のモダンであるとされている(図1、モダン焼フジにて撮影)。
サンプルプログラム
ModanShogiで「Hello, world!」と表示するプログラムの例をリスト1に示す。
では、ModanShogiの言語仕様を見ていこう。
文法
ModanShogiのプログラムは、命令又はラベルを並べたものである。命令及びラベルの間の文字列は単に無視されるので、プログラマは自由にインデントを行ったり、ラベルの後などにコメントを書くことができる。ソースコードのエンコーディングはUTF-8でなければならない。
命令
命令は、以下のような形式をとる。
PLAYERは「▲」(先手)または「△」(後手)のいずれかである。意味は特にない。最初の命令には▲を使い、以後は△と▲を交互に使うのが望ましい(必須ではない)。また、▲および△の代わりに、Unicodeで規定されている「☗」および「☖」を使うことが許されているが、入力が面倒なのでお薦めしない。
COLは全角アラビア数字の「1」から「9」までのいずれか、ROWは漢数字の「一」から「九」までのいずれかである。COLは命令の第一引数として、ROWは命令の第二引数として使われる(後述)。特例として、COLおよびROWが直前の命令と等しい場合には、これらをまとめて「同 」とすることができる。「同」のあとは全角スペースである。
PIECEは「香」「桂」「銀」「金」「玉」「王」「飛」「角」「龍」「馬」「と」のいずれかである。PIECEは命令の種類を表す(後述)。PIECEとしてはこの他に「成香」「成桂」「成銀」があり得るが、これらは将来の拡張のために予約されており、使用するべきではない。また余談ではあるが、将棋の棋譜としては「玉」のみを使うのが慣例であるため、潔癖症のプログラマは「王」を使用するべきではない。
ラベル
ラベルは、ジャンプ命令の飛び先として使われる(後述)。ラベルは、以下のような形式をとる。
Nは1以上の任意の自然数を、半角アラビア数字で表記したものである。
意味論
ModanShogiプログラムは、仮想的なレジスタマシン(以下、「仮想マシン」)の上で実行される。
レジスタ
ModanShogiの仮想マシンは9個のレジスタを持つ。これらのレジスタには1番から9番までの番号が振られている。各レジスタは、1つの実数を保持することができる(つまり、整数だけではなく、小数も保持できる)。
プログラムの開始時には、各レジスタは、そのレジスタ番号と同じ値を初期値としてもつ(つまり、1から9までの整数が入っている)。ModanShogiには数値リテラルが存在しないため、これらの値をやりくりして必要な計算を行うことになる。混乱を避けるため、慣れるまでは1から4あたりのレジスタには上書きしない方がよいだろう。
スタック
仮想マシンには、9個のレジスタに加え、1つのスタックが用意されている。このスタックには実数をプッシュ・ポップすることができる。
命令
ModanShogiの命令群の概略を表1に示す。
表1 ModanShogiの命令群
PIECE | 別名 COL ROW | 意味 |
と | mov X Y | X = Y |
歩 | add X Y | X += Y |
金 | sub X Y | X -= Y |
銀 | mul X Y | X *= Y |
桂 | div X Y | X /= Y |
香 | mod X Y | X %= Y |
龍 | push X _ | Xをプッシュ |
馬 | pop X _ | Xをポップ |
玉 | putc X _ | 文字コードXの文字を出力 |
王 | putn X _ | Xを数値として出力 |
飛 | jump_if X Y | Xが非0なら、ラベルY番にジャンプ |
角 | jump_ifp X Y | Xが0以上なら、ラベルY番にジャンプ |
mov命令は、レジスタY番の値を、レジスタX番に上書きする。
add/sub/mul/div命令は、レジスタX番とY番の加減乗除を行う。結果はX番に上書きされる。div命令の結果は小数になり得ることに注意。mod命令は、レジスタX番の値をY番の値で割った余りをX番に書き込む。
push命令は、レジスタX番の値をスタックにプッシュする。pop命令は、スタックからポップした値をレジスタX番に書き込む。
putc命令は、レジスタX番の値を文字コードとしてもつ文字を標準出力に出力する。putn命令は、レジスタX番の値を数値として出力する。
jump_if命令は、レジスタX番の値が0以外ならレジスタY番の値をもつラベルにジャンプする(つまり、そのラベルの直後の命令から実行を続ける)。
jump_ifp命令は、レジスタX番の値が0以上だった場合にジャンプする。
Rubyによる実装
2010年4月1日現在、ModanShogiはその言語仕様のみが公開されており、実際に動く処理系は用意されていない。そこで本記事では、全世界に先駆け、RubyによるModanShogi処理系「ShogiModan」を実装した。以下のWebサイトからソースコードをダウンロードすることができる。
実行方法
ShogiModanのソースコードをダウンロードし展開したのち、リスト1のプログラムを適当なファイル名(ここではsample.modanとする)にUTF-8で保存し、以下のコマンドを実行する。
画面に「Hello, world!」と表示されるはずである。
実装概要
言語処理系の分類としては、ソースコードを逐次実行するインタプリタ方式、ソースコードを機械語に変換するコンパイラ方式、中間言語にコンパイルしたものを仮想マシン(VM)で実行する中間言語方式の3種類が代表的である。このうち、ShogiModanは中間言語方式を採用している。
中間言語方式の処理系は、さらにスタック型とレジスタ型に分類できる。JVMなど、現代の多くの処理系がスタック型を採用しているが、プログラミング言語LuaのLua VM、Android用のJava VMであるDalivk VM、さまざまな動的言語を実行するParrotなど、レジスタ型の仮想マシンも一部に存在する。
ShogiModanも、レジスタ型VMを採用しているため、各レジスタをCPUのレジスタと対応させ、アセンブリ言語に変換することで、さらなる高速化が見込める。実際に、ModanShogiプログラムから、LLVMのアセンブリコードを出力する拡張が、ujihisa氏の手によって行われている。
ModanShogiの今後
ModanShogiのプログラムは、必ずしも棋譜として正しいことが要求されないため、ありえない駒の移動や、二歩になる打ち駒なども動作するプログラムとして受け入れられてしまう。今後の改定では、不可能な駒の移動や反則をエラーとする機能(Strictモード)が言語仕様に追加される予定である。
また、棋譜をモチーフにしているという特性から、命令数を増やすのが難しいのではないかと思われていたShogiModanだが、「矢倉囲い」「穴熊囲い」など、駒を特定のパターンに沿って並べることで特殊な命令を実行するという奇手が検討されている(図2)。