風呂瀬 信五

ボイドアルゴリズムが描く群れの生命:p5.jsで探る創発のダイナミクス

プログラミングで複雑な生命現象を表現しようとするとき、私たちは壁に突き当たります。魚の群れが描く流麗な軌跡、鳥の群れが見せる一糸乱れぬ動き。それらを単なる物理シミュレーションとして再現するだけでは、どこか空虚さが残ります。私たちが真に捉えたいのは、その奥にある「生命感」や、個々の単純な振る舞いから立ち上る予測不能な「創発的な美」ではないでしょうか。なぜアルゴリズムが織りなす自律的な動きに、私たちは心を奪われるのでしょう。この記事では p5.js を使い、自律エージェントのシミュレーションを通じて、個と群れが織りなす生命の詩学の深淵へと足を踏み入れていきます。

はじめに:アルゴリズムが宿す生命の息吹

デジタルなキャンバスに点を打ち、線を描く。クリエイティブコーディングの第一歩は、多くの場合、静的な図形の描画から始まります。しかし、私たちが本当に魅了されるのは、その静的な世界に時間が流れ、動きが生まれた瞬間です。コードによって与えられた自律性を持つ存在、つまり「エージェント」が、まるで自身の意思で動き出したかのように振る舞うとき、私たちはそこに生命の息吹を感じます。

それは、決定論的なアルゴリズムの連鎖から、なぜか非決定論的で有機的な印象が生まれるという不思議な体験です。ひとつひとつのエージェントはごく単純なルールに従っているに過ぎないのに、その集合体は私たちの予測を裏切り、複雑で美しい秩序を自ら形成していく。この現象こそ、ジェネラティブアートにおける エージェントシミュレーション の核心であり、私たちがこれから探求するテーマです。

エージェントベースシミュレーションとは:個と群れの織りなす世界

エージェントベースシミュレーション(Agent-Based Simulation)とは、自律的な意思決定能力を持つ「エージェント」を多数配置し、それらの相互作用によってシステム全体の振る舞いを分析するモデルです。特筆すべきは、そのアプローチが「ボトムアップ」である点です。システム全体を支配する中央集権的なリーダーや絶対的なルールは存在しません。存在するのは、個々のエージェントが持つ、ごく局所的な環境認識と、それに基づく単純な行動規則だけです。

自然界に目を向ければ、このモデルの美しさがよくわかります。鳥の群れ「マーマレーション」は、特定のリーダーが指揮しているわけではありません。一羽一羽が、隣の鳥との距離や速度を意識して飛んでいるだけです。その結果として、全体がまるで巨大な一つの生命体であるかのような、滑らかで複雑な動きが生まれます。アリの行列が効率的な食料運搬ルートを形成するのも、個々のアリがフェロモンという局所的な情報に従って行動する結果に過ぎません。

p5.js の世界では、このエージェントをオブジェクトとして実装するのが一般的です。JavaScript のクラス構文を用いれば、各エージェントの位置、速度、色といった「状態」と、周囲の状況に応じてどのように振る舞うかという「行動」を、ひとつの独立した単位としてカプセル化できます。これにより、私たちは何百、何千という個を生成し、それらが織りなす群れのダイナミクスを観察する舞台を整えることができるのです。

創発的行動のメカニズム:シンプルなルールから生まれる複雑な秩序

個々の単純な振る舞いから、全体として高度で複雑な秩序が生まれる現象。これを「創発 (emergence)」と呼びます。エージェントシミュレーションの美しさは、この創発のプロセスそのものにあります。では、具体的にどのようなルールが、この魔法のような現象を引き起こすのでしょうか。

この分野で最も有名で古典的なモデルが、コンピュータ科学者クレイグ・レイノルズが1986年に発表した「ボイド (Boids)」アルゴリズムです。彼は、鳥の群れの動きをシミュレートするために、驚くほどシンプルな3つの基本原則を定義しました。

  1. 分離 (Separation): 周囲の仲間とぶつからないように、密集しすぎた個体から離れようとする。
  2. 整列 (Alignment): 周囲の仲間の平均的な進行方向に、自分の向きを合わせようとする。
  3. 結合 (Cohesion): 周囲の仲間の中心(重心)に向かって、集まろうとする。

これらのルールは、いずれもエージェントが自身の「近傍」にいる仲間だけを認識し、行動を決定するという点で局所的です。彼らは群れ全体の形状や目的を知りません。しかし、すべてエージェントがこの3つのルールを同時に、かつ継続的に実行することで、個々の動きが相互に影響し合い、結果として自然な群れの挙動が「創発」するのです。この「単純な局所的ルールから、予測不能な大域的パターンが生まれる」という構造こそ、ジェネラティブアートにおいて私たちが生命感を表現するための、強力な鍵となります。

p5.jsでボイドシミュレーションを実装する:群れの知性をコードに刻む

それでは、この ボイドシミュレーション の概念を p5.js のコードに落とし込んでみましょう。完全な実装を示すことはしませんが、その核となる構造と思想を共有します。中心となるのは、個々のボイドを表現する Boid クラスです。

まず、Boid クラスは自身の状態を管理するためのプロパティとして、位置 (position)、速度 (velocity)、加速度 (acceleration) を持ちます。これらはすべて p5.Vector オブジェクトで表現するのが極めて効果的です。p5.Vector が提供する豊富なメソッド群(add, sub, mult, limit など)は、物理的な力の計算を直感的かつ簡潔に記述する上で不可欠です。


// Boidクラスの骨格
class Boid {
  constructor() {
    this.position = createVector(random(width), random(height));
    this.velocity = p5.Vector.random2D();
    this.velocity.setMag(random(2, 4));
    this.acceleration = createVector();
    this.maxForce = 0.2;
    this.maxSpeed = 4;
  }

  // 加速度を速度に、速度を位置に反映させる
  update() {
    this.velocity.add(this.acceleration);
    this.velocity.limit(this.maxSpeed);
    this.position.add(this.velocity);
    this.acceleration.mult(0); // 毎フレーム、加速度をリセット
  }

  // 力(p5.Vector)を加速度に適用する
  applyForce(force) {
    this.acceleration.add(force);
  }
  
  // ... ここに3つのルールを実装するメソッドが続く
}

このクラスの心臓部となるのが、3つのルールを計算し、それらを自身の動きに反映させるメソッド群です。例えば、flock() のような統括メソッドを定義し、その中で分離・整列・結合の各ルールに対応する力を計算させます。


// Boidクラス内のメソッドの概念
flock(boids) {
  // 3つのルールに基づいて力を計算する
  let separationForce = this.separate(boids);
  let alignmentForce = this.align(boids);
  let cohesionForce = this.cohere(boids);

  // 各ルールから計算された力には「重み」をかけることができる
  separationForce.mult(1.5);
  alignmentForce.mult(1.0);
  cohesionForce.mult(1.0);

  // 計算した力を自身の加速度に適用する
  this.applyForce(separationForce);
  this.applyForce(alignmentForce);
  this.applyForce(cohesionForce);
}

// 分離ルールを計算するメソッド (概念)
separate(boids) {
  let desiredSeparation = 25.0;
  let steer = createVector(0, 0);
  let count = 0;
  // 他のすべてのボイドとの距離を確認
  for (let other of boids) {
    let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
    if ((d > 0) && (d < desiredSeparation)) {
      // 距離が近すぎる場合、離れる方向のベクトルを計算
      let diff = p5.Vector.sub(this.position, other.position);
      diff.normalize();
      diff.div(d); // 距離が近いほど強く反発する
      steer.add(diff);
      count++;
    }
  }
  // 平均化
  if (count > 0) {
    steer.div(count);
  }

  if (steer.mag() > 0) {
    steer.normalize();
    steer.mult(this.maxSpeed);
    steer.sub(this.velocity);
    steer.limit(this.maxForce);
  }
  return steer;
}
// align() と cohere() も同様に、周囲のボイドを走査して計算する

メインのスケッチファイルでは、setup()Boid インスタンスの配列を作成し、draw() ループの中で配列の各要素に対して flock() メソッドと update() メソッドを呼び出します。このシンプルな繰り返しが、複雑な群れの振る舞いを生み出すのです。

ここで重要なのは、分離・整列・結合の各ルールの影響度合いを調整する「重み付け」です。例えば、分離の力を強くすれば群れは拡散し、結合の力を強くすれば密集します。このパラメータを微調整するプロセスは、生命の振る舞いをデザインする行為そのものであり、作家の思想や美学が色濃く反映される、極めて創造的な探求と言えるでしょう。

自律エージェントが問いかけるもの:コードと生命の境界線

自ら実装したボイドの群れが、キャンバス上を滑らかに、そして予測不能に泳ぎ回る様を眺めていると、ふと根源的な問いが頭をよぎります。私たちは一体、何を見ているのでしょうか。これは単なる for ループとベクトル計算が可視化されたものなのか。それとも、そこに宿る何らかの生命のシミュラクラ(模擬物)なのでしょうか。

エージェントたちは、私たちが与えた厳格なルールセットから逸脱することは決してありません。しかし、その厳格さから生まれる結果は、驚くほど自由で有機的に見えます。彼らは障害物を避け、いくつかの小集団に分かれ、また合流する。その姿は、まるで集団としての「意思」や「社会性」を持っているかのようです。この感覚は、私たちが生命を認識する際のパターンと、アルゴリズムが生み出すパターンが共鳴する瞬間に生まれるのかもしれません。

コードという、この上なく論理的で構築的な言語を用いて、非論理的で流動的な「生命らしさ」を立ち上がらせる試み。それは、私たち自身が持つ生命や知性に対する認識を、鏡のように映し出します。自律エージェントのシミュレーションは、単なる技術的な挑戦に留まらず、私たちに「生命とは何か」「知性とは何か」を問いかける、哲学的な営為でもあるのです。

終わりに:無限に広がる生命の詩学

今回探求したボイドシミュレーションは、自律エージェントが織りなす広大な世界への、ほんの入り口に過ぎません。この基本的な枠組みに、新たなルールを付け加えていくことで、その表現の可能性は無限に広がります。

例えば、群れを追いかける「捕食者」エージェントを追加すれば、逃げる群れの動きはよりダイナミックで切実なものになるでしょう。キャンバス上に「餌」を配置し、それを探す行動ルールを実装すれば、より複雑な生態系(エコシステム)が立ち上がります。あるいは、エージェント同士が音や光のような信号でコミュニケーションをとるルールを導入すれば、さらに高度な社会性が生まれるかもしれません。

p5.js という身近なスケッチブックと、自律エージェントという設計思想を手に、私たちはデジタルな粘土で生命を創造する彫刻家となることができます。そこには唯一の正解はありません。あなた自身の問いと美意識を羅針盤として、ぜひ、あなただけのルールセットを探求し、独自の生命詩学をキャンバスに紡ぎ出してみてください。その先に、きっとまだ誰も見たことのない創発の美が待っているはずです。

関連記事