
"๋จ์ํ ๊ท์น์ด ๋ง๋ค์ด๋ด๋ ์์ธก ๋ถ๊ฐ๋ฅํ ๋ณต์กํ ํ๋, ํ์ง๋ง ๊ทธ ์์์ ๋ฐ๊ฒฌ๋๋ ์จ๊ฒจ์ง ํจํด"์ด์์.
์ด๊ฒ์ ๋ ์จ, ์ฃผ์ ์์ฅ, ์ฌ์ฅ ๋ฐ๋, ๋๋ฅ ๋ฑ ์์ฐ์ ๋ณต์กํ ํ์์ ์ค๋ช
ํ๋ ํต์ฌ ๊ฐ๋
์
๋๋ค.
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ์ด๋ฆ | Chaos Theory (์นด์ค์ค ์ด๋ก ) |
| ์๋ฏธ | ๊ฒฐ์ ๋ก ์ ์ด์ง๋ง ์์ธก ๋ถ๊ฐ๋ฅํ ์์คํ ์ ํ๋์ ์ฐ๊ตฌํ๋ ์ด๋ก |
| ํต์ฌ ์์ด๋์ด | ์ด๊ธฐ ์กฐ๊ฑด์ ๋ฏธ์ธํ ์ฐจ์ด๊ฐ ์๊ฐ์ด ์ง๋๋ฉด์ ์์ฒญ๋๊ฒ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ฆ (๋๋นํจ๊ณผ) |
| ๊ฒฐ๊ณผ ํจํด | ๋ฌด์ง์ํด ๋ณด์ด์ง๋ง ์ผ์ ํ ๊ตฌ์กฐ(์ดํธ๋ํฐ)๋ฅผ ๊ฐ์ง ํจํด |
| ๊ด๋ จ ๊ฐ๋ | ๋๋นํจ๊ณผ(butterfly effect), ์คํธ๋ ์ธ์ง ์ดํธ๋ํฐ(strange attractor), ์ด๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์ฑ |
1๏ธโฃ ๊ฒฐ์ ๋ก ์ ์์คํ
โ ๋ช
ํํ ๊ท์น์ ๋ฐ๋ผ ์์ง์
โ ๋๋ค์ด ์๋๋ผ ์ํ์ ๊ณต์์ผ๋ก ์ ์๋จ
2๏ธโฃ ์ด๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์ฑ (๋๋นํจ๊ณผ)
โ ์์์ ์ ์์ฃผ ์์ ์ฐจ์ด๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์์ ํ ๋ฐ๊ฟ
โ "๋ฒ ์ด์ง์ ๋๋น ํ ๋ง๋ฆฌ๊ฐ ๋ด์์ ํญํ์ ๋ง๋ ๋ค"
3๏ธโฃ ์ฅ๊ธฐ ์์ธก ๋ถ๊ฐ๋ฅ
โ ๊ท์น์ ์์๋ ๋ฏธ๋๋ฅผ ์ ํํ ์์ธกํ ์ ์์
โ ์ปดํจํฐ๋ก๋ ๊ณ์ฐ์ ํ๊ณ๊ฐ ์์
4๏ธโฃ ์คํธ๋ ์ธ์ง ์ดํธ๋ํฐ
โ ๋ฌด์ง์ ์์์ ๋ฐ๊ฒฌ๋๋ ์จ๊ฒจ์ง ๊ตฌ์กฐ
โ ์์คํ
์ด ํน์ ํจํด์ผ๋ก ์๋ ดํ๋ ค๋ ๊ฒฝํฅ
5๏ธโฃ ํ๋ํ ๊ตฌ์กฐ
โ ์นด์ค์ค ์์คํ
์ ์ข
์ข
ํ๋ํ ํจํด์ ์์ฑ
โ ์ด๋ค ์ค์ผ์ผ์์ ๋ณด๋ ๋น์ทํ ๊ตฌ์กฐ๊ฐ ๋ฐ๋ณต๋จ
๐ ์์ฐ ํ์๊ณผ์ ์ฐ๊ฒฐ
| ๐ช๏ธ ๋ ์จ | ์ด๊ธฐ ์กฐ๊ฑด์ ๋ฐ๋ผ ์์ธก์ด ๋ฉฐ์น ์ด์ ๋ถ๊ฐ๋ฅ |
|---|---|
| ๐ง ๋๋ฅ | ๋ฌผ์ด๋ ๊ณต๊ธฐ์ ๋ณต์กํ ์์ฉ๋์ด ํจํด |
| ๐ ์ฌ์ฅ ๋ฐ๋ | ๊ฑด๊ฐํ ์ฌ์ฅ์ ์ฝํ ์นด์ค์ค ํจํด์ ๋ณด์ |
| ๐ ์ฃผ์ ์์ฅ | ๋ฌด์ํ ๋ง์ ์์ธ์ด ์ฝํ ์์ธก ๋ถ๊ฐ๋ฅ |
| ๐ช 3์ฒด ๋ฌธ์ | ์ธ ๊ฐ์ ์ฒ์ฒด๊ฐ ๋ง๋๋ ์นด์ค์ค์ ๊ถค๋ |

๋ก์ง์คํฑ ๋งต์ ์๋ ๊ฐ์ฒด๊ตฐ ๋ํ(Population Dynamics)๋ฅผ ๋ชจ๋ธ๋งํ๊ธฐ ์ํด ์๋ฌผํ์์ ๋์ ๋ ๋จ์ํ 1์ฐจ์ ๋ฐ๋ณต ๋ฐฉ์ ์(Iterative Equation)์ ๋๋ค.
์ฝ๋๊ฐ ์ฌ์ฉํ๋ ํต์ฌ ์์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
x ๋ณ์์ ํด๋นํฉ๋๋ค.r ๋ณ์์ ํด๋นํ๋ฉฐ, ๋ง์ฐ์ค ์์ง์์ผ๋ก 0๋ถํฐ 4๊น์ง ์กฐ์ ๋ฉ๋๋ค.์ด ๋ฐฉ์ ์์ ๊ฐ์ฒด๊ตฐ์ ์ฑ์ฅ์ ๋ค์ ๋ ๊ฐ์ง ์์๋ก ์ค๋ช ํฉ๋๋ค:
์๋์ p5.js ์ฝ๋๋ ๊ฐ์ ๋ฐ๋ฅธ ๊ฐ์ฒด๊ตฐ ๋ฐ๋()์ ์๊ฐ ํ๋ฆ์ ๊ทธ๋ํ๋ก ์๊ฐํํฉ๋๋ค.
r = map(mouseX, 0, width, 0, 4); ์ฝ๋๋ฅผ ํตํด ๋ง์ฐ์ค์ ๊ฐ๋ก ์์น(mouseX)๋ฅผ 0๋ถํฐ 4๊น์ง์ ๊ฐ์ผ๋ก ๋ณํํฉ๋๋ค.x = r * x * (1 - x); ์ฝ๋๊ฐ draw() ํจ์(ํ๋ ์๋ง๋ค ์คํ) ๋ด์์ ๋ฐ๋ณต์ ์ผ๋ก ์คํ๋๋ฉฐ ๊ฐ์ ์
๋ฐ์ดํธํฉ๋๋ค. ์ด๊ฒ์ด ๋ก์ง์คํฑ ๋งต์ ๋ฐ๋ณต ๊ณผ์ ์
๋๋ค.points ๋ฐฐ์ด์ ์ถ๊ฐ๋๊ณ , ํ๋ฉด์ ๋์ด๊ฐ๋ ์ค๋๋ ๊ฐ์ ์ ๊ฑฐ๋ฉ๋๋ค (points.shift()).beginShape()์ endShape()๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐ์ด์ ๊ฐ๋ค์ ์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ์ผ๋ก ์ฐ๊ฒฐ๋ ์ ์ผ๋ก ๊ทธ๋ฆฝ๋๋ค.let r = 2.8; // ์ฑ์ฅ๋ฅ ํ๋ผ๋ฏธํฐ
let x = 0.5; // ์ด๊ธฐ๊ฐ
let points = [];
const BURN_IN = 50; // ์ด๊ธฐ๊ฐ 50ํ ๊ณ์ฐ ๊ฑด๋๋ฐ๊ธฐ
let counter = 0; // ๋ฐ๋ณต ํ์ ์นด์ดํฐ
function setup() {
createCanvas(800, 400);
background(0);
frameRate(60); // ๊ณ์ฐ ์๋๋ฅผ ์ข ๋ฆ์ถฐ์ ์๊ฐํ์ ๋์์ ์ค๋๋ค.
}
function draw() {
// 1. ์์์์ด ๋งค ํ๋ ์ ๊ฐฑ์
background(0);
// 2. ๋ง์ฐ์ค๋ก r ๊ฐ ์กฐ์
r = map(mouseX, 0, width, 0.0, 4.0);
// 3. ๋ก์ง์คํฑ ๋ฐฉ์ ์ ๊ณ์ฐ
// 3-1. ์ด๊ธฐ๊ฐ ๊ณ์ฐ ๊ฑด๋๋ฐ๊ธฐ (BURN-IN):
// x์ ๊ถค์ ์ด ์์ ์ ์ ์ถฉ๋ถํ ๋๋ฌํ๋๋ก ํฉ๋๋ค.
if (counter < BURN_IN) {
x = r * x * (1 - x);
counter++;
// ์ด ๋จ๊ณ์์๋ ์ ์ ๊ทธ๋ฆฌ์ง ์์ต๋๋ค.
} else {
// 3-2. ๋ก์ง์คํฑ ๋งต ๋ฐ๋ณต
x = r * x * (1 - x);
// 4. ๊ทธ๋ํ์ ์ ์ถ๊ฐ
points.push(x);
if (points.length > width) {
points.shift();
}
}
// 5. ๊ทธ๋ฆฌ๊ธฐ
stroke(30, 190, 180);
strokeWeight(2);
noFill();
beginShape();
for (let i = 0; i < points.length; i++) {
let px = i;
// Y์ถ ๋งคํ์ ์ข ๋ ๋ณด๊ธฐ ์ฝ๊ฒ ์กฐ์
let py = map(points[i], 0, 1, height, 0);
vertex(px, py);
}
endShape();
// 6. ์ ๋ณด ํ์ (์๋ต ์์ด ์๋ ์ฝ๋ ์ ์ง)
fill(255);
noStroke();
textAlign(LEFT);
text("r = " + nf(r, 1, 3), 10, 20);
text("x = " + nf(x, 1, 5), 10, 40);
textAlign(CENTER);
text("๋ง์ฐ์ค๋ฅผ ์ข์ฐ๋ก ์์ง์ฌ r ๊ฐ์ ๋ณ๊ฒฝํ์ธ์", width / 2, height - 10);
// 7. r ๊ฐ์ ๋ฐ๋ฅธ ์ํ ์ค๋ช
fill(200, 200, 30);
textAlign(RIGHT);
if (r < 1) {
text("๋ฉธ์ข
", width - 10, 20);
} else if (r < 3) {
text("์์ ", width - 10, 20);
} else if (r < 3.57) {
text("์ง๋", width - 10, 20);
} else {
text("์นด์ค์ค!", width - 10, 20);
}
}
// ๋ง์ฐ์ค๋ฅผ ๋ผ๋ฉด x๋ฅผ ์ด๊ธฐํํ์ฌ BURN-IN ๊ณผ์ ์ ๋ค์ ์์
function mouseReleased() {
x = 0.5;
points = [];
counter = 0;
}

๋ก๋ ์ธ ์ดํธ๋ํฐ๋ 1963๋ ๊ธฐ์ํ์ ์๋์๋ ๋ก๋ ์ธ (Edward Lorenz)๊ฐ ๋๊ธฐ์ ๋๋ฅ(convection) ํ์์ ๋ชจ๋ธ๋งํ๊ธฐ ์ํด ๋จ์ํํ ์ธ ๊ฐ์ ๋น์ ํ ๋ฏธ๋ถ ๋ฐฉ์ ์์์ ํ์ํ์ต๋๋ค.
์ฝ๋๊ฐ ์ฌ์ฉํ๋ ์ธ ๊ฐ์ ๋น์ ํ ๋ฏธ๋ถ ๋ฐฉ์ ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
์ฝ๋๋ ์ด ๋ฏธ๋ถ ๋ฐฉ์ ์์ ์๊ฐ ๊ฐ๊ฒฉ ๋์ ๊ทผ์ฌ์ ์ผ๋ก ๊ณ์ฐํ๋ ์ค์ผ๋ฌ ๋ฐฉ๋ฒ(Euler Method)์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค:
dx = a (y - x) dt;
dy = (x (b - z) - y) dt;
dz = (x y - c z) * dt;
์ฌ๊ธฐ์ , , ๋ ์์คํ
์ ํ๋ผ๋ฏธํฐ์ด๋ฉฐ, ๊ฐ๊ฐ (์๊ทธ๋ง), (๋ก), (๋ฒ ํ)์ ํด๋นํฉ๋๋ค.
๋ก๋ ์ธ ์ดํธ๋ํฐ๋ ์ด์ํ ๋๊ฐ(Strange Attractor)์ ๊ฐ์ฅ ์ ๋ช ํ ์์์ ๋๋ค.
๐์ด์ํ ๋๊ฐ (Strange Attractor)
์๊ฐ์ ์ผ๋ก ์ด ์ดํธ๋ํฐ๋ ๋ ๊ฐ์ ๋ ๊ฐ๋ฅผ ๊ฐ์ง ๋๋น ๋ชจ์์ฒ๋ผ ๋ณด์ ๋๋ค. ์์คํ ์ ์ํ๋ ๋ ๋ ๊ฐ ์ฌ์ด๋ฅผ ๋์์์ด ๋ถ๊ท์นํ๊ฒ ์ํํ๋ฉฐ ๊ถค์ ์ ๋จ๊น๋๋ค.
๐์นด์ค์ค์ ํน์ง (๋๋น ํจ๊ณผ์ ์์ด)
๋ก๋ ์ธ ์ดํธ๋ํฐ์ ์นด์ค์ค์ ํ๋์ ๋ก์ง์คํฑ ๋งต๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด๊ธฐ ์กฐ๊ฑด์ ๋ํ ๊ทน๋์ ๋ฏผ๊ฐ์ฑ์ผ๋ก ์ค๋ช ๋ฉ๋๋ค.
๐์ฝ๋์ ์๊ฐํ
์ฝ๋๋ ์ด 3์ฐจ์ ๊ถค์ ์ ์๊ฐํํฉ๋๋ค.
draw() ๋ฃจํ๋ง๋ค ์๋ก์ด ์ขํ๊ฐ ๊ณ์ฐ๋์ด points ๋ฐฐ์ด์ ์ถ๊ฐ๋ฉ๋๋ค.createCanvas(800, 600, WEBGL);๋ก 3D ํ๊ฒฝ์ ์ค์ ํฉ๋๋ค.beginShape()์ vertex(v.x * 5, v.y * 5, v.z * 5);๋ฅผ ์ฌ์ฉํ์ฌ ์ฐ์๋ ์ ๋ค์ ์ ์ผ๋ก ์ฐ๊ฒฐํ์ฌ ๊ถค์ ์ ๊ทธ๋ฆฝ๋๋ค.colorMode(HSB);์ stroke(hu, 255, 255, 200);๋ฅผ ์ฌ์ฉํ์ฌ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๊ถค์ ์ ์์์ด ๋ณํํ๋๋ก ๋ง๋ค์ด ์๊ฐ์ ์ธ ๊น์ด์ ํ๋ฆ์ ๋ํฉ๋๋ค.๊ฒฐ๊ณผ์ ์ผ๋ก ํ๋ฉด์๋ ๋ ๊ฐ์ ์ค์ฌ์ ๊ฐ์ง ์๋ฆ๋ต๊ณ ๋ณต์กํ ๋๋น ๋ชจ์์ ๊ถค์ ์ด ๊ทธ๋ ค์ง๊ฒ ๋ฉ๋๋ค. ์ด๋ ๋จ์ํ ์ธ ๊ฐ์ ๊ท์น์ผ๋ก ์ธํด ๋ฐ์ํ๋ ๋ฌดํํ ๋ณต์กํ๊ณ ๋น๋ฐ๋ณต์ ์ธ ํจํด์ ์๊ฐ์ ์ผ๋ก ๋ณด์ฌ์ฃผ๋ ๊ฒ์ ๋๋ค.
let x = 0.01;
let y = 0;
let z = 0;
let a = 10; // ์๊ทธ๋ง
let b = 28; // ๋ก
let c = 8 / 3; // ๋ฒ ํ
let points = [];
let dt = 0.01;
function setup() {
createCanvas(800, 600, WEBGL);
colorMode(HSB);
}
function draw() {
background(0);
// ๋ก๋ ์ธ ๋ฐฉ์ ์
let dx = a * (y - x) * dt;
let dy = (x * (b - z) - y) * dt;
let dz = (x * y - c * z) * dt;
x += dx;
y += dy;
z += dz;
points.push(createVector(x, y, z));
// ์ต๋ ์ ๊ฐ์ ์ ํ
if (points.length > 3000) {
points.shift();
}
// ์นด๋ฉ๋ผ ํ์
rotateY(frameCount * 0.003);
rotateX(-0.5);
// ์ ๋ค์ ์ ์ผ๋ก ์ฐ๊ฒฐ
strokeWeight(1.5);
noFill();
beginShape();
for (let i = 0; i < points.length; i++) {
let v = points[i];
let hue = map(i, 0, points.length, 0, 255);
stroke(hue, 255, 255, 200);
vertex(v.x * 5, v.y * 5, v.z * 5);
}
endShape();
// ํ์ฌ ์์น ๊ฐ์กฐ
push();
noStroke();
fill(255);
translate(x * 5, y * 5, z * 5);
sphere(3);
pop();
}

์ธ ์ ์()๊ฐ ๋ฏธ์ธํ ์ฐจ์ด์์ ์ถ๋ฐํ์ฌ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๊ถค์ ์ด ๊ธ๊ฒฉํ๊ฒ ๋ฒ์ด์ง๋ ์นด์ค์ค ์์คํ ์ ์์์ ๋๋ค. ์ด p5.js ์ฝ๋๋ ์ด๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์ฑ์ ์๊ฐํํ ๋ฟ๋ง ์๋๋ผ, ์์คํ ์ด ์ผ๋ง๋ ๋น ๋ฅด๊ฒ ์นด์ค์ค๋ก ์ดํํ๋์ง๋ฅผ ๋ํ๋ด๋ ํต์ฌ ์งํ์ธ ๋ฆฌ์ํธ๋ ธํ ์ง์(Lyapunov Exponent)๋ฅผ ๊ทผ์ฌ์ ์ผ๋ก ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
์์คํ
: ChaosParticle ํด๋์ค ๋ด์์ ๋ก์ง์คํฑ ๋งต์ด ๋ ์ฐจ์(stateX, stateY)์ ๋
๋ฆฝ์ ์ผ๋ก ์ ์ฉ๋ฉ๋๋ค.
ํต์ฌ ์๋ฆฌ:
stateX, stateY)์์ ์์ํ๋ฉฐ, ๊ทธ ์ฐจ์ด๋ ์ด๋ผ๋ ๊ทน๋๋ก ๋ฏธ์ธํ ๊ฐ์
๋๋ค.update() ํจ์์์ ์์น ๊ฒฝ๊ณ๋ฅผ ํ ๋ฌ์ค(Torus) ํํ๋ก ์ฒ๋ฆฌํ์ฌ, ์
์๊ฐ ํ๋ฉด ๊ฐ์ฅ์๋ฆฌ์์ ์ฌ๋ผ์ง๋ฉด ๋ฐ๋ํธ์์ ๋ํ๋ ๊ถค์ ์ ์ฐ์์ฑ์ ์ ์งํฉ๋๋ค.์๊ฐํ: ์
์์ ๋ด๋ถ ์ํ ๋ณํ(stateX, stateY)๊ฐ ์
์์ ์๋(vx, vy)๋ก ๋ณํ๋์ด ํ๋ฉด์์ ๊ถค์ ์ ๋ง๋ญ๋๋ค.
๋ฆฌ์ํธ๋ ธํ ์ง์๋ ์นด์ค์ค ์ด๋ก ์์ ์์คํ ์ ์์ธก ๋ถ๊ฐ๋ฅ์ฑ ์ ๋๋ฅผ ๋ํ๋ด๋ ๊ฐ์ฅ ์ค์ํ ์ฒ๋์ ๋๋ค.
์ฝ๋์์ ๋ฆฌ์ํธ๋ ธํ ์ง์๋ฅผ ๊ทผ์ฌ์ ์ผ๋ก ๊ณ์ฐํ๋ ๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
// ๋ฆฌ์ํธ๋
ธํ ์ง์ ๊ณ์ฐ
if (frameCount > 0 && maxDistance > 0) {
let lyapunov = Math.log(maxDistance / 0.000001) / frameCount;
text("๋ฆฌ์ํธ๋
ธํ ์ง์: " + nf(lyapunov, 0, 4), 20, 90);
}
์ด ์ฝ๋๋ ์์์ ์ค๋ช ํ ๊ณต์์ ์ ๋ํด ์ ๋ฆฌํ ํ, ์ด์ฐ์ ์ธ ์๊ฐ ๋จ๊ณ(ํ๋ ์ ์ )์ ๋ง์ถฐ ๊ณ์ฐํฉ๋๋ค.
lyapunov ๊ฐ์ด ์์๋ก ์์ ๋๋ค๋ฉด, ์ด ๋ก์ง์คํฑ ๋งต ์์คํ
์ ๊ฐ๋ ฅํ ์นด์ค์ค์ ํ๋์ ํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.let particles = [];
let maxDistance = 0;
function setup() {
createCanvas(800, 600);
colorMode(RGB);
// 0.5๋ฅผ ํผํ ๋น๋์นญ์ ์ธ ์ด๊ธฐ ์ํ
let baseStateX = 0.3;
let baseStateY = 0.9;
let epsilon = 0.000001; // ๋งค์ฐ ์์ ์ด๊ธฐ ์ฐจ์ด
// ์ธ ๊ฐ์ ์
์ ์์ฑ - ๊ฐ๊ฐ ๋ฏธ์ธํ๊ฒ ๋ค๋ฅธ ์ด๊ธฐ ์ํ
particles.push(new ChaosParticle(baseStateX, baseStateY, color(255, 0, 0)));
particles.push(
new ChaosParticle(baseStateX + epsilon, baseStateY, color(0, 255, 0))
);
particles.push(
new ChaosParticle(baseStateX, baseStateY + epsilon, color(0, 0, 255))
);
}
function draw() {
// ๋ฐํฌ๋ช
๋ฐฐ๊ฒฝ (์์ ํจ๊ณผ)
background(0, 25);
// ์
์ ์
๋ฐ์ดํธ ๋ฐ ํ์
for (let p of particles) {
p.update();
p.show();
}
// ์
์๋ค ๊ฐ์ ์ต๋ ๊ฑฐ๋ฆฌ ๊ณ์ฐ
maxDistance = 0;
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
let d = dist(
particles[i].x,
particles[i].y,
particles[j].x,
particles[j].y
);
maxDistance = max(maxDistance, d);
}
}
// ์ ๋ณด ํ์
fill(255);
noStroke();
textSize(14);
textAlign(LEFT);
text("์ด๊ธฐ ์ํ ์ฐจ์ด: 1.0e-6", 20, 30);
text("๊ฒฝ๊ณผ ์๊ฐ: " + nf(frameCount / 60, 0, 1) + "์ด", 20, 50);
text("์
์ ๊ฐ ์ต๋ ๊ฑฐ๋ฆฌ: " + nf(maxDistance, 0, 1) + "px", 20, 70);
// ๋ฆฌ์ํธ๋
ธํ ์ง์ ๊ณ์ฐ
if (frameCount > 0 && maxDistance > 0) {
let lyapunov = Math.log(maxDistance / 0.000001) / frameCount;
text("๋ฆฌ์ํธ๋
ธํ ์ง์: " + nf(lyapunov, 0, 4), 20, 90);
}
// ์ค๋ช
textSize(12);
fill(200);
text("๋นจ๊ฐ, ์ด๋ก, ํ๋: 10โปโถ ์ฐจ์ด๋ก ์์ํ ์ธ ์
์", 20, height - 40);
text("๋ก์ง์คํฑ ๋งต (r=3.99) ์ฌ์ฉ - ์์ ํ ์นด์ค์ค ์์ญ", 20, height - 20);
}
// ๋ก์ง์คํฑ ๋งต ํจ์
function logisticMap(x, r) {
return r * x * (1 - x);
}
class ChaosParticle {
constructor(stateX, stateY, col) {
// ๋ก์ง์คํฑ ๋งต์ ๋ด๋ถ ์ํ (0~1 ์ฌ์ด)
this.stateX = stateX;
this.stateY = stateY;
// ํ๋ฉด ์์น
this.x = width / 2;
this.y = height / 2;
this.col = col;
this.trail = [];
// ์นด์ค์ค ํ๋ผ๋ฏธํฐ
this.r = 3.99; // ์์ ํ ์นด์ค์ค ์์ญ
}
update() {
// ๋ก์ง์คํฑ ๋งต์ ๊ฐ ์ฐจ์์ ๋
๋ฆฝ์ ์ผ๋ก ์ ์ฉ
this.stateX = logisticMap(this.stateX, this.r);
this.stateY = logisticMap(this.stateY, this.r);
// ์ํ๋ฅผ ์๋๋ก ๋ณํ (-1 ~ 1 ๋ฒ์๋ฅผ -4 ~ 4๋ก ํ๋)
let vx = (this.stateX - 0.5) * 8;
let vy = (this.stateY - 0.5) * 8;
// ์์น ์
๋ฐ์ดํธ
this.x += vx;
this.y += vy;
// ํ๋ฉด ๊ฒฝ๊ณ ์ฒ๋ฆฌ (ํ ๋ฌ์ค ํํ)
if (this.x < 0) this.x = width;
if (this.x > width) this.x = 0;
if (this.y < 0) this.y = height;
if (this.y > height) this.y = 0;
// ๊ถค์ ์ ์ฅ
this.trail.push(createVector(this.x, this.y));
if (this.trail.length > 100) {
this.trail.shift();
}
}
show() {
// ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ
if (this.trail.length > 1) {
stroke(red(this.col), green(this.col), blue(this.col), 64);
strokeWeight(1);
noFill();
beginShape();
for (let v of this.trail) {
vertex(v.x, v.y);
}
endShape();
}
// ํ์ฌ ์์น
fill(this.col);
noStroke();
circle(this.x, this.y, 6);
}
}
// ๋ง์ฐ์ค ํด๋ฆญ์ผ๋ก ์ฌ์์
function mousePressed() {
setup();
}

์ด์ค ์ง์๋ ๋ ๊ฐ์ ์ง์(pendulum)๊ฐ ์ฐจ๋ก๋ก ์ฐ๊ฒฐ๋์ด ์๋ ์์คํ ์ ๋๋ค. ์ฒซ ๋ฒ์งธ ์ง์๊ฐ ๊ณ ์ ๋ ์ ์ ๋งค๋ฌ๋ ค ์๊ณ , ๋ ๋ฒ์งธ ์ง์๊ฐ ์ฒซ ๋ฒ์งธ ์ง์์ ๋์ ๋งค๋ฌ๋ ค ์์ต๋๋ค. ์ด์ค ์ง์๋ ๋จ์ํ ๋ฌผ๋ฆฌ ๋ฒ์น์ผ๋ก๋ ์ผ๋ง๋ ๋ณต์กํ๊ณ ์์ธก ๋ถ๊ฐ๋ฅํ ์์ง์, ์ฆ ์นด์ค์ค(Chaos)๊ฐ ๋ฐ์ํ ์ ์๋์ง ๋ณด์ฌ์ฃผ๋ ๋ํ์ ์ธ ์์์ ๋๋ค.
sin, cos)๋ฅผ ํฌํจํ๋ ๋ณต์กํ ๋น์ ํ ๋ฏธ๋ถ ๋ฐฉ์ ์์
๋๋ค.์ฝ๋๊ฐ angleA1๊ณผ angleA2๋ฅผ ๊ณ์ฐํ๋ ๋ถ๋ถ์ ์ด์ค ์ง์์ ๊ฐ๊ฐ์๋(, )๋ฅผ ๊ตฌํ๋ ๋ณต์กํ ๊ณต์์
๋๋ค.
์ด ๋ณต์กํ ๊ณ์ฐ์ ํตํด ๊ฐ๊ฐ์๋๋ฅผ ๊ตฌํ๊ณ , ์ด๋ฅผ ์๊ฐ์ ๋ฐ๋ผ ์ ๋ถํ์ฌ ๊ฐ์๋์ ๊ฐ๋๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค:
angleV1 += angleA1; // ๊ฐ๊ฐ์๋๋ฅผ ๊ฐ์๋์ ๋ํจ
angleV2 += angleA2;
angle1 += angleV1; // ๊ฐ์๋๋ฅผ ๊ฐ๋์ ๋ํจ
angle2 += angleV2;
์ด์ค ์ง์๋ ๋ก๋ ์ธ ์ดํธ๋ํฐ, ๋ก์ง์คํฑ ๋งต๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์ฑ์ ๊ทน์ ์ผ๋ก ๋ณด์ฌ์ค๋๋ค.
mousePressed() ํจ์:angle1 = PI / 2 + random(-0.1, 0.1);
angle2 = PI / 2 + random(-0.1, 0.1);
์ด ์ฝ๋๋ ๋ง์ฐ์ค๋ฅผ ํด๋ฆญํ ๋๋ง๋ค (์ํ) ์์น๋ฅผ ๊ธฐ์ค์ผ๋ก -0.1์์ 0.1 ๋ผ๋์ ์ฌ์ด์ ๋งค์ฐ ์์ ๋ฌด์์ ํธ์ฐจ๋ฅผ ์ด๊ธฐ ๊ฐ๋์ ๋ถ์ฌํฉ๋๋ค.
m2)์ ๊ถค์ ์ trail ๋ฐฐ์ด์ ์ ์ฅํ๊ณ ํ๋ฉด์ ๊ทธ๋ฆฝ๋๋ค. ํด๋ฆญ ํ ๋ช ์ด ๋์์ ๊ถค์ ์ด ๋น์ทํ๊ฒ ๋ณด์ผ ์ ์์ง๋ง, ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ค๋ฅธ ํด๋ฆญ์์ ์์๋ ๊ถค์ ๊ณผ๋ ์์ ํ ๋ค๋ฅธ ํจํด์ ์์ฑํ๋ฉฐ ์์ธก ๋ถ๊ฐ๋ฅํ๊ฒ ์์ง์ด๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.angleV1 *= 0.999;
angleV2 *= 0.999;
์ด ์ฝ๋๋ ๊ฐ์๋์ 0.999๋ฅผ ๊ณฑํ์ฌ ๊ณต๊ธฐ ์ ํญ์ด๋ ๋ง์ฐฐ๋ก ์ธํ ๊ฐ์ (Damping)๋ฅผ ๋ชจ๋ฐฉํฉ๋๋ค. ๊ฐ์ ๊ฐ ์๋ค๋ฉด ์๋์ง๊ฐ ๋ณด์กด๋์ด ์์ํ ์์ง์ด์ง๋ง, ํ์ค์ ์ธ ๊ฐ์ ๊ฐ ๋ค์ด๊ฐ๋ฉด ๋ณต์กํ ์์ง์์ ๋ณด์ด๋ค๊ฐ ๊ฒฐ๊ตญ ์๋์ง๋ฅผ ์๊ณ ๋ฉ์ถ๊ฒ ๋ฉ๋๋ค.
ํ์ฌ๋ ๊ถค์ ์ด ๋จ์์ด์ง๋ง, ๊ถค์ ์ ์๋(angleV2)์ ๋ฐ๋ผ ์์์ ๋ณํ์ํค๊ฑฐ๋, ๊ถค์ ์ ๋ฐ๋๋ฅผ ์ด์ฉํ์ฌ ์ง๊ฐ ์๋ ๋ฐฐ๊ฒฝ์ ์์ฑํ๋ ๋ฐ ํ์ฉํ ์ ์์ต๋๋ค.
๋ ์ผ์ค ์ง์(Triple Pendulum)๋ก ํ์ฅํ์ฌ ์นด์ค์ค ํจ๊ณผ๋ฅผ ๋์ฑ ์ฆํญ์ํฌ ์๋ ์์ต๋๋ค.
let angle1 = Math.PI / 2;
let angle2 = Math.PI / 2;
let angleV1 = 0;
let angleV2 = 0;
let angleA1 = 0;
let angleA2 = 0;
let r1 = 125; // ์ฒซ ๋ฒ์งธ ๋ง๋ ๊ธธ์ด
let r2 = 145; // ๋ ๋ฒ์งธ ๋ง๋ ๊ธธ์ด
let m1 = 20; // ์ฒซ ๋ฒ์งธ ์ง๋
let m2 = 30; // ๋ ๋ฒ์งธ ์ง๋
let g = 1; // ์ค๋ ฅ
let cx, cy;
let trail = [];
function setup() {
createCanvas(800, 600);
cx = width / 2;
cy = 150;
}
function draw() {
background(0, 20); // ์์ ํจ๊ณผ
// ๋๋ธ ํ๋๋ผ ์ด๋ ๋ฐฉ์ ์ (๋ณต์กํ ์นด์ค์ค ์์คํ
)
let num1 = -g * (2 * m1 + m2) * sin(angle1);
let num2 = -m2 * g * sin(angle1 - 2 * angle2);
let num3 = -2 * sin(angle1 - angle2) * m2;
let num4 =
angleV2 * angleV2 * r2 + angleV1 * angleV1 * r1 * cos(angle1 - angle2);
let den = r1 * (2 * m1 + m2 - m2 * cos(2 * angle1 - 2 * angle2));
angleA1 = (num1 + num2 + num3 * num4) / den;
num1 = 2 * sin(angle1 - angle2);
num2 = angleV1 * angleV1 * r1 * (m1 + m2);
num3 = g * (m1 + m2) * cos(angle1);
num4 = angleV2 * angleV2 * r2 * m2 * cos(angle1 - angle2);
den = r2 * (2 * m1 + m2 - m2 * cos(2 * angle1 - 2 * angle2));
angleA2 = (num1 * (num2 + num3 + num4)) / den;
angleV1 += angleA1;
angleV2 += angleA2;
angle1 += angleV1;
angle2 += angleV2;
// ๊ฐ์ (์๋์ง ์์ค)
angleV1 *= 0.999;
angleV2 *= 0.999;
// ์ขํ ๊ณ์ฐ
let x1 = r1 * sin(angle1) + cx;
let y1 = r1 * cos(angle1) + cy;
let x2 = x1 + r2 * sin(angle2);
let y2 = y1 + r2 * cos(angle2);
// ๊ถค์ ์ ์ฅ
trail.push(createVector(x2, y2));
if (trail.length > 500) {
trail.shift();
}
// ๊ถค์ ๊ทธ๋ฆฌ๊ธฐ
stroke(30, 210, 180, 100);
strokeWeight(2);
noFill();
beginShape();
for (let v of trail) {
vertex(v.x, v.y);
}
endShape();
// ํ๋๋ผ ๊ทธ๋ฆฌ๊ธฐ
stroke(255);
strokeWeight(2);
line(cx, cy, x1, y1);
line(x1, y1, x2, y2);
fill(255);
circle(cx, cy, 8);
noStroke();
fill(255);
circle(x1, y1, m1);
noStroke();
fill(255);
circle(x2, y2, m2);
// ์ ๋ณด ํ์
fill(255);
noStroke();
textAlign(CENTER);
text("ํด๋ฆญํ๋ฉด ์ด๊ธฐ ์กฐ๊ฑด์ ๋ฆฌ์
ํฉ๋๋ค", width/2, height-20);
}
function mousePressed() {
// ์ด๊ธฐ ์กฐ๊ฑด์ ์ฝ๊ฐ ๋ค๋ฅด๊ฒ ๋ฆฌ์
angle1 = PI / 2 + random(-0.1, 0.1);
angle2 = PI / 2 + random(-0.1, 0.1);
angleV1 = 0;
angleV2 = 0;
trail = [];
}


์ด ์ฝ๋์์๋ ์นด์ค์ค ์ด๋ก ๊ณผ ํ๋ํ ๊ธฐํํ์ด ์ด๋ป๊ฒ ๋ฐ์ ํ๊ฒ ์ฐ๊ฒฐ๋์ด ์๋์ง ๋ณด์ฌ์ค๋๋ค.
์ด ์ฝ๋๊ฐ ์์ฑํ๋ ํจํด์ ๋ํ์ ์ธ ํ๋ํ์ธ ์์ดํ์คํค ์ผ๊ฐํ(Sierpinski Triangle)์
๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ํจํด์ด '์นด์ค์ค ๊ฒ์'์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ถ๋ฆฌ๋ ์ด์ ๋ ๊ทธ ์์ฑ ๊ณผ์ ์ ์์ต๋๋ค.
์ด ์ฝ๋๋ ์นด์ค์ค ๊ฒ์์ด๋ผ๋ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํ๋ฉฐ, ์ด ๊ณผ์ ์์ ๋ฌด์์์ฑ(Randomness)๊ณผ ๊ฒฐ์ ๋ก ์ ๊ตฌ์กฐ(Deterministic Structure)๊ฐ ๊ฒฐํฉ๋์ด ์นด์ค์ค์ ์ธ ์์๊ฐ ๋์ ๋ฉ๋๋ค.
current)์์ ์์ํฉ๋๋ค.random(vertices)) ์ ํํฉ๋๋ค.current = lerp(current.x, vertex.x, 0.5);์ด ์๊ณ ๋ฆฌ์ฆ์ด '์นด์ค์ค'์ ๊ด๋ จ๋๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ฆ, ์นด์ค์ค ๊ฒ์์ ๋จ๊ธฐ์ ์ผ๋ก๋ ๋ฌด์์์ฑ(์นด์ค์ค)์ ๋ณด์ด์ง๋ง, ์ฅ๊ธฐ์ ์ผ๋ก๋ ๊ณ ์ ๋ ํจํด(์ดํธ๋ํฐ/ํ๋ํ)์ผ๋ก ์๋ ดํ๋, ์ง์ ์์ ๋ฌด์ง์๋ฅผ ๋ณด์ฌ์ฃผ๋ ์์คํ ์ ๋๋ค.
์ด ์ฝ๋์ ์นด์ค์ค ๊ฒ์์ ์ ์ผ๊ฐํ(3๊ฐ์ ๊ผญ์ง์ )์ ์ฌ์ฉํ์ง๋ง, ์ฌ๊ฐํ(4๊ฐ์ ๊ผญ์ง์ )์ ์ฌ์ฉํ๋ฉด ์์ดํ์คํค ์นดํซ(Sierpinski Carpet)์ด, ํน์ 5๊ฐ ์ด์์ ๊ผญ์ง์ ์ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ๊ท์น(์: ๋ฐ๋ก ์ ์ ์ ํํ ๊ผญ์ง์ ์ ๋ค์ ์ ํํ์ง ์์)์ ์ ์ฉํ๋ฉด ๋์ฑ ํฅ๋ฏธ๋กญ๊ณ ๋ณต์กํ ํ๋ํ ํจํด์ ๋ง๋ค ์ ์์ต๋๋ค.
let points = [];
let current;
let vertices = [];
function setup() {
createCanvas(800, 800);
background(0);
// ์ ์ผ๊ฐํ์ ์ธ ๊ผญ์ง์
vertices.push(createVector(width / 2, 50));
vertices.push(createVector(50, height - 50));
vertices.push(createVector(width - 50, height - 50));
// ์์์ ์์์
current = createVector(random(width), random(height));
}
function draw() {
// ๋งค ํ๋ ์๋ง๋ค ์ฌ๋ฌ ์ ์ ์ฐ์ด ๋น ๋ฅด๊ฒ ํจํด ์์ฑ
for (let i = 0; i < 100; i++) {
stroke(0, 255, 200);
strokeWeight(1);
point(current.x, current.y);
// ๋ฌด์์๋ก ๊ผญ์ง์ ํ๋ ์ ํ
let vertex = random(vertices);
// ํ์ฌ ์ ๊ณผ ์ ํ๋ ๊ผญ์ง์ ์ ์ค์ ์ผ๋ก ์ด๋
current.x = lerp(current.x, vertex.x, 0.5);
current.y = lerp(current.y, vertex.y, 0.5);
}
// ๊ผญ์ง์ ํ์
fill(255);
noStroke();
for (let v of vertices) {
circle(v.x, v.y, 10);
}
// ์ ๋ณด ํ์
if (frameCount < 180) {
fill(255);
textAlign(CENTER);
text("๋ฌด์์ ์ ์ด ๋ง๋๋ ํ๋ํ ํจํด", width / 2, 20);
text("์นด์ค์ค ๊ฒ์ (Chaos Game)", width / 2, 40);
}
}
์๋๋ ๋ค๊ฐํ ์นด์ค์ค ๊ฒ์์ ์์ ์ฝ๋์ ๋๋ค.
let current;
let vertices = [];
let lastVertexIndex = -1; // ์ด์ ์ ์ ํ๋ ๊ผญ์ง์ ์ ์ธ๋ฑ์ค
function setup() {
createCanvas(800, 800);
background(0);
// ๊ผญ์ง์ ๊ณ์ฐ
let numVertices = 19;
let radius = 350;
let center = createVector(width / 2, height / 2);
for (let i = 0; i < numVertices; i++) {
let angle = map(i, 0, numVertices, -HALF_PI, TWO_PI - HALF_PI);
let x = center.x + radius * cos(angle);
let y = center.y + radius * sin(angle);
vertices.push(createVector(x, y));
}
// ์์์ ์์์ (์ค์ ๊ทผ์ฒ)
current = createVector(
center.x + random(-10, 10),
center.y + random(-10, 10)
);
}
function draw() {
// ๋งค ํ๋ ์๋ง๋ค ์ฌ๋ฌ ์ ์ ์ฐ์ด ๋น ๋ฅด๊ฒ ํจํด ์์ฑ
for (let i = 0; i < 200; i++) {
stroke(255, 165, 0); // ์์์ ์ฃผํฉ์ ๊ณ์ด๋ก ๋ณ๊ฒฝ
strokeWeight(1);
point(current.x, current.y);
// 1. ๊ท์น์ ๋ฐ๋ผ ๋ค์ ๊ผญ์ง์ ์ธ๋ฑ์ค ์ ํ
let nextVertexIndex = selectNextVertexIndex(lastVertexIndex);
let vertex = vertices[nextVertexIndex];
// 2. ํ์ฌ ์ ๊ณผ ์ ํ๋ ๊ผญ์ง์ ์ ์ค์ ์ด๋ (ํฉ๊ธ๋น ๊ทผ์ฌ์น)
// ๋น์จ์ 0.5 ๋์ 0.618034๋ก ์ฌ์ฉํ๋ฉด ๋ ์ ํํ ํ๋ํ์ด ์์ฑ๋ฉ๋๋ค.
let moveRatio = 0.618;
current.x = lerp(current.x, vertex.x, moveRatio);
current.y = lerp(current.y, vertex.y, moveRatio);
// 3. ๋ง์ง๋ง ๊ผญ์ง์ ์ธ๋ฑ์ค ์
๋ฐ์ดํธ
lastVertexIndex = nextVertexIndex;
}
// ๊ผญ์ง์ ํ์
fill(255);
noStroke();
for (let v of vertices) {
circle(v.x, v.y, 8);
}
}
// ๋ค์ ๊ผญ์ง์ ์ ์ ํํ๋ ํจ์ (์ ํ ๊ท์น ์ ์ฉ)
function selectNextVertexIndex(lastIndex) {
let numVertices = vertices.length;
let availableIndices = [];
for (let i = 0; i < numVertices; i++) {
// 1. ์ด์ํ ๋ ๊ผญ์ง์ ์ ์ธ๋ฑ์ค๋ฅผ ๊ณ์ฐ (๋ชจ๋๋ฌ ์ฐ์ฐ์ผ๋ก ์ํ)
let prevNeighbor = (lastIndex - 1 + numVertices) % numVertices;
let nextNeighbor = (lastIndex + 1) % numVertices;
// 2. ํ์ฌ ์ ํํ ๊ผญ์ง์ ์ธ๋ฑ์ค๊ฐ ์ด์์ด ์๋ ๊ฒฝ์ฐ๋ง ํ์ฉ
if (i !== prevNeighbor && i !== nextNeighbor) {
availableIndices.push(i);
}
}
// ํ์ฉ๋ ๊ผญ์ง์ ์ค์์ ๋ฌด์์๋ก ํ๋ ์ ํํ์ฌ ์ธ๋ฑ์ค ๋ฐํ
let randomIndex = floor(random(availableIndices.length));
return availableIndices[randomIndex];
}
// ๋ง์ฐ์ค ํด๋ฆญ์ผ๋ก ์ฌ์์
function mousePressed() {
setup();
}