例題(N-クィーン)


概要

このサンプルプログラムは、オブジェクト操作のインタフェースを用いたプログラム例です。
このプログラムは、N-クィーン問題を解くアプリケーションで、メッセージインタフェースを利用しており、そのKLIC側のインタフェース内部動作を、Java側で確認するプログラムとなっています。この内部動作をJava側に送信するために、オブジェクト操作のインタフェースを利用しています。
KLICで書かれたN-クィーンを解くプログラムをJavaから手続き呼び出しのインタフェースで利用しています。KLIC側では、サーバプログラムとしてJavaのプログラムと接続するのを待ちます。Java側では、N-クィーンのGUIがあり、この中で、盤の大きさを指定すると、KLICのプログラムと接続し、手続き呼び出しのインタフェースを用いて、KLICのプログラムとJavaのプログラムの間で通信を行います。このときのKLIC側のインタフェースの内部状態を、KLIC側でもうひとつのプログラムを動作させて取得し、このデータをオブジェクト操作のインタフェースを用いてJava側のGUIに出力しています。


コンパイル

他のサンプルプログラム同様に、jkディレクトリにあるソースを利用するので、トップディレクトリで、makeしてください。これにより、このサンプルプログラムが利用できるようになります。
プログラムの本体は、sample/queen/の下にありますので、プログラムの実行は、このディレクトリで行います。


ファイル説明


実行方法

まず、Java側のサーバプログラムを起動します。
% java JKServer &
として起動します。次に、KLIC側のサーバプログラムを起動します。
% ./queen &
として実行します。最後にJava側のクライアントプログラムを実行します。
% java Queen
とすれば、Java側のプログラムが起動し、サンプルプログラムが利用できます。
表示されたウィンドウにN-クィーンの解が表示されれます。下のスライダーを動かすことにより、他の解を見ることが出来ます。また、解を得るときに、メッセージインタフェースを利用しており、このときのKLIC側の動作状況が、"Inspector Manager"というタイトルのウィンドウに出力されます。このウィンドウは、KLICのプログラムに最初に接続した時に、自動的に生成されますが、ウィンドウの表示に多少時間がかかる場合があります。


プログラムの説明

このプログラムは、KLICとJavaのプログラム間で、オブジェクト操作のインタフェースを利用してデータをやり取りするサンプルプログラムです。
JavaによるN-クィーンのGUIと、それを解くKLIC側のプログラムがあり、これらが手続き呼び出しのインタフェースを用いて通信しています。KLIC側では、このうちのKLIC側のインタフェース部分の動作を監視しています。そして、このインタフェースの内部動作状況を把握し、そのデータをオブジェクト操作のインタフェースにより、Java側で別に動作しているプログラムで表示させます。
Java側のプログラムは、N-クィーンのGUIを提供するプログラムと、KLIC側の内部動作を表示するためのプログラムの2つが動いています。N-クィーンのGUIは、Queen.javaとQueennCanvas.javaの2つのソースファイルで記述されています。KLIC側の内部動作を表示するためのプログラムは、KLIC側からのメッセージを受け付けるためのプログラムがあり、JKServer.javaがソースファイルです。実際の表示を行うプログラムは、インスペクタと呼び、jkディレクトリにある、Inspector.javaとInspectorManager.javaの2つのソースファイルにあります。
KLIC側のプログラムは、サーバプログラムとして動作しています。Java側から接続されると、2つのプロセスが生成されます。1つは、N-クィーンを解くためのプロセスで、もうひとつは、このプロセスが利用するメッセージインタフェースの動作を取得して、それをJava側のGUIに送るプロセスです。N-クィーンを解くプロセスは、接続されたソケットを用いて、メッセージインタフェースを作成します。このとき、jk:jkE/5を用いて、メッセージインタフェース内部の3つのプロセスの動作状況を取得します。これにより取得した情報は、もう1つのプロセスを通じて、オブジェクト操作のインタフェースを用いてJavaのGUIに表示されます。

N-クィーンのGUI
このプログラムを実行すると1つのウィンドウが開きます。最上部の"Exit"ボタンを押すとこのプログラムが終了します。また、その下のSizeから、盤の大きさを選択できます。値が選択されると、ソケットを作成し、KLIC側のプログラムと接続して、メッセージインタフェースを作成します。そして、手続き呼び出しのインタフェースを用いて解を取得し、GUIに表示させます。その下のキャンバスには、N-クィーンの解が表示されています。解が取得できなかったときはなにも表示されません。一番下にある数字とスライダーは、表示している解を表しています。数字の"/"の左側が現在表示されている解の番号で、右側が解の個数です。表示する解を変更する場合は、スライダーを動かしてください。
N-クィーンの実行画面

インスペクタのGUI
このプログラムは、1つのInspectorクラスのオブジェクトが生成されると、そのデータを表示させるためのウィンドウが開きます。これは、複数のInspectorオブジェクトを管理しており、その中の1つを選択して表示するようになっています。このGUIは、メインプログラムを終了させるまでこれまで生成されたInspectorオブジェクトのデータを表示しています。よって、今回の例では、このGUIを消すためにはJKServerを起動したJavaプログラムを停止させてください。
インスペクタの実行画面

メッセージインタフェースの内部状態の取得
まず、内部状態を取得する場合には、メッセージインタフェースを作成する際に、jk:jk/2ではなくjk:jkE/5を用います。このゴールは、メッセージインタフェース内部の3つのプロセスの動作状況を取得できるゴールです。このゴールは、
jkE -Stream +Sock -InspectorMain -InspectorSpool -InspectorInput
のようになっており、StreamとSockはjk:jk/2と同じですが、InspectorMain, InspectorSpool, InspectorInputには、main, spool, inputのインタフェース内部の3つのプロセスの内部状態を通知するデータが返されます。InspectorMain, InspectorSpool, InspectorInputに設定されるメッセージは、jkinspector:inspector/2に設定するストリームの形式となっています。

内部状態のGUI表示(KLIC側)
インタフェースの状態をJavaのGUIに表示させる部分は、jkinspector:inspecotr/2を利用します。これは、
inspector +InspectorList +JK_Stream
の形をしています。InspectorListにjk:jkEで取得したInspectorMain, InspectorSpool, InspectorInputのうちのいずれか、または複数をリストにして指定します。また、JK_Streamには、監視しているメッセージインタフェースとは別のメッセージインタフェースへのストリームを渡します。例を示すと、
test(NSock1, NSock2) :-
     NSock1 = normal(Sock1), NSock2 = normal(Sock2) |
  jk:jkE(JKS1, Sock1, IM, IS, II),
  jk:jk(JKS2, Sock2),
  JKS2 = [auto_close | Inspector],
  jkinspector:inspector([IM, IS, II], Inspector),
  mainProcess(JKS1).
のようになります。ここで、auto_closeというメッセージをメッセージインタフェースに渡しているのは、監視しているメッセージインタフェースが終了したときに、自動的にインスペクタのためのインタフェースを終了するためです。

InspectorListに渡すデータは、

new +InspectorName -InspectorStream
というデータです。InspectorNameは、監視している対象の名前を識別します。これは、JavaのGUIで識別名として利用されます。InspectorStreamには、以下のデータをストリームで渡します。

例えば次のようになります。

process(Inspector) :-
  Inspecotor = new("A process", Stream),
  Stream = [write("This is a test."), nl, put(f(abc,123), nl].
内部状態のGUI表示(Java側)
インタフェースの状態をJavaのGUIに表示させるプログラムは、Inspector.javaとInspectorManager.javaを利用しています。このクラスのオブジェクトは、jkinspector:inspector/2から生成されます。コンストラクタとして利用されるのは、
public Inspector(String name)
です。nameにはInspectorオブジェクトを識別する名前を指定します。内部状態の表示は、KLIC側からのメソッド呼び出しで行われます。実際に利用されているのは、

の2つです。改行は、insertString("\n")で行われています。