2025年6月14日(土) 11:11 JST

コッホ曲線

  • 2009年2月 4日(水) 12:34 JST
  • 投稿者:

ハノイの塔もナイト・ツアーも、有名なパズルはその計算量が半端じゃないですね。Prologだと直感的にプログラムが書けるのはよいですが、成果の確認に余計な手間が掛かることがあります。結果を待っている間にC/C++で書き直せそうです(笑)。新しいパズルへの挑戦はひと休みにして、グラフィックにPrologが使えるか、ちょっと考えてみました。

最近、建築の世界ではアルゴリズミックデザインという言葉が流行っています。どうして今頃流行るのか理由は定かでないですが、うちの研究室でもfDLAなんてものを考案していろいろ試行錯誤しています。fDLAについては、このリンク先をご覧ください。


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

今回はフラクタル(非線形科学)の話では必ず出てくるコッホ曲線をPrologで描いてみましょう。コッホ曲線の場合Prologで描くメリットは実はほとんどありません。C言語でリカーシブコールを使うのはごく簡単なので。たとえば、n!を求めるプログラムを思い出してください。

とはいうものの、せっかく作ったので、もしかしたらこういうものでもお役に立つかもしれないと思い記事にしました。以下のコードを参考にいろいろとルールを取っ替え引っ替えして変わった模様を作ってみてください。

フラクタル図形を書くときに、膨張型と収縮型いずれを採用するかですが、今回のサンプルプログラムは収縮型です。最初に与えた基本図形が複数のより小さい基本図形に再構成されていきます。うちの研究室ではこの様子を精緻化のプロセスと勝手に呼んでいます。できあがる図形は最初に与えた図形の大きさとほぼ同じになるので、縦横のサイズが決まっている領域をフラクタル図形で埋める場合には、領域内外の判定を不要にできる分、膨張型に比べて一手間省けます。

ところで、assert/1, retract/1を多用するのは速度的に問題があるから云々、は分かっているのですが、RDBに慣れ過ぎちゃったんでしょうね、この辺への抵抗はなくなってしまいました。速度が厳しい場合はsetval系述語の使用を検討するのがよいと思います。次回以降の記事ではsetval系のグローバル変数をたくさん使うことになるでしょうが、今回は使っていません。

もう一点。XPCEの座標系はY軸下向きが正なので、角度の与え方を反転させています。

%
% koch.pl
% HLAB(C) 2009
%

:- encoding(utf8).
:- new(@w, picture('コッホ曲線')), send(@w, open).

:- dynamic(line/3).

go :- koch(3).

generator(p(Xa,Ya),p(Xb,Yb),p(Xc,Yc),p(Xd,Yd),p(Xe,Ye)) :-
Vx is Xb - Xa,
Vy is Yb - Ya,
Nx is Vx / 3.0,
Ny is Vy / 3.0,
Xc is Xa + Nx,
Yc is Ya + Ny,
Xe is Xa + 2.0 * Nx,
Ye is Ya + 2.0 * Ny,
Theta is - pi * 60.0/180.0,
Xd is Xc + Nx * cos(Theta) - Ny * sin(Theta),
Yd is Yc + Nx * sin(Theta) + Ny * cos(Theta).

generator(p(Xa,Ya),p(Xb,Yb),p(Xc,Yc),p(Xd,Yd),p(Xe,Ye),p(Xf,Yf)) :-
Vx is Xb - Xa,
Vy is Yb - Ya,
Nx is Vx / 3.0,
Ny is Vy / 3.0,
Xc is Xa + Nx,
Yc is Ya + Ny,
Xf is Xa + 2.0 * Nx,
Yf is Ya + 2.0 * Ny,
Theta is - pi * 90.0/180.0,
Xd is Xc + Nx * cos(Theta) - Ny * sin(Theta),
Yd is Yc + Nx * sin(Theta) + Ny * cos(Theta),
Xe is Xd + Nx,
Ye is Yd + Ny.

line(0,p(100,100),p(300,100)).
line(0,p(300,100),p(200,270)).
line(0,p(200,270),p(100,100)).
line(0,p(300,100),p(100,100)).
line(0,p(200,270),p(300,100)).
line(0,p(100,100),p(200,270)).

koch(N) :-
between(1, N, Nth), koch0(Nth), fail.
koch(N) :-
line(N,p(X1,Y1),p(X2,Y2)),
send(@w, display,
new(Handle, line(X1,Y1,X2,Y2,none))),
fail.
koch(N) :-
send(@w, flush).

koch0(Nth) :-
Prev is Nth - 1,
retract(line(Prev,Pa,Pb)),
generator(Pa,Pb,Pc,Pd,Pe),
assert(line(Nth, Pa, Pc)),
assert(line(Nth, Pc, Pd)),
assert(line(Nth, Pd, Pe)),
assert(line(Nth, Pe, Pb)),
fail.
koch0(Nth).

以下のコメントは、その投稿者が所有するものでサイト管理者はコメントに関する責任を負いません。