XPCE/Prolog ~ ハノイの塔 2D

ハノイの塔の3D版を前回紹介しました。SWI-Prolog関連のドキュメントは割としっかりしていて、XPCE/PrologというSWI-Prolog専用(?)のGUI構築開発環境についても詳しい解説が用意されています。今回はこのXPCE/Prologを試してみました。


(全部読むには 全文表示 をクリックしてください。)

XPCE/PrologではウインドウやボタンなどのさまざまなGUIウィジットがPrologだけで書けます。少し変わっていると思えるのは、長方形や円のような単純な図形の描画でもPrologのデータベース機能が使われているのでしょう、図形のハンドルを指定して位置やサイズなどのフィーチャーを後で変更できます。VisioのVBAを触ったことがある方はあの感じを想像してもらえばよいです。もちろんこちらはPrologでVisioはBasicですから見た目は全く違いますが。

さて、前回のハノイの塔を例題にすると、一度円盤を描いたらその後は位置を変えてあげればよいわけです。円盤1枚あたりdrawは一回のみで、あとは必要なだけmoveを行えばよいのです。Win32での描画のように、円盤を移動した後の処理をプログラムで処理しないといけないならば、移動対象の円盤が軸の最下部にあるかそうでないかで処理が変わるとかいろいろと考えなければならないですがその必要はありません。また、登録(描画)した図形の順番通りに図形相互の前面後面関係も保持していますので、軸内での円盤の上下関係を処理しなくても大丈夫です。小円盤が大円盤に隠されてしまうこともありません。まあWin32ならややこしいこと考えずにフレーム毎にシーン全部を書き換えてしまうでしょうが。

ということで、以下が試しに書いたソースです。上述のXPCE/Prologの特性をうまく利用しているつもりです。興味のある方はどうぞお試しください。hanoi/1を繰り返し試したい場合は、初期化の部分を工夫してください。(具体的には前回実行時の軸と円盤のデータを削除します)。

円盤10枚の解:アニメーション効果を付加した動画デモ(H264)
(コーデックはH264です。H264のデコーダはffdshow等に含まれています。)

%
% Hanoi 2D  
% hlab, 2009 
% 

:- dynamic(pole/3). 
:- new(@p, picture('Hanoi 2D')), send(@p, open).  

go :- hanoi(14).  %←この数字で円盤の数を変える 大きいとメモリが足りなくなります  

kazu(1,@one). 
kazu(2,@two). 
kazu(3,@three). 
kazu(4,@four). 
kazu(5,@five). 
kazu(6,@six). 
kazu(7,@seven). 
kazu(8,@eight). 
kazu(9,@nine). 
kazu(10,@ten). 
kazu(11,@eleven). 
kazu(12,@twelve). 
kazu(13,@thirteen). 
kazu(14,@fourteen). 
kazu(15,@fifteen). 
kazu(16,@sixteen). 
kazu(17,@seventeen). 
kazu(18,@eighteen). 
kazu(19,@nineteen). 
kazu(20,@twenty).  % 20枚まで対応。これ以上が必要なら定義してください。

hanoi(N) :-
 	setupPoles(N),
 	placeDiscsInit(N),
 	X='left', Y='middle', Z='right',
 	placement(N,X,Y,Z).

setupPoles(N) :-
 	N > 2,
 	Y  is N * 10 + 2,
 	X1 is N * 10 + 2,
 	X2 is N * 10 + X1,
 	X3 is N * 10 + X2,
 	assert(pole('left', X1, Y)),
 	assert(pole('middle', X2, Y)),
 	assert(pole('right', X3, Y)).

placeDiscsInit(0). 
placeDiscsInit(N) :-
 	pole('left', X, Y),
 	placeDisc(N, X, Y),
 	N1 is N - 1,
 	placeDiscsInit(N1). 
placeDisc(N, X, Y) :-
 	kazu(N, Handle),
 	R is 10 * N,
 	X1 is X - R/2,
 	Y1 is Y - R/2,
 	send(@p, display, new(Handle, circle(10*N)), point(X1,Y1)),
 	send(Handle, fill_pattern, colour(gold)).  

move(N, X, Z) :-
 	kazu(N, Handle),
 	pole(Z, Xnew, Ynew),
 	R is 10 * N,
 	Xnew1 is Xnew - R/2,
 	Ynew1 is Ynew - R/2,
 	send(Handle, move, point(Xnew1, Ynew1)),
 	send(Handle, flush),
 	write(N), write('th disk '),
 	write(X), write('  to '),
 	write(Z), write('.'), nl,
 	%sleep(0.5), %←ゆっくり鑑賞したい場合はこの行を生かす
 	true.  

placement(0,X,Y,Z) :- !. 
placement(1,X,Y,Z) :- move(1,X,Z). 
placement(N,X,Y,Z) :-
 	N1 is N - 1,
 	placement(N1,X,Z,Y),
 	move(N,X,Z),
 	placement(N1,Y,X,Z).

コメント (0件)


HLAB
http://www.hlab-arch.jp/article.php/20090111185530493