ショートストーリー ビッグバンドのシミュレーション
東京の一角、薄暗いオフィスの片隅で、プログラマーの佐藤はディスプレイに向かっていた。彼は、宇宙の始まりと終焉に関する理論を基にシミュレーションを構築してきた。そして、ついにその決定的な瞬間が訪れようとしていた。「ビッグバンド」と彼が名付けた新たな理論。それは、宇宙の膨張と爆散のエネルギーの変化を、小曲線関数によって説明するものだった。
「この双曲線関数…単純だが、この関数が宇宙の秘密を握っているんだ。」
彼の指はキーボードを走り、シミュレーションの設定を微調整する。双曲線関数とは、数学的に言えば
$$
f(x)= 1/x
$$
というシンプルな関数だ。この関数の特徴は、Xがゼロに近づくと値が無限大に発散することだ。そして、ゼロを境に、プラス無限大から一気にマイナス無限大へと移行する。まさに、この「無限に発散し、反転する」性質こそが、宇宙の大きなエネルギー変化を表している。
宇宙は平穏だった。彼のシミュレーションでは、星々が整然と位置を保ち、物質は静かに存在していた。しかし、パラメーターがゼロに近づくにつれ、徐々に異変が起き始める。双曲線関数が示す通り、ブラックホールの重力が急激に強化されていき、物質はすべてブラックホールに引き寄せられる。吸い込まれる物質の量は膨大で、重力源は果てしなく巨大化する。
「このままでは…」
佐藤の視界に映るグラフは、重力源がゼロを境に無限大に達し、そして逆方向へ反転する様子を描いていた。突然、宇宙のすべてを飲み込んでいたブラックホールが膨張を始め、内包していたエネルギーが一気に解放される。宇宙を押し広げるその力は、双曲線関数の特徴そのものだ。まるで見えない境界を越えたかのように、エネルギーがプラスからマイナスへと符号を反転させ、全ての物質が外へと飛び散っていく。
「これが…ビッグバンドだ。」
佐藤は、画面に映る宇宙の爆散に圧倒されながらつぶやいた。この双曲線関数の変位こそ、宇宙の膨張と爆散を繰り返すエネルギーの象徴だったのだ。ゼロを境にして、無限に膨張し続けるエネルギーが逆方向に反転し、物質を爆発的に押し出していく。宇宙の誕生、そしてそれを繰り返すビッグバンド。すべては彼のシミュレーションで目の前に現れた。
宇宙の秘密は、実にシンプルな数式で説明できる。X分の1、双曲線関数。それは、無限大に至る力と、ゼロを超えて逆転するエネルギーの動きそのものだ。
コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Particle Explosion Simulation with Negative Gravity</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
<script>
let particles = [];
let gravityCenter;
let gravityStrength;
let xValue = 10; // スライダーの初期値
let timeStep = 0.01; // 時間分解能を細かくするための時間ステップ
function setup() {
createCanvas(windowWidth, windowHeight);
gravityCenter = createVector(width / 2, height / 2); // 重力源は画面の中心
// パーティクルを生成
for (let i = 0; i < 2000; i++) {
particles.push(new Particle(random(width), random(height)));
}
}
function draw() {
background(0);
// 自動的にスライダーの値をゆっくりと変化させる
xValue -= 0.005; // スライダーの値をゆっくり減少
if (xValue < -10) {
xValue = 10; // 値が-10未満になったら10に戻す
}
// 重力強度の計算
gravityStrength = (xValue >= 0 ? 100 : -100) / (1 + abs(xValue)); // xValueが負の場合、重力もマイナス
// 重力源の表示
fill(255, 0, 0);
ellipse(gravityCenter.x, gravityCenter.y, 20, 20);
// 各パーティクルの動きを更新
for (let particle of particles) {
particle.update(gravityStrength, xValue);
particle.show();
}
// スライダーの値を表示
fill(255);
textSize(16);
text(`Gravity Strength: ${gravityStrength.toFixed(2)}`, 20, 60);
text(`Slider Value (xValue): ${xValue.toFixed(2)}`, 20, 80);
}
class Particle {
constructor(x, y) {
this.position = createVector(x, y);
this.velocity = p5.Vector.random2D().mult(random(1, 2)); // ランダムな速度でスタート
this.acceleration = createVector(0, 0);
this.mass = random(0.1, 1.5); // パーティクルの質量を軽く設定
this.isExploding = false; // 爆散フラグ
}
applyForce(force) {
let f = p5.Vector.div(force, this.mass);
this.acceleration.add(f);
}
update(gravityStrength, xValue) {
let force = p5.Vector.sub(gravityCenter, this.position); // 重力源に向かうベクトル
let distance = force.mag(); // 重力源までの距離
force.normalize();
// 反比例の双曲線関数で重力を計算
let gravityEffect = gravityStrength / (distance * distance);
// xValueに基づいて重力の符号を反転
if (xValue < 0) {
gravityEffect = -gravityEffect; // 符号を反転
this.isExploding = true; // 爆散フラグを立てる
}
// 重力をパーティクルに適用
force.mult(gravityEffect);
this.applyForce(force);
// 爆散中のパーティクルはより大きな速度を持つ
if (this.isExploding) {
this.velocity.add(p5.Vector.random2D().mult(5)); // 爆散時にランダムな速度を追加
}
// 位置と速度を更新
this.velocity.add(this.acceleration);
this.position.add(this.velocity); // ここを修正
this.acceleration.mult(0); // 加速度をリセット
// キャンバス外に出た場合、反対側に戻す
if (this.position.x > width) this.position.x = 0;
if (this.position.x < 0) this.position.x = width;
if (this.position.y > height) this.position.y = 0;
if (this.position.y < 0) this.position.y = height;
}
show() {
fill(255);
ellipse(this.position.x, this.position.y, this.mass * 2);
}
}
</script>
</body>
</html>