2.5 while, for文の理解

繰り返し処理の代表的な例である、while文for文を勉強しましょう。これが分かると、表現できるグラフィックのバリエーションが広がります。
forと比べるとwhileの方が少し簡単なので、whileから先に説明しましょう。

2.5.1 while文

while文は繰り返し処理のひとつで、プログラミングの基本的な構文の代表格です。ここでは図形を複製する際に利用しながら、構文を説明します。
まずは、円が横に並んでいるプログラムを考えます。分かりやすくするために画面は200×200ピクセルに縮小しています。また、黒ばかりだと退屈なので、色もつけています(意味はありません。好きな色にしてください)。

while_loop
図2.5-a

構文は次のようになります。継続条件がtrueである限りは処理を繰り返します
例えば、while(i <= 200)の条件の時、iが200までだったらtrue、201以上になったらfalseになって繰り返しが終わります。

while(継続条件) {  
   繰り返し処理
}

最終的なコードは次のようになります。

リスト2.5-a
int i = 0;      //繰り返し処理の基準になる値
int eSize = 5;  //円の直径を設定する

size(200, 200);
background(255);
noStroke();
fill(200, 0, 50);  //色を設定

//iの値が200以下の場合、while内の繰り返し処理を実行
while (i <= 200) {
  ellipse(i, 100, eSize, eSize);    //円を描く
  i += 10;  //iに入っていた数値と10を足してまたiに代入
}

この式では、iが200以下である限りは{ }(ブレース)の中を繰り返します
そして、iが200を超えたときに初めてプログラムは終了します。

この場合、while文の構造は【図2.5-b】になります。

while_graph
図2.5-b

2.5.2 比較演算子

ここで、a <= bという記号が出てきます。先に答えを言ってしまうと、aがb以下の場合という意味です。このaとbを比べる場合の記号を、比較演算子といいます。
比較演算子はプログラミングではほとんどの場合必ず使いますので、ここで基本的なものは覚えておきましょう。と言っても、6種類しかありません。
更に、whileやforで使われるのは多くの場合a <= b(以下)a < b(より小さい)だけです。

リスト2.5-b
カテゴリ演算子説明使用例
比較演算子"=="等しいif (a == b)
!=異なるif (a != b)
<未満if (a < b)
>超(超える)if (a > b)
<=以下if (a <= b)
>=以上 if (a >= b)

2.5.3 for文

構文は、次のようになります。カウンタの開始から始まり、継続条件がtrueである限りは処理を繰り返します
例えば、for(int i = 0; i <= 200; i = i + 10)の場合、カウンタである変数iは0から始まり、10ずつ足されていきます。iが200までは継続条件はtrueで、200以上になるとfalseになって繰り返しが終わります。

for(カウンタの開始; 継続条件; カウンタの更新) {  
   繰り返し処理
}

次の例題は、while文の例題と同じ結果になります。while文よりもfor文を使った方が簡潔に書けるので、forの方がよく使われるようです。

リスト2.5-c
int eSize = 5;  //円の直径を設定する

size(200, 200);
background(255);
noStroke();
fill(200, 0, 50);  //色を設定

//iは0から始まって、200以下の場合は繰り返され、
//繰り返すたびに10が加算されていく
for (int i = 0; i <= 200; i += 10) {    
  ellipse(i, 100, eSize, eSize);    //円を描く
}

この場合、for文の構造は【図2.5-c】になります。

for_graph
図2.5-c

2.5.4 for()のネスト —> 入れ子構造

次に、for文でよく使われるネストについて説明します。理解するのは少し難しいですが、よく使われるのできちんと理解しておいてください。
例えば、次のような図形を表示したい場合にはどうしたらいいでしょうか?

nest
図2.5-d

答えは、次のとおりです。

for(int y = 0; y <= height; y += 10){
  for(int x = 0; x <= width;  x += 10){
    ellipse(x, y, eSize, eSize);
  }
}

for文の中に、またfor文を入れるのです。これをネスト(入れ子)構造といいます。と、これだけ見せられてもよく分かりませんよね。分解して順を追ってプログラムの過程を見てみましょう。
まず、前述のコードを参考にして、10ピクセル間隔で並んだ複数の円を3行作るためにfor文を3つ使ってみます。まだ、for文の中にfor文は入れなくていいです。

nestStart
図2.5-e

for文のコードはこんな感じになるでしょう。

for (int x = 0; x <= width;  x += 10) {    //1行目の円を描画
  ellipse(x, 0, eSize, eSize);
}

for (int x = 0; x <= width;  x += 10) {    //2行目の円を描画
  ellipse(x, 10, eSize, eSize);
}

for (int x = 0; x <= width;  x += 10) {    //3行目の円を描画
  ellipse(x, 20, eSize, eSize);
}

1行ずつ書いているだけです。ここでellipseのy座標に注目してください。10ピクセル間隔なので、1行目は0、2行目は10、3行目は20と、10ずつ増えていますね。

nest_start_win
図2.5-f

これをコードではどう書くのでしょうか。x座標用のfor文をy座標用のfor文で囲ってあげればいいのです。for文のネストを使うと3行を実行するプログラムは次のようになります。

for(int y = 0; y <= 20;  y += 10){      //y座標用
  for(int x = 0; x <= width;  x += 10){    //x座標用
    ellipse(x, y, eSize, eSize);
  }
}

ここまで来たらあとは簡単です。y座標の条件式を必要な分まで増やせばいいのです。
色々数値を変えて試してみてください。最終的なコードは次のとおりです。

リスト2.5-d
int eSize = 3;  //円のサイズを指定
size(100, 100);       //画面サイズの決定
background(255);      //背景色の決定

noStroke();  //輪郭非表示
fill(200, 0, 50);    //色を設定

//y座標用
for (int y = 0; y <= height; y += 10) {
  //x座標用
  for (int x = 0; x <= width; x += 10) {
    ellipse(x, y, eSize, eSize);
  }
}

この時、x座標とy座標の関係を図で示すと次のとおりになります。
左から右へ、そして一行ずつ順に実行されていきます。

for.gif
図2.5-g

2.5.5 for文を使用したグラデーション

ここでは、for文を利用して色を指定し、線を描画することによってグラデーションを作ってみます。

2016_05_30_18_30
図2.5-h
size(256, 256);
background(255);

//1ピクセルずつ繰り返す
for(int x = 0; x < width; x ++){

  stroke(x);  //線の色を決定
  line(x, 0, x, height);  //線を描画 
  
  println(x);  //xの値を出力
}

左端を黒、右端を白にしたいとき、画面の横幅が256ピクセルの場合、このコードのx座標は、左端はx = 0、右端はx = 255になります。しかし、画面サイズが256ピクセルではなく、400ピクセルの時に同じように書いてしまうと次のような結果になります。

2016_05_30_18_42
図2.5-i
size(400, 400);
background(255);

//1ピクセルずつ繰り返す
for(int x = 0; x < width; x ++){

  stroke(x);  //線の色を決定
  line(x, 0, x, height);  //線を描画 
  
  println(x);  //xの値を出力
}

x=256~399の値の際に描画された範囲は真っ白になってしまい、画面左端から右端までの均等なグラデーションにはなりません。

このようなとき、map()という関数が便利です。関数については後述しますが、ここでは、map()は0~399の値を0~255の値に変換しているのだと理解しておいてください。

map(value, low1, high1, low2, high2)

という書き方をします。
value = 変更する変数
low1 = 変更前の範囲の最小値
high1 = 変更前の範囲の最大値
low2 = 変更後の範囲の最小値
high2 = 変更後の範囲の最大値

つまり、map関数はvalueの値をある範囲(low1〜high1)からある範囲(low2〜high2)に変更してくれるのです。この関数は次のように使うことができます。

リスト2.5-e
float c;  //色彩用の変数
size(400, 400);
background(255);
 
for(int x = 0; x <= width; x ++){
 
  //xの値を0~255の値に変換
  c = map(x, 0, width, 0, 255);
 
  stroke(c); //線の色を決定
  line(x, 0, x, height);  //線を描画 
 
  println(c); //色の値を出力
}

このサンプルが優れているところは、画面サイズを変えても左端が黒、右端が白の均等なグラデーションになるということです。この機会に、map()の機能をぜひ覚えてください。

2016_05_30_18_56
図2.5-j