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 は、偶数列で 0、奇数列で 1 になります。奇数列だけ 20 下がるため、互い違いの配置になります。

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

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

反復は同じものを量産する命令ではなく、番号を位置、色、大きさへ変換する仕組みです。次章では、番号ではなく角度や乱数から変化を作ります。

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

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

  • ellipseのまま、緑の大きさを行ごとに変えると植物園
  • rectへ変え、黄色を一部だけ灯すと夜の窓
  • triangleへ変え、列ごとに傾きを想像して配置すると旗の列

全部を作る必要はありません。一つ選び、まず図形と背景色だけを変えます。そのあと、一個だけ異なる要素を「間違い」ではなく「物語の主役」として置きます。なぜその一個だけ違うのかは、言葉で説明できなくてもかまいません。

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より小さくなったら、その呼び出しをそこで終える条件です。この条件がないと、いつまでも小さくしようとして処理を終えられません。

ここは発展なので、仕組みを一度で理解する必要はありません。まずそのまま実行し、240180へ、1224へ変えてください。その次に、円を四角形へ変える、左右ではなく上下へ分ける、色を大きさから決める、といった改造へ進めます。

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

この章の小さな区切り

  • timesで同じ形を繰り返せた
  • 行か列の数を一つ変えた
  • 余裕があれば、フラクタルの大きさか分かれ方を変えた

格子模様を表示できれば、再帰を理解しきらなくても保存して次章へ進めます。

参考資料