SFC – デザインとプログラミング 2017
反復と乱数
プログラムを構造化していく際に、3つの重要な構成要素があります。それは、「順次 (Sequence)」、「反復 (Iteration)」、「分岐 (Selection)」 です。今回は、この3つの構成要素の中の反復 (Iteration) に注目して、Processingで形を描きながら反復について考えます。また、一意的でないランダムな値である「乱数」と反復を組合せて、どのような表現か可能となるか探求していきます。
スライド資料
反復 (Iteration)
- コンピューターは、「くりかえし」の天才!
- 最近のマシンであれば、1秒間に2億回(2GHz)以上のクロックで、正確に計算をくりかえすことができる
- 反復は、プログラムの基本的で重要な構造のひとつ

構造化プログラミング、3つの構成要素
- 順次 (Sequence)、反復 (Iteration)、分岐 (Selection)

30年前のPCでのプログラムを再現
- Commodore 64

- HELLOをひたすらくりかえす
10 PRINT “HELLO”
20 GOTO 10
- 実行結果 – プログラムを止めるまで、延々と“HELLO”を出力

- ちょっとアレンジ
10 PRINT “/\”;
20 GOTO 10
- 波の模様が延々と続く

- さらに、乱数(後述)を利用して…
10 PRINT CHR$(205.5+RND(1));
20 GOTO 10
- 迷路のような複雑な模様が浮かびあがる

- Mac OS Xのターミナルでも、以下のコードで同じ現象を再現可能
yes 'c=(╱ ╲);printf ${c[RANDOM%2]}'|bash

参考: 10 PRINT CHR$(205.5+RND(1)); : GOTO 10

- では、Processingをつかって、くりかえしの実験をしてみましょう!
変数
- クイズ: 正方形の中に、ちょうど半分の幅と高さの正方形を描く

- 答
size(400,400);
rect(100,100,200,200);
rect(100,100,100,100);
- クイズ2:さらに半分の正方形を中に

- 答
size(400,400);
rect(100,100,200,200);
rect(100,100,100,100);
rect(100,100,50,50);
手で計算するのではなく、もっとかしこくできないか
- 描いた四角形の常に半分のサイズで次の四角形を描く
- 現在のサイズの値を記録できると便利なのに…
- 「値を記録する」→ 変数を利用する
変数
- 変数とは?
- 一時的に値(文字、文字列、数字など)を記憶しておく場所
- データを入れておく「箱」のようなもの
- データ型 – 値の種類
- Processingでよく用いられるデータ型
- int:整数 (-1, 0, 1, 2, 3….)
- float:少数 (-0.01, 3.14, 21.314)
- boolean:ブール値、真か偽か、(true, false)
- char:1文字分のデータ(a, b, c, d…)
- color:色の情報を保存

- 宣言:使用する変数の名前の箱を準備する
int hoo;
- 代入:変数の箱に値を入れる
hoo = 0;
- 演算:変数の値を計算する
hoo = hoo + 1;
- 先程の例は、変数を利用すると下記のようになる
size(400,400);
float rectSize = 200;
rect(100,100,rectSize,rectSize);
rectSize = rectSize / 2;
rect(100,100,rectSize,rectSize);
rectSize = rectSize / 2;
rect(100,100,rectSize,rectSize);
rectSize = rectSize / 2;
rect(100,100,rectSize,rectSize);
rectSize = rectSize / 2;
rect(100,100,rectSize,rectSize);
rectSize = rectSize / 2;
...
- どんどん小さな正方形を描いていくことができる
- 変数を利用して、いろいろ実験してみましょう

- 変数の使用例
size(800, 600);
background(0);
noStroke();
fill(0, 127, 255, 100);
float x, y, diameter;
x=width/2;
y=height/2;
diameter=height;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
– 実行結果

繰り返し – for文
- さっきのプログラムに注目
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
...
- 繰り返しの部分を何度も書かずに一気に指定したい
diameter = diameter / 1.4;
ellipse(x, y, diameter, diameter);
例えば、これを10回くりかえすという指定はできないだろうか? → for文を使う!
- for文の書きかた
for (初期化式; 継続条件式; 再初期化式) {
文;
}
- 初期化式:初期化の際の条件式
- 継続条件式:繰り返しを継続する条件式
- 再初期化式:繰り返されるたびに実行される式
Processingでfor文を使ってみる
- forを用いた、繰り返しの例 1
int i;
for (i=0; i < 100; i=i+1){
print("+");
}
- forを用いた、繰り返しの例 2
int i;
for (i=0; i < 100; i=i+1){
print(i + ", ");
}
- 同心円をくりかえしを用いて描画
//初期条件の設定
size(800, 600);
background(0);
noStroke();
smooth();
fill(0, 127, 255, 40);
float x, y, diameter;
x = width / 2;
y = height / 2;
diameter = height;
int i;
//同心円を描いていく
for (i=0; i < 32; i++) {
ellipse(x, y, diameter, diameter);
diameter = diameter / 1.2;
}

くりかえしによる入れ子構造
- for文を使ってくりかえし図形を描く
- 工夫することで図形が入れ子状に連なった図形を描くことが可能
入れ子状の矩形
size(800, 600);
background(0);
stroke(0);
fill(0, 127, 255, 100);
float x, y, w, h;
x = 0;
y = 0;
w = width;
h = height;
for (int i = 0; i < 32; i++) {
w = w / 2;
h = h / 2;
rect(x, y, w, h);
rect(x + w, y + h, w, h);
}

入れ子状の円
size(800, 600);
background(0);
stroke(0);
fill(0, 127, 255, 100);
float x, y, diameter;
x = width/4;
y = height/2;
diameter = width/2;
for (int i = 0; i < 32; i++) {
ellipse(x, y, diameter, diameter);
ellipse(x + diameter, y, diameter, diameter);
diameter = diameter / 2;
x = x / 2;
}

回転のくりかえし
size(800, 800);
background(0);
noStroke();
fill(0, 127, 255, 30);
float diameter;
diameter = width/1.8;
translate(width/2, height/2);
rotate(PI/4);
for (int i = 0; i < 256; i++) {
ellipse(diameter / -2, 0, diameter, diameter);
ellipse(diameter / 2, 0, diameter, diameter);
diameter = diameter / 1.05;
rotate(PI / 24.0);
}

色について – RGBモデルとHSBモデル
- 色を指定するには?
- R(赤) G(緑) B(青)の三原色で指定する
- 加法混色 (光の三原色であることに注意) ←→ 色料の三原色

- RGB以外の方法での色の指定
- HSB (HSV)による指定
- 色相 (Hue):色の種類
- 彩度 (Saturation):色の鮮かさ
- 明度 (Brightness):色の明かるさ
- HSB (HSV)による指定
- プログラミングしながら色を指定する場合は、HSBの方が直感的に望みの色を指定し易いことも多い
- HSB (HSV) 色空間の視覚イメージ
- 色相:外環の角度
- 彩度:中心点からの距離
- 明度:高さ
- HSB (HSV) 色空間への切替方法
- colorMode関数を使用する、
- それぞれのパラメータの範囲も同時に指定する
- 例:
- 色相:360階調(°)
- 彩度:100階調(%)
- 明度:100階調(%)
colorMode(HSB, 360, 100, 100);
繰り返しによる色の表現
- HSB (HSV) 色空間と繰り返しを使用して、色の変化をつかった様々な表現に挑戦
例:虹色のグラデーション
//変数の宣言
int i;
//初期設定
size(800,600);
colorMode(HSB, 360, 100, 100);
noStroke();
//色相を変化させながら四角を描いていく
for(i=0; i < width ; i++){
fill(i * 360.0/800.0,100,100);
rect(i,0,1,height);
}

乱数
- プログラムは、設定された手続きを何度でも繰り返す
- そのままでは、予想外の挙動はしない
- 完全に全てをコントロールするのではなく、偶然性、意外性をとり入れたい
- 実行する度に毎回異なる値を出力する仕組み
- 乱数
- 何ら法則性、規則性のない、でたらめな値を出力
- ランダム
Processingで乱数を生成 – 乱数の範囲を指定する
- 例:0から100の乱数を生成
random(100);
- 例:100から1000の乱数を生成
random(100, 1000);
ランダムに色を塗る
//ランダムに色を塗る
//変数の宣言
int i;
//初期設定
size(800, 600);
colorMode(HSB, 360, 100, 100);
noStroke();
//ランダムに色を塗る
for (i=0; i < width ; i++) {
fill(random(360), random(100), random(100));
rect(i*1, 0, 1, height);
}

似たような色相で
//似たような色相で色を塗る
//変数の宣言
int i;
//初期設定
size(300,300);
colorMode(HSB, 360, 100, 100);
noStroke();
//似たような色相で色を塗る
for(i=0; i < 300; i++){
fill(random(200,220),random(100),random(100));
rect(i*1,0,1,300);
}

似たような明度と彩度で
//変数の宣言
int i;
//初期設定
size(800, 600);
colorMode(HSB, 360, 100, 100);
noStroke();
//似たような明度と彩度で色を塗る
for (i=0; i < width ; i++) {
fill(random(360), 60, 90);
rect(i*1, 0, 1, width);
}

例6:たくさん円を描く
- さらに図形を描く場所もランダムに!
//変数の宣言
int i;
//初期設定
size(800, 600);
background(0);
colorMode(HSB, 360, 100, 100, 100);
noStroke();
//たくさんの円を描く
for (i=0; i < 100; i++) {
float diameter;
fill(random(200, 240), random(50, 100), random(50, 100), 50);
diameter = random(50, 200);
ellipse(random(width), random(height), diameter, diameter);
}

たくさん四角形を描く
//たくさんの四角形を描く
//変数の宣言
int i;
//初期設定
size(800, 600);
background(0);
colorMode(HSB, 360, 100, 100, 100);
rectMode(CENTER);
noStroke();
//たくさんの四角形を描く
for (i=0; i < 100; i++) {
fill(random(0, 40), random(50, 100), random(50, 100), 50);
rect(random(800), random(600), random(5, 200), random(5, 200));
}
