%tc05.tex
\chapter{亀を動かすテクニック}
\section{等加速運動}%1
亀をまっすぐ動かすには\verb+
forward +を使えばいいのですが、さて曲線はどうしましょう。次に示すプログラムはさまざまな仰角で亀を
\footnote{本当は砲弾なのですが。}打ち出して自由落下に従わせるといったものです。
\begin{itembox}{Cannon その1}
{%\small
\begin{verbatim}
to Cannon
cg
penup
Shoot 0
end
to Shoot :Theta
setpos [0 -144]
pendown
seth :Theta
Time_goes_by (cos :Theta)(sin :Theta)
if :Theta >= 180 [stop]
Shoot :Theta + 10
end
\end{verbatim}
}%---------end of \small
\end{itembox}
\begin{itembox}{Cannon その2}
{%\small
\begin{verbatim}
to Time_goes_by :Vx :Vy
Set_head :Vx :Vy
forward sqrt (:Vx * :Vx + :Vy * :Vy)
if (abs xcor) > 400 [penup stop]
if ycor + 144 < 0 [penup stop]
Time_goes_by :Vx (:Vy - 0.003)
end
to Set_head :Vx :Vy
if :Vy > 0 [ seth arctan :Vx / :Vy ]
if :Vy < 0 [ seth ((arctan :Vx / :Vy) + 180)]
end
\end{verbatim}
}%------end of \small
\end{itembox}
まず、その2の\verb+
Time_goes_by +を見てみましょう。これはある瞬間で起こるべきことを起こして、次の瞬間を呼んでいます。運動の軌跡が曲線でも、極々短期間でみれば直線運動として近似することができるというわけです。
引数の、\verb+:Vx :Vy +はそれぞれ $x,y$ 方向の速度をあらわしています。
\verb+Set_Head +は下に定義していますが、速度方向に亀を向かせる命令です。
速度ベクトルが$(V_x,V_y) $ のとき、速さは、$\sqrt{{V_x}^2+{V_y}^2}$ですね。
単位時間の間にはこの速さだけ進みます。亀は速度方向に向いているのですから、単に\verb+ forward +すればいいのです。\verb+xcor,ycor
+というのは、亀の位置の$x$座標と$y$座標。画面からはみでそうになったらそこで止めることにしています。差し当たり無難な値にしていますが、画面の大きさによっていろいろと工夫してみて下さい。
さて、次の瞬間ですが自由落下ですから、$x$方向の速度は変りませんが、$y$方向は重力加速度の影響を受けますね。画面にあらわれる運動がきれいになるように重力加速度をあらわす数値 0.003 を選びました。時間とか距離とか、実際のものが画面のどれに当たるのか設定するのは単位の選びかたですから、試行錯誤で現象がきれいに見えるように定数を決めました。
では、その1に戻って、\verb+Shoot
:Theta+は仰角\verb+ :Theta +初速度1で打ち出してから、さらに仰角を10度増した自分自身を呼びます。これで10度ごとに亀が打ち出されていくわけですが、仰角の初期値を0度にしてこれを開始させるのが、
\begin{figure}
\begin{center}
\bmpfile(10cm,75mm){CANNON.BMP}
\caption{Pc Logo による {\rm Cannon}}
\end{center}
\end{figure}
\noindent
\verb+Cannon +です。新しい言葉は、\verb+seth と setpos+それぞれ引数で指定された向きと位置とに亀を動かします。\verb+seth +の引数は、上向きが0で、時計の向きに角度を測ります。方位磁石に書いてある方角に当たります\footnote{逆にいまの亀が向いている方角は、{\rm heading}で得られます。}。\verb+setpos +は
$$[x座標 \vspace{2zw} y座標]$$
をあらわすリストを引数にとります\footnote{矢印キーで亀を動かすことができるようにする \verb+ turtlemove + という命令もあります。}。
\verb+Set_Head +の説明は、その働きをもう説明しましたから省きましょう。逆三角関数を使って無理やり作った感がしますね。あとの問でもうちょっと Logo らしく定義してみましょう。
\section{二体問題}%2
万有引力に従う2つの天体があるときの運動を考えることを二体問題といいます。
太陽と地球、地球と月などの関係は近似的にこれになります。近似的と言ったのは、例えば、惑星とその衛星の運動を考えるとき、隣の惑星とか、恒星とかの影響が実際にはないとは言えないからです。地球と月とアポロ飛行船となると3体問題となりますが、
この解は積分では解けないことが知られています。数値計算によらざるを得ないのです。アポロが月面に軟着陸できたのも、その計算を可能にしたコンピュータが使えたからでしたというのは、1960年代の特徴的な史実と言えます。
さて、Logo では亀に天体のまねをさせてみましょう。まずは、プログラムをみてもらいます。\footnote{
引数をそれぞれ $900 800 1 -60$ などとして実行させます。}
\begin{itembox}{二体問題 その1}
{%\small
\begin{verbatim}
to Two_Body :m2 :m1 :v1 :y1
cg
tell 0
ht C [/* hide turtle */ ]
penup
tell 1
penup
st C [/* show turtle */ ]
setpos ( list 200 :y1 )
left 90
pendown
setc 1 C [/* set pen color blue*/ ]
tell 2
penup
st
setpos [ 0 -10 ]
pendown
setc 2 C [/* Green */ }
Time_goes_by ( - :V1) 0
0 0
C [/* :V1x :V1y :V2x :V2y */]
end
\end{verbatim}
}%-------------end of \small
\end{itembox}
\begin{itembox}{二体問題 その2}
{%\small
\begin{verbatim}
to Time_goes_by :V1x :V1y :V2x :V2y
wait 5
tell 1
make "x1 xcor
make "y1 ycor
Set_head :V1x :V1y
forward sqrt( :V1x * :V1x + :V1y *
:V1y )
if (abs xcor) > 450 [ stop ]
if (abs ycor) > 150 [ stop ]
tell 2
make "x2 xcor
make "y2 ycor
Set_head :V2x :V2y
forward sqrt( :V2x * :V2x + :V2y *
:V2y )
if (abs xcor) > 450 [ stop ]
if (abs ycor) > 200 [ stop ]
tell 0
setpos (list ( :x2 - :x1 ) ( :y2 -
:y1 ) )
make "R sqrt( xcor * xcor + ycor * ycor )
make "Ay ycor / ( (:R ^ 3 ) *
100 )
make "Ax xcor / ( (:R ^ 3 ) *
100 )
Time_goes_by :V1x + :M2 * :Ax
:V1y + :M2 * :Ay
:V2x - :M1 * :Ax
:V2y - :M1 * :Ay
end
to C :Dummy
end
\end{verbatim}
}%------end of \small
\end{itembox}
いくつかの新しい言葉を中心に説明します。二体問題ですから2つの天体をあらわす必要がありますね。そこで、1番目の亀と2番目の亀にその役割をさせます。\verb+tell 1 +は、「おーい亀1号よ」と以降の命令は亀1号に対してなされるようにします。このプログラムでは天体をあらわす1号,2号の他に計算を担当する0号も登場させています。
計算亀は姿をあらわさないように、\verb+ht
= Hide Turtle +、逆に、1号,2号は、\verb+st
= Show Turtle +で姿をあらわすようにしています。計算亀は1号,2号の位置に応じて定数を 0.01 とする万有引力の法則に応じてそれぞれの加速度を計算しています。ベクトル量を自分の位置の位置ベクトルとしていますね。あとは、引数の意味程度しか説明する必要がないようです。\verb+M,V,A +は、動力学の定石通りにそれぞれ質量、速度、加速度をあらわし、それぞれに1号か、2号か、$x$方向か、$y$方向かなどの字を添えています。\\
\begin{figure}
\begin{center}
\bmpfile(10cm,75mm){two_body.bmp}
\caption{Pc Logo による二体問題}
\end{center}
\end{figure}
{\bf (問2−1)}\verb+setc +とは、{\rm SET pen
Color }の意味、引数の色番号に応じて亀の持っているペンの色を変えます。
ところで、プログラム中にそのことを注釈として書き込みました。そう、\verb+C +です。注釈行の仕様は Logo
Writer のマニュアルには記されていませんが、ここではどのように実現させたのでしょう。\\
{\bf (問2−2)}色番号は0から15までの整数です。何色になるか、また、番号はどのように決められているか調べてください。\\
{\bf (問2−3)}Pc Logo では、\verb+setc +は、\verb+setpc +となっています。Logo Writer と互換性を持たせるためには、どのような細工をするべきでしょうか。\\
{\bf (問2−4)}towards は点の座標をあらわすリストを引数として亀がいる位置からその点へもし向くとしらどのような方角になるかを出力とします。これを利用して、\verb+Set_Head +を作りなさい。なお 命令を受けている亀の番号は関数\verb+ who + で出力されます。\\
{\bf (問2−5)}画面からはみでないように適当な位置にきたら実行が止るようにしていますが、動いている時間が長くなるように引数の値を工夫してみてください。\\
{\bf [課題]}ここでは、二体問題を扱いましたが、出てくる天体の数が増えると考えるべき力が急速に増えてしまいます。その工夫をして、$n$体問題が扱えるプログラムを作ってください。
\section{利用者の入力}%3
まず、簡単な例から見てもらいます。
\begin{itembox}{真也君のお留守番}
{%\small
\begin{verbatim}
to Sin_ya
repeat 3 [ insert [# ] wait 60 ]
print "だれですか?
if member? ReadWord [パパ ママ ネータン]
[print "おかえり!いまかぎあけるね。カチャッ。
stop
]
print "いま留守です。
end
to ReadWord
output first readlist
end
\end{verbatim}
}%----end of \small
\end{itembox}
\verb+readlist +はそれ以降でリターンキーが押されるまでのキー入力をリストとして出力とします。しかしこの例題の場合はキー入力をワードとしたいので、\verb+ReadWord +を作りました。要素がひとつしかないリストなので\verb+ first +を使えば充分ですね\footnote{逆にワードからそれだけを要素に持つリストを作るには{\rm parse}です。}。
しかし、これではいちいちリターンキーを押さないと入力ができないので、ゲームなどを作る場合は操作性が悪くなってしまいます。\verb+readchar +は、それ以降に入力された1文字を出力します。また、\verb+key? +は、キーが押されたかどうかを出力します。次のプログラムは、リターンキーが押されるまで押されているキーのアスキーコードをページに書くものです。
\begin{itembox}{キャラクターコード調べ}
\begin{verbatim}
to TestKey
local "k
if key?
[ make "k ( charcode readchar )
if :k = 13 [stop]
print :k
]
TestKey
end
\end{verbatim}
\end{itembox}
\\
{\bf (問3−1)}リターンキーのアスキーコードは何でしょう。\\
{\bf (問3−2)}矢印キーやスペースバーをあらわすアスキーコードを上のプログラムで調べてください。
\section{ダイナタートル}%4
\noindent
{\bf (問4−1)}左向き,右向きの矢印キーを押すとそれぞれ左や右へ90度亀の向きを変えて、上向きの矢印キーを押すと亀を10歩前に進めることをリターンキーが押されるまで続けるプログラムを書きなさい。\\
{\bf (問4−2)}上のものは物理的には正しくなくて、本当は上向きの矢印で亀が向いている方向に1加速度を増やすべきです。このように前問のプログラムを改良してください。\\
{\bf (問4−3) (問4−2)}のようなテクニックを応用すれば、ニュートン力学に理想的に従う摩擦がない世界のシミュレーションが行なえます。\\
{\bf (1)}ダイナトラックは、原点を中心とする2つの円に囲まれた領域をトラックとして亀を動かし、円にぶつからずに何秒動かし続けることができるかを競うゲームです。作って見ませんか?\\
{\bf (2)}地球から月に人工衛星を飛ばして軟着陸させます。軟着陸とは適当な速度以下で月にぶつかることですね。人工衛星は地球と月から万有引力を及ぼされていますが、地球と月はともに不動であるとします。\\
{\bf (問4−4)}ゲーム作りのヒントをもうひとつ。MS-DOS
Ver.5.0 の英語版に
Quick Basic が付いていてそのデモプログラムにゴリラというゲームがありました。
2匹のゴリラがニューヨークは摩天楼街にあらわれて交互にバナナを投げあうというものです。もちろん相手に早くバナナを当てた方が勝ち。プレーヤーはバナナの初速度を投げる仰角を指定します。また風速とゴリラのいる、あるいは、ゴリラの間にあるビルの高さは乱数で決まります。\\
{\bf (問4−5)}上にあげたようなゲームを物理の授業などに取り入れることの教育的な意義について考えて下さい。\vfill
\noindent
【参考になる文献のメモ】\\
{\bf(1)}H.Abelson,A.A.diSessa,1980“Turtle Geometry-----The Computer as a Medium for Exploring
Mathematics”(M.I.T. Press)pp.53-77 に亀に「羊と狼」など他の役割を担わせる例が出ています。\\
{\bf (2)}H.Abelson/五藤博義,1985『Logo-----エーベルソンの Logo 入門』(啓学出版)の第7章,第9章では、それぞれ、ここと次章に紹介するプログラムがかなり具体的に紹介されていますが、残念ながら本の入手が難しくなっています。\\
{\bf (3)}Pc Logo for Windows ver.2.0 をインストールすると、\verb+\PCLOGO20\game +というディレクトリに \verb+ ANIMAL.LGO,DYNATRAK.LGO +が生じます。\\
{\bf (4)}小谷善行,1984『パソコンLOGOプログラミング』(東海大学出版会)は、日本語でかかれたLogoの本が数あるなかでのロングセラーとしてお勧めできる本です。巨大数などの具体的なプログラム例を見ることができます。\\
{\bf (5)}小谷善行「LOGO」(石田晴久(監修),1984『パソコン言語学』(アスキー出版局)所収)は、コンパクトにまとめられた紹介で他の言語との比較ができます。\newpage
\section{曲線を描く}
これまでに描いてきた曲線は物理的な法則に従うという点で亀に役割を担わせることで描きやすいものでした。ここでは、幾つかの例題を使って曲線を描くあの手この手を紹介します。
\subsection{デカルトの正葉線}
次のプログラムは第1,第2の引数であらわされた $ x , y $ の範囲で、第3の引数である $ x , y $ に関する式の正領域と負領域とを色分けします。第4の値は、曲線を描くきめの粗さをあらわします。
方程式 $ x^3 + y^3 - 3xy =
0 $ で表される曲線は自分自身と交差するので亀を動かすことでは描きにくいのですが、このプログラムでは、
\begin{center}
\begin{verbatim} InKansuu [-1 3 ] [1 2] [:x
^ 3 + :y ^ 3 - 3 * x * y ] 5
\end{verbatim}
\end{center}
で描くことができます。
\begin{figure}
\begin{center}
\bmpfile(8cm,6cm){descarte.bmp}
\caption{デカルトの正葉線}
\end{center}
\end{figure}
{%\small
\begin{verbatim}
-------------------
to InKansuu :X_Range :Y_Range :Shiki :Step
cg
penup
setc 1
setpos [ -160 120 ]
seth
90
Walk
Axis
end
to Walk
make "x ValueX :X_Range
make "y ValueY :Y_Range
make "Value ( run :Shiki )
if :Value > 0 [ pendown ]
if :Value < 0 [ penup ]
forward :Step
if
xcor > 160
[ right 90
forward :Step
right 90
]
if xcor < -160
[ left 90
forward :Step
left 90
]
if ycor < -120 [stop]
Walk
end
to ValueX :L
output ( ( last :L ) - ( first :L ) ) * ( xcor + 160 )
/ 320 + ( first :L )
end
to ValueY :L
output ( ( last :L ) - ( first :L ) ) * ( ycor + 120 )
/ 240 + ( first :L )
end
to Axis
setc 2
penup
if ( abs ZeroY :Y_Range ) < 120
[ setpos (list -165 ZeroY :Y_Range )
pendown
seth 90
forward 330
penup
]
if ( abs ZeroX :X_Range ) < 160
[ setpos (list ZeroX :X_Range -125 )
pendown
seth 0
forward 250
penup
]
setc 1
ht
end
to ZeroX :L
output ( first :L ) * ( -320 ) / ( ( last :L ) - (
first :L ) ) - 160
end
to ZeroY :L
output (
first :L ) * ( -240 ) / ( ( last :L ) - ( first :L ) ) - 120
end
--------------------
\end{verbatim}
}%----------end of \small
\subsection{包絡線}
\begin{figure}
\begin{center}
\bmpfile(8cm,6cm){houraku.bmp}
\caption{包絡線}
\end{center}
\end{figure}
20本の線分を使って曲線を描いてみます\footnote{このようないろいろな曲線の書き方については、Jon Millington,1989“Curve Stitching”(Tarquin) が参考になります。}。
{%\small
\begin{verbatim}
to Houraku
cg st
make "k 0
repeat 20
[ DrawSeg :k
make "k ( :k + 1 )
]
end
to DrawSeg :k
Segment ( list -120 ( :k * 12 - 120) ) ( list ( 120 -
:k * 12 ) -120 )
end
to Segment :a :b
show (list :a :b )
penup
setpos :a
pendown
seth towards :b
forward distance :b
end
-------------------
\end{verbatim}
}%-----end of \small
\verb+ Segment :a :b +では、はじめの引数で座標があらわされている点Aから、次の
引数で座標があらわされている点Bまでの線分を引きます。新しい言葉は、\verb+ distance +です。これは座標が引数としてあらわされた点までの距離を亀に答えさせます。ごく短いプログラムですがきれいな図が得られます。
\subsection{漸化式であらわされた数列の収束}
直前の項のみによって次々に項が決められている、即ち、$ a_{n+1}=f(a_n) $ となっているとき、この $f のグラフ y=f(x)$ をかいてみましょう。また、この数列が極限値$\alpha$を持つとき、$$ a_{n+1}
\rightarrow \alpha ,~~~~~ a_n \rightarrow \alpha $$
ですから、$ y = x , y = f( x
) $ の交点の$x$座標となります。
さて、どのように値が収束するか、
$$(a_1,0),(a_1,a_2),(a_2,a_2),(a_2,a_3),(a_3,a_3),(a_3,a_4),\cdots$$
の順に亀をたどらせて見てください。2つのグラフ$
y = x , y = f( x ) $もかきいれてください。場合によっては速すぎて何だがわからない
ことがあります。動作の度ごとに、スペースバーを押す必要があるなど
利用者の入力が必要なようにすると良いでしょう。また、座標の値をコマンドセンターに表示するなどすると、よりわかりやすくなりますね。
\begin{figure}
\begin{center}
\bmpfile(8cm,6cm){shusoku.bmp}
\caption{漸化式であらわされた数列の収束}
\end{center}
\end{figure}
ただし、$f$をあらわす$x$に関する式は、リストの形で第1の引数で、グラフをかく範囲を第2、第3の引数で、初期値は第4の引数で指定できるようにしましょう。\newpage
{%\small
\begin{verbatim}
--------------------------
to Shusoku :Siki :RangeX :RangeY :x0
cg
Graph [ 0
] 2
Graph [ :x ] 4
Graph :Siki
4
setc 1 penup
setpos ( list GetX_Cor :x0 GetY_Cor 0 ) pendown
Walk :x0
end
to Graph :Siki :Color
local [ x y Y_cor ]
penup
setc :Color
setpos (list -160 0 )
repeat 320
[ make "x GetX ( xcor + 1 )
make "y run :Siki
make "Y_cor GetY_Cor :y
if (abs :Y_cor) > 120
[ penup ]
if (abs :Y_cor) <= 120
[ setpos
( list ( xcor + 1 ) :Y_cor
)
pendown
]
]
end
to Walk :x
local "y
make "y run :Siki
if readchar = "q
[ penup
forward 50
pendown
stop
]
DrawTo ( list :x :y )
show
( list :x :y )
DrawTo ( list :y :y )
Walk :y
end
to DrawTo :p
local [ x y pos ]
make "x first :p
make "y last :p
make "pos
( list GetX_Cor :x GetY_Cor :y )
seth towards :pos
forward distance :pos
end
to GetX_Cor :x
local [ x1 x2 z ]
make "x1 first :RangeX
make "z ( :x - :x1 )
make "x2 last :RangeX
make "z :z / ( :x2 - :x1 )
output
320 * :z - 160
end
to GetY_Cor :y
local [ y1 y2 z ]
make "y1 first :RangeY
make "z ( :y - :y1 )
make "y2 last :RangeY
make "z :z / ( :y2 - :y1 )
output
240 * :z - 120
end
to GetX :x_cor
local [ x1 x2 xc z ]
make "x1 first :RangeX
make "x2 last :RangeX
make "z
( :x2 - :x1 ) / 320
make "z
:z * ( :x_cor + 160 )
output :x1 + :z
end
-------------------------------------
\end{verbatim}
}%----------------end of \small
\newpage