Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第6章 反復は同じ形を別の景色に変える

円を 10 個描くために ellipse を 10 行書くこともできます。位置が少しずつ変わるなら、その違いを規則として書けます。反復回数や間隔を変えたり、一つだけ色を変えたりすると、同じ図形から異なる模様を作れます。

6.1 5 回描く times

まず、同じ場所へ円を 5 回描きます。

def setup
  createCanvas(500, 220)
  background(245)

  5.times do
    ellipse(100, 110, 60, 60)
  end
end

見える円は一つです。同じ場所へ完全に重ねたからです。反復回数は増えましたが、位置が変わっていません。

times(タイムズ)は、何回目の反復かをブロック変数へ渡せます。直前の長いコードにある 5.times do から対応する end までを、次の変更部分と置き換えます。

5.times do |i|
  x = 70 + i * 90
  ellipse(x, 110, 60, 60)
end

初めて見る記号がいくつかあります。左から順に読みます。

  • 5.times は、その後の処理を 5 回繰り返します
  • do は、繰り返す処理の始まりです
  • |i| は、今が何回目かを受け取るための書き方です。縦線 2 本の間に変数名を書きます
  • 最後の end は、繰り返す範囲の終わりです

i は 0、1、2、3、4 と変わります。プログラムでは番号を 0 から数える場面が多くあります。5 回繰り返しても最後が 4 なのは、最初が 0 だからです。

最初の x は 70 + 0 * 90 なので 70、次は 70 + 1 * 90 なので 160 です。* は掛け算を表します。反復回数を 8 へ変えるだけで、同じ間隔の円が増えます。

6.2 行と列を重ねる

横方向の反復を、縦方向の反復の内側へ置きます。

def setup
  createCanvas(480, 360)
  background(28, 32, 50)
  noStroke

  4.times do |row|
    6.times do |column|
      x = 50 + column * 75
      y = 55 + row * 85
      fill(240, 180, 70)
      ellipse(x, y, 44, 44)
    end
  end
end

外側の row が 1 回進む間に、内側の column が 0 から 5 まで進みます。4 行 × 6 列なので、円は 24 個です。

外側の繰り返しが行を進み、内側の繰り返しが列を進む格子の図
図解 6-A 二重の繰り返しを、行と列として見る。

反復を重ねるとコードは短くなりますが、最初は動きを追いにくくなります。行数を 2、列数を 3 へ減らすと、どの順で描かれるか想像しやすくなります。

6.3 規則の中の一つだけを変える

すべて同じだと、画面は安定します。直前の長いコードの二重反復部分を、次の変更部分と置き換え、条件分岐で一つだけ色を変えます。

4.times do |row|
  6.times do |column|
    x = 50 + column * 75
    y = 55 + row * 85

    if row == 1 && column == 3
      fill(235, 80, 120)
    else
      fill(240, 180, 70)
    end

    ellipse(x, y, 44, 44)
  end
end

== は値が等しいかを比べ、&& は「かつ」です。2 行目であり、かつ 4 列目の円だけが別の色になります。ブロック変数は 0 から始まるため、row == 1 が 2 行目です。

濃紺の 480×360 のキャンバスに黄色い円が 4 行 6 列で並び、2 行目の 1 個だけが赤い実行結果
図 6-1 24 個の規則の中で、条件に合う 1 個だけを変える。

6.4 同じ間隔からずれを作る

列ごとに y 座標を少し変えると、格子が波打って見えます。二重反復の中にある y = 55 + row * 85 の 1 行だけを、次の 1 行と置き換えます。

y = 55 + row * 85 + (column % 2) * 20

% は余りを求める演算子です。column % 2 は、column が偶数なら 0、奇数なら 1 になります。番号が奇数の列だけ 20 下がるため、互い違いの配置になります。

さらに ellipse の大きさへ row や column を使えば、左から右、上から下への変化を作れます。二重反復の中にある ellipse(x, y, 44, 44) の 1 行を、次の変更部分と置き換えます。

size = 24 + column * 6
ellipse(x, y, size, size)

反復の番号を位置、色、大きさへ使うと、同じ図形の並び方を変えられます。

6.5 同じ反復から三つの作品を選ぶ

今の行と列のコードは、形を変えるだけで別の風景になります。

  • ellipse の色を緑にし、円の大きさを行ごとに変えると植物園
  • rect へ変え、黄色を一部だけ灯すと夜の窓
  • rect の横幅を細くし、列ごとに高さを変えると街の輪郭

三つの案から一つ選び、まず図形と背景色だけを変えてみましょう。そのあと、一個だけ色か大きさを変え、最初に目へ入る図形を作ります。どの位置の図形を変えると目立つかも比べられます。

6.6 発展:形の中へ同じ形を描く

大きな円の中へ半分の円を描き、その円の中へさらに半分の円を描くと、同じ規則が小さくなりながら続く模様ができます。このように、全体と似た形が一部分にも現れる構造をフラクタルと呼びます。

大きな円から二つの小さな円へ枝分かれし、さらに小さな円へ続く図
図解 6-B 大きさを半分にして同じ処理を呼ぶと、枝分かれが続く。
def setup
  createCanvas(500, 320)
  background(20, 25, 45)
  noStroke
  draw_circles(width / 2, height / 2, 240)
end

def draw_circles(x, y, size)
  return if size < 12

  fill(120 + size / 3, 100, 210, 150)
  ellipse(x, y, size, size)

  next_size = size / 2
  draw_circles(x - size / 4, y, next_size)
  draw_circles(x + size / 4, y, next_size)
end

draw_circles の中から、もう一度 draw_circles を呼んでいます。自分自身を呼び出す方法を再帰と呼びます。return if size < 12 は、円が 12 より小さくなったら、その呼び出しをそこで終える条件です。この条件がないと、いつまでも小さくしようとして処理を終えられません。

この発展例は、同じ形の中へ形を描くときの変化を画面から確かめます。まずそのまま実行し、setup の 240 だけを 180 へ変えて実行します。模様全体が小さくなるか見たら、240 へ戻して実行します。次に、return if size < 12 の 12 だけを 24 へ変えて実行し、小さい円の数が減るか見ます。エラーが出たら、変更した数字を元へ戻して実行します。その次に、円を四角形へ変える、左右ではなく上下へ分ける、色を大きさから決める、といった改造へ進めます。

濃紺の背景に、半透明の紫色の円が左右へ小さく枝分かれしながら重なった模様
図 6-2 同じ処理を小さくして呼び直した円のフラクタル。

格子模様とフラクタルでは、同じ反復でも違う画面になりました。残したいほうへ短い名前を付けたら、第7章で規則的な動きと予想できない変化を比べます。

参考資料