Copyright (C) 2000 DaiichiGakushusha Corporation. All Rights Reserved.
連載 JavaScript実習講座
第1回 JavaScriptによるシミュレューション
エデュカーレNo.13 より
筑波大学大学院教授 久野 靖
第1回 シミュレューション
 <INDEX>
第2回ゲーム作成
第3回ウェブページの工夫
 昨年度,「JavaScript入門講座」を3回にわたって連載させていただいたが,今年度は「JavaScript実習講座」を同じく3回にわたってお届けする。その主旨は,「情報B」の授業の一環としてJavaScriptを用いた実習をおこなうときのために,参考となる活用例を示すことである。まず最初に,全体的な考え方を説明させていただこう。
 「情報B」の授業では,コンピュータの原理やアルゴリズムの考え方を学ぶ過程において,これらの題材を実際にプログラミングして体験させることが,高校生の理解を深める上で有効である。前回の連載では,そのような方向でJavaScriptを活用することについて取り上げた。
 しかし,プログラミング学習をより有効に活用するには,さらにその先,つまり高校生が「こういうことはプログラムを書けばできるな」と感じたときに,自分でプログラムをつくってそれを実現できるようにしてやるのが一番望ましい。そのようにして一人立ちできた高校生は,自分が興味をもったさまざまなテーマを自発的に探求し,考える力をみずから養っていけるはずである。
 このような考えにもとづき,今回の連載では「情報B」のカリキュラムにあらわれる複数のテーマについて,その学習にプログラミングを組み合わせるような授業の題材を提案していく。
 先生方には,これらの題材をもとにした内容を,自分のクラスの授業進行にうまく組みこむことにより,高校生に「プログラミングは一度学んだら終わりではなく,さまざまな場面に活用できるのだな」と思わせるような扱いをぜひともお願いしたい。
※今回の連載では,前回の「JavaScript入門講座」相当の内容を一通り理解していることを前提にしている。もしも高校生がこれらの内容をすべて終えていない場合は,必要に応じて「JavaScript入門講座」相当の内容に立ちもどった説明や実習を組み合わせるようにして,高校生がとまどわないように配慮していただきたい。
 シミュレーションとは,実際にものを動かしたり実験したりするかわりに,小規模な模型を使ったり,コンピュータの上で計算したりして,起こることの「真似」をおこない,結果を予測する手法をいう(simulationは「真似する」という意味の英語。similarは「似ている」という意味。決して「シュミレーション」ではないので注意)。
 簡単な計算によるシミュレーションであれば, 筆算や電卓で計算することができる。しかし, 同じ規則で何回も計算を繰り返すことになるので飽きてしまいやすいし,手順を間違えてうまく結果が得られないこともある。
 シミュレーションをおこなう専用のソフトウェアも多数ある。しかし, 特定目的向けの高度なものが多いことと, シミュレーションそのものはうまく実行できても,その中でどのように計算が進んでいるのかの原理は高校生にわかりづらい, という問題がある。
 表計算ソフトウェアを用いたシミュレーションの計算も, 授業で多くおこなわれる。これは高校生が表計算ソフトウェアに習熟していれば便利な方法の1 つだが, 計算の手順がセルの計算式程度におさまる必要があり, また結果の提示方法がセルの数値か表計算ソフトウェアの提供するグラフ程度しかないという弱点もある。
 これに対し, 自分でプログラムを書いてシミュレーションをおこなう場合は, 計算の手順(繰り返しなど) もプログラムに含まれるので原理が理解しやすく, 自分の能力の範囲内であれば, こみ入った計算規則や多様な結果の提示方法も扱えるという利点がある。今回はこれを取り上げることにする。
 いよいよ,プログラムによる時間進行型のシミュレーションを扱ってみよう。その基本的な考え方は次のようなものである。
・真似する対象の注目点をあらわすような数値などのデータ(1つの値であることも,一群の値であることもある) とその初期値を定める。
・ある一定の時間がたつと,そのデータがどのように変化するかの規則を定める。
・初期値に対して,定めた一定時間後の計算をおこない,その時点でのデータの値を定める。
・そのデータの値をもとに,さらに一定時間後の計算をおこない,その時点でのデータの値を定める。
・以上を繰り返すことにより,必要な範囲でのデータの変化のシミュレーションがおこなえる。
 具体例として, 簡単なローンの計算をJavaScript で記述してみよう。ここでは先に説明した一定時間として「1年」を用いることにして, 年単位で計算を進める。シミュレーションの規則は次の通りとする。
・借り入れ金額は100万円とする。
・金利はx%に固定とする。返済額はm万円に固定とする。
・毎年,利息額(借り入れ残高のx%)だけ残高が増え,そこから返済額m万円を引いたものが翌年の残高になる。
・最大30年間にわたって計算する。ただし残高が0になればそこで打ち切る。
 この規則をJavaScript であらわしたものをプログラム[1]に示す。
プログラム[1]

<script>
a = 100;								//(1)
x = parseFloat(prompt('100万円借り入れ。金利(%) を入力してください'));	//(2)
m = parseFloat(prompt('毎年返済額(万円) を入力してください'));		//(3)
for(i=1; i<=30 ;++i){							//(4)
	a = a + ( a * 0.01 * x ) - m					// :
	document.write( i + '年目の借り入れ残高:' + a + '万円<br>');	// :
}									// :
</script>


(1)借り入れ残高を変数 a であらわすこととし,初期値100とする。
(2)金利(%) を数値で読みこみ,変数 x に入れる。
(3)返済額(万円) を数値で読みこみ,変数 m に入れる。
(4)変数 i を1から30まで1ずつ増やしながら繰り返す。繰り返しの中では,上で説明した規則で残高を計算し,年数 i と残高 a を書き出す。書き出した後,残高が0以下になっていたら,i を31にする(繰り返しを終わりにさせるため)。

演習1
プログラム[1]を参考にして, 次のような積み立て貯金のシミュレーションをおこなうプログラムを作成しよう。
・貯金残高は最初0万円とする。
・金利は x % に固定,積み立て額は m 万円に固定とする。
・毎年利息額(貯金残高の x %)だけ残高が増え,そこに積み立て額m万円を加えたものが翌年の残高になる。
・30年間にわたって計算する。
 シミュレーションの結果を理解しやすくするには,数字だけで表示するよりも,グラフなどで視覚に訴えるようにするとよい。JavaScript では,HTML の要素の色,形,配置を制御できるので,これを利用して棒グラフのようなものをつくってみよう。基本的な考え方は次の通り。
・1つ1つの「棒」をHTMLの div 要素 <div>…</div> であらわす。
・それぞれの div 要素を書き出すときに,「p1」「p2」…という ID をつける。
・それぞれの div 要素を JavaScript 側で操作できるように取り出し,色・枠・幅を設定する。
 これをJavaScript であらわしたものをプログラム[2]に示す。
プログラム[2]

<script>
a = 100;
x = parseFloat(prompt('100万円借り入れ。金利(%) を入力してください'));
m = parseFloat(prompt('毎年返済額(万円) を入力してください'));
for(i=1; i<=30 ;++i){							//(1)
	a = a + ( a * 0.01 * x ) - m					// :
	if( a<0 ) a = 0 ;						//(2)
	document.write( '<div id="p' + i + '">.<\/div>');		//(3)
	box = document.getElementById('p'+i);				//(4)
	box.style.overflow = 'hidden';					// :
	box.style.backgroundColor = 'yellow';				// :
	box.style.border = 'blue solid 2px';				// :
	box.style.width = ( a*4 )+'px';					// :
	if( a<=0 ) i = 31;
}
</script>


(1)金額の計算の部分は,プログラム[1]と同じである。
(2)棒グラフでは,金額がマイナスのとき「マイナスの幅」の表示はできないので, a の値がマイナスのときは 0 に書きかえてから表示をおこなう。
(3)表示する「棒」は <div id='p1'>.</div> のようなものを document.write() で書き出す。’p’ という文字列と変数 i の値を「+」で連結することで,’p1’,’p2’ …のように順次別の ID 名をもつものが生成できる。divの中に「.」が入っているのは,div要素に何も中身がないと表示がおこなわれないためである。
(4)(3)の後に document.getElementById() を使って,この div 要素のデータを変数 box に取り出し,次の設定をおこなう。
・style.overflow=’hidden’
中身が div 要素の大きさより大きい場合は,その中身を表示しない(隠す)。
・style.backgroundColor=’yellow’
div 要素の内側の背景を黄色にする。
・style.border=’blue solid 2px’
div 要素の縁を幅2ピクセルの青線にする。
・style.width=(a*4)+’px’
div要素の幅をaの4倍のピクセル数にする。
 これにより,各年の残高に対応した幅をもつ箱が並んだ「棒グラフ」が表示できる。

演習2
演習1でつくったプログラムも,結果を棒グラフで表示するように変更して動かしてみよう。
 今度は別の例題として,ゴム紐をつけたボールの動きを取り上げてみよう。画面にはA,B2つの四角形があらわれ,それぞれ次のような役割を果たす。
 A…「手でもつところ」であり,マウスポインタをその上にもっていって移動することで動かせる。
 B…「ボール」で,Aとゴム紐でつながっている。ゴム紐は見えないくらい細いものとする。
 Bの座標 Y と動く速さ V を,0.1 秒(100ミリ秒)の時間間隔で次のようにして計算する(これがシミュレーションの規則になる)。F はゴム紐の強さをあらわす定数,G は重力の強さをあらわす定数になる。
 速度:V’= V - F * ゴム紐の伸び + G
    V’= V + G (伸びがない場合)
 位置:Y’= Y + 0.1 * V
 
 つまり,ある時点の V と Y から 0.1 秒後の V’と Y’を計算し,これをずっと続けていくことでボールの動きをシミュレーションし続ける。これを JavaScript であらわしたものをプログラム[3]に示す。
プログラム[3]

<script>
	document.write('<div id="a1">A<\/div>');		//(1)
	a = document.getElementById('a1');			//(2)
	a.style.backgroundColor = 'pink';			// :
	a.style.position = 'absolute';				// :
	a.style.width = '20px';					// :
	a.style.height = '20px';				// :
	a.style.left = '100px';					// :
	a.style.top = '100px';					// :
	ay = 100;						//(3)
	function apos(e){					//(4)
		if(window.event) ay=window.event.clientY;	// :
		else		ay = e.pageY;			// :
		a.style.top = ( ay - 10 ) + 'px';		// :
	}							// :
	a.onmousemove = apos;					//(5)
	
	document.write('<div id="b1">B<\/div>');		//(1)
	b = document.getElementById('b1');			//(2)
	b.style.backgroundColor = 'purple';			// :
	b.style.position = 'absolute';				// :
	b.style.width = '20px';					// :
	b.style.height = '20px';				// :
	b.style.left = '100px';					// :
	b.style.top = '200px';					// :
	by = 200;						//(3)
	len = 100;
	f = 2;
	vy = 0;
	g = 10;

	function bpos(){					//(6)
		if(by-ay-len>0) vy = vy - (by-ay-len) * f + g;	// :
		else	vy = vy + g				// :
		by = by + 0.1 * vy ;				// :
		b.style.top = ( by - 10 ) + 'px';		// :
	}							// :
	setInterval(bpos,100);					// :
</script>


(1)A ,B とも div 要素であらわすので,まず document.write() で HTML の div 要素を書き出す。
(2)(1)のデータを変数 a ,b に取得して,色・幅・高さ・ XY 座標を設定する。
(3)Y 座標は計算でも使うので,変数 ay,by に入れる。
(4)A の上でマウスが動いたときはそのマウスの座標を ay とし,四角形の中心が ay になるように移動する。
(5)動作は関数 apos() として実現させ,onmousemove ハンドラとして設定することでマウスが動いたときに起動されるようにする。
※ブラウザによってマウスの Y 座標を取り出す方法が2通りあるので,if文によって枝分かれしている。もし window.event というデータがあるようなブラウザであれば,Y 座標は window.event. clientY に格納されている。そうでなければ,onmousemove ハンドラにパラメタが渡され(ここでは「 e 」という名前で受けている),その中の pageY というプロパティ(付随データ)が Y 座標になる。
(6) B では,その位置を計算する関数 bpos() を,100ミリ秒間隔で呼び出し,その中で次々に位置を計算して四角形の位置を動かしている。動かす計算式は上で説明した通り。ゴム紐の現在の長さは by−ay で,そこからゴム紐の長さ len を引いたものが伸びになる。伸びがマイナスかどうかで V の計算式は変わるので,if で切り替えている。
※BがAの上にあって,その距離がもともとのバネの長さよりも長い場合は,本来ならバネの力が働く方が自然であるが,例題プログラムではそこまで対応していない。そのように対応させるのもよい演習問題である。

演習3
プログラム[3]の F の値を変更してどう変わるかを観察してみよう。実際にゴム紐(輪ゴムを切ってつなぐ)で適当なボールをつるし,ゴム紐の強さを変える(2本,3本とたばねる)のと結果が同じかどうかも調べてみよう。

演習4
現在は抵抗がなくいつまでもボールが動いているが,摩擦抵抗を入れてボールが次第にゆっくりになるようにしてみよう(ヒント:速度に0.99などの値を乗じて小さくする)。また,床や天井をつくってはね返らせてみてもよい。