演習5 - くりかえし文の活用(for文、while文) 

5.0 はじめに

 今回は、プログラム独特の文法の一つである、くりかえし文について学びます。 計算機といえば、短い時間に大量の処理を行うことがよく知られた特徴の一つですが、 この一つ一つの処理に対して、やはり一つ一つの文を対応させていたのでは、 プログラムのコードまで大量の容量に膨れ上がってしまいます。 しかし、現実はもちろんそうではなく、 くりかえし文のテクニックを使うと、 数行の記述で、万や億といった途方も無い数の処理の実行を命令することができます。

5.1 for文

「地道なやり方」

 まずは、前回までに学んだ知識のみを用いて、 HTMLのcanvasに、それぞれ異なるサイズの正方形を20個(!!)描いてみましょう。 今回は、全ての正方形の左上の頂点位置を固定し、一辺の長さを5ピクセル(5-200)ずつ増やして描画してみます。 なお、今回の演習も、script要素以外では一切の変更がありません。

- - - - - ソース - - - - - - - - - - - - - - - - - - - - -

(sample5A.html)

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -

(枠線内をクリックすると表示されます。)

(sample5A.html)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

画面に現れた20の四角形に対応して、ソースでもstrokeRectの文が20行分書かれていることがわかります。 実際の作業としては、一つの文を20行分コピペして、第三引数と第四引数の数字をひたすら変更していくといったやり方が正攻法でしょうか。いずれにしても、骨の折れる作業です。このような「地道なやり方」では、数十、数百といったスケールの処理には対応できません。

for文の使い方

 「くりかえし文」をつくるfor文を活用すると、 sample5A.htmlの15-34の全20行は、次のようなわずか3行に圧縮することができます (sample5B.html)

簡単に言うと、この3行の記述の中では、変数iを1から20まで1つずつ増やしながら(1, 2, 3, ...20)、 20回、波括弧内の式が実行されています。

 一般に、for文の括弧内は、以下のように、三つの式をセミコロン(;)で区切る構成となっています。

for(変数の初期化; 繰り返しを持続する条件; 繰り返し毎の変数の増減)
  • 変数の初期化

    変数の初期化の形態は、以下の2種類が考えられます。

    var 変数 = 初期値  //変数がまだ宣言されていない場合
    変数 = 初期値      //既に宣言されている変数を用いる場合
    また、変数としてはiやaやpなどがよく使われます。

  • 繰り返しを持続する条件

    今回のケースでは、i<=20が記されており、iが20以下である限り波括弧内の式を実行するという意味です。 逆に言えば、iが20より大きくなると、for文を打ち切り、for文より後ろの式へと処理を移します。 実は、このような不等式も、プログラムにおいては立派な式の一つであり、 例えば、以下のように変数に不等式の結果を代入することもできます。

    var result =  a <= 20;
    ただし、この場合、resultに代入されるのは数字ではなく、trueかfalseのどちらかです (aが20より小さい場合resultにはtrueが、それ以外の場合はfalseが代入されます)。 true(真)とfalse(偽)のような値は、数値や文字列と区別して論理値あるいはブール値と呼ばれます。 (次の演習の)条件文では、この論理値に基づいて条件の分岐を行います。

    >=のような不等式は比較演算子と呼ばれ、論理値を返す式として一般的なプログラム言語にあらかじめ埋め込まれているものです。 以下に、代表的な比較演算子をあげておきます。

    a == baとbが等しい
    a != baとbが等しくない
    a > baがbより大きい
    a >= baがbに等しいか, より大きい
    a < baがbより小さい
    a <= baがbに等しいか, より小さい


  • 繰り返し毎の変数の増減

    波括弧内の処理を1回実行するたびに、変数をどのように増減するかを記述します。 典型的には今回のようなインクリメント(++、--)が使われます。 前回の復習となりますが、i++は、以下の式を簡略化したものです。

    i = i + 1
    もちろん、i++の代わりに上の式を書いても構いません。

変数は0で初期化する

 補足ですが、今回はわかりやすくiを1で初期化して持続の条件としてi<=20の式を与えましたが、 プログラムでは繰り返し用の変数は0で初期化することが一般的です。 つまり、今回の場合であれば

と書くのが一般的です。

ゼロを始点とする考え方は、プログラムの特徴的な概念の一つです。 私の経験では、くりかえし文の中で、複数の変数同士の関係性を計算する場合(%を使う場合など)、 ゼロを始点とした方が圧倒的にスマートな記述に落とすことができます。 また、(後でとりあげる)プログラムの中での集合構造を表現する配列の添字もゼロを始点としており、 1を始点とすると、結果的に面倒な計算を増やすことになりがちです。 はじめのうちは違和感があるかもしれませんが、皆さんも、まずはこの「ゼロから」記法に従ってみてください。

サンプル

 それでは、for文を用いた使用例を簡単に2つ程。 まずsample5C.htmlでは、正方形の上げ幅を低くして、画面内に描ける図形を35に増やしてみます。 また、初期のサイズ(幅と高さ)をマイナスとしているので、正方形は始点の左上方にも伸びています。

- - - - - ソース - - - - - - - - - - - - - - - - - - - - -

(sample5C.html)

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -

(枠線内をクリックすると表示されます。)

(sample5C.html)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 次に、今度は刻み幅を1にして、100もの正方形をfillRectを使って描画します。 この際、fillStyleで色のアルファ値(透明度)を0.03としますので、 より多く重ねて描かれている場所では不透明となり、 そうでない右辺と下の辺の境界付近では透明度が強くなります。 その結果、全体としてグラデーション効果が得られていることがわかります。

- - - - - ソース - - - - - - - - - - - - - - - - - - - - -

(sample5D.html)

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -

(枠線内をクリックすると表示されます。)

(sample5D.html)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

5.2 for文のネスト

 次のサンプルでは、for文の中にfor文を入れ子にすることによって、 繰り返しの方向を多元化する例について見ていきます。 まずは、ソースと実行結果を確認してください。

- - - - - ソース - - - - - - - - - - - - - - - - - - - - -

(sample5E.html)

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -

(枠線内をクリックすると表示されます。)

(sample5E.html)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 sample5E.htmlの中で、具体的な描画命令に対応する文は、23行目の

context.strokeRect(x,y,size,size);

の一文のみです。 この中で、size(一辺の長さ)は固定されています。 また、2重のfor文の中で、xとyは共に単調に増加していきます。 すなわち、図形の座標を右へ(xの増加)、そして下へずらしながら(yの増加)、 画面の中に満遍なく同じサイズの四角形を埋めていっていることになります。

処理の流れを確認します。まず、19行目でiが0に初期化され、 20行目で以下の計算からxに5が代入されます。

x = ix + 0*itvl (=5)

この状態で、21行目のfor文が実行されますと、 21-23行目では、図形のx座標を(x=5)に固定した状態で、 y座標のみを下にずらしながら(5から104まで、9刻み)、 正方形を描いていくことになります。結果として、 実行結果における、左端の縦に並ぶ12の正方形が描画されます。 この後、再び19行目へと戻り、iが0から1へと増加することに伴い、 xもitvlだけ増加して、描画位置が右方向へと14ピクセルずれます。 同様に、図形のx座標を固定したまま(x=14)で、また21-23行のくりかえし文が実行されます (その結果、左端から2列目の縦に並ぶ正方形群が描画されます。)。 以上の手続きを、iが15になるまで、すなわち図形のx座標が140(=5+15x9)となるまで繰り返します。 これにより、描く位置を右へ下へとずらしながら、 満遍なく二次元の空間の中に正方形を埋めていくことができます。

なお、通常くりかえし文を入れ子とする場合、それぞれのfor文で使用する変数は、 階層が深くなるに従って、(今回のように)i,j,k,..のようにアルファベットを一つ後ろに進めるのが一般的です。 他には、a,b,c,...やp,q,r,...などもよく使われます。

5.3 while文

 for文は、繰り返し回数をあらかじめ指定できる場合に便利でしたが、 一方で、繰り返し回数が実行の段階ではわからず、 「ある条件が満足している間は繰り返す」というような処理にしたい場合には、 以下の書式を持つwhile文を用いるのが便利です。

while(条件式){...}

この書式は、「条件式を満たす限り、波括弧内の処理を繰り返し行う」ことを意味しています。 for文と比べて、括弧内で変数を初期化する必要はありません。

sample5E.htmlでは、 横方向の繰り返し回数と縦方向の繰り返し回数を、 それぞれ(私自身が、正確な計算もせずに適当な数字として)16と12と決めましたが、 右端と下側に隙間が残ってしまい少々不格好です。 while文では、繰り返しの条件式として直接的に、 「四角形の頂点がcanvasの枠内に収まっている」ことを設定することができるので、 これを用いて、正方形がcanvasの境界を横切らないギリギリまで埋まるよう、 sample5E.htmlを新しいファイルに書き換えてみましょう。

- - - - - ソース - - - - - - - - - - - - - - - - - - - - -

(sample5F.html)

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -;

(枠線内をクリックすると表示されます。)

(sample5F.html)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ソースでは、まず19行目で次のようにwhile文が使われています。

while((x+size) < canvas.width){...}

このコードの中で、変数xは、正方形の左側の頂点座標を示すものでした。 x+sizeは、そこから一辺分右にずらす操作となりますので、 正方形の右側のx座標を指しています。 canvas.widthはcanvasの最右端のx座標と等しいため、 このwhile文は、 「正方形がcanvasの右の境界線よりも左側にある限り、...を実行せよ」 ということを意味しています。

23行目のwhile文も同様に、

while((y+size) < canvas.height){...}

「正方形がcanvasの下の境界線よりも上側にある限り、...を実行せよ」を意味しています。

これによって、正方形が、境界線と横切らないギリギリの場所まで正しく描かれていることがわかります。

5.4 グリッド線を一気に引く

 前回の演習で、canvasの領域内にグリッド線を引くコードを書きました (sample4F.html)。 その時点では、縦線のX座標あるいは横線のY座標を、 分割数に応じて一つ一つ変数として登録する必要がありました。 for文を使うと、分割数に関わらず、一気に大量のグリッド線を引くことができます。

(sample5G.html)

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -;

(枠線内をクリックすると表示されます。)

(sample5G.html)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

13行目のlinesumが、縦線(あるいは横線)の総数を意味しており、すなわち、 縦と横を何分割するかを決定します。サンプルでは25となっています。 このとき、縦線の間の隙間(spacex)と横線の間の隙間(spacey)は15-16行で記されているように、 キャンバスの幅(高さ)を分割数で割ることによって得られます。

23-27行のfor文の中では、「x座標をspacex分右にずらして、縦線のパスを引く」という手続きを右端まで繰り返しています。 30-34行のfor文についても同様で、「y座標をspacey分下にずらして、横線のパスを引く」という手続きを下端まで繰り返しています。 なお、31-33行の部分は、23-27行のfor文の中に入れることもできます。

5.5 演習課題

課題1

 原点から、canvasの右端線と下端線に対して等間隔にラインを引くような、プログラム(sample5X.html)を作りなさい。ラインの数、キャンバスの大きさは自由です。参考のため、以下に実行結果を載せておきます。

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -;

(枠線内をクリックすると表示されます。)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

課題2

 課題1でつくったサンプルを基に、canvasの原点だけでなく、全ての頂点が固定点となって双対する辺に対して等間隔な線を引くようなプログラム(sample5Y.html)を作ってください。やはり、ラインの数、キャンパスのサイズは自由です。以下に実行結果を載せておきます(上は各辺あたり40本、下は各辺辺り5本を引いた例)。

- - - - - 実行結果 - - - - - - - - - - - - - - - - - - - -;

(枠線内をクリックすると表示されます。)

Drawing

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Drawing

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-11-20 (火) 13:30:09 (2310d)