๐ŸŽ“11์ฃผ์ฐจ: ์นด์˜ค์Šค(Chaos)

BamgasiJMยท2025๋…„ 11์›” 6์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
22/67
post-thumbnail

"๋‹จ์ˆœํ•œ ๊ทœ์น™์ด ๋งŒ๋“ค์–ด๋‚ด๋Š” ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ๋ณต์žกํ•œ ํ–‰๋™, ํ•˜์ง€๋งŒ ๊ทธ ์†์—์„œ ๋ฐœ๊ฒฌ๋˜๋Š” ์ˆจ๊ฒจ์ง„ ํŒจํ„ด"์ด์—์š”.
์ด๊ฒƒ์€ ๋‚ ์”จ, ์ฃผ์‹ ์‹œ์žฅ, ์‹ฌ์žฅ ๋ฐ•๋™, ๋‚œ๋ฅ˜ ๋“ฑ ์ž์—ฐ์˜ ๋ณต์žกํ•œ ํ˜„์ƒ์„ ์„ค๋ช…ํ•˜๋Š” ํ•ต์‹ฌ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.

ํ•ญ๋ชฉ๋‚ด์šฉ
์ด๋ฆ„Chaos Theory (์นด์˜ค์Šค ์ด๋ก )
์˜๋ฏธ๊ฒฐ์ •๋ก ์ ์ด์ง€๋งŒ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์‹œ์Šคํ…œ์˜ ํ–‰๋™์„ ์—ฐ๊ตฌํ•˜๋Š” ์ด๋ก 
ํ•ต์‹ฌ ์•„์ด๋””์–ด์ดˆ๊ธฐ ์กฐ๊ฑด์˜ ๋ฏธ์„ธํ•œ ์ฐจ์ด๊ฐ€ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ์—„์ฒญ๋‚˜๊ฒŒ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ฆ (๋‚˜๋น„ํšจ๊ณผ)
๊ฒฐ๊ณผ ํŒจํ„ด๋ฌด์งˆ์„œํ•ด ๋ณด์ด์ง€๋งŒ ์ผ์ •ํ•œ ๊ตฌ์กฐ(์–ดํŠธ๋ž™ํ„ฐ)๋ฅผ ๊ฐ€์ง„ ํŒจํ„ด
๊ด€๋ จ ๊ฐœ๋…๋‚˜๋น„ํšจ๊ณผ(butterfly effect), ์ŠคํŠธ๋ ˆ์ธ์ง€ ์–ดํŠธ๋ž™ํ„ฐ(strange attractor), ์ดˆ๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์„ฑ

๐Ÿ“– ์นด์˜ค์Šค์˜ ๊ธฐ๋ณธ ์›๋ฆฌ

1๏ธโƒฃ ๊ฒฐ์ •๋ก ์  ์‹œ์Šคํ…œ
โ†’ ๋ช…ํ™•ํ•œ ๊ทœ์น™์— ๋”ฐ๋ผ ์›€์ง์ž„
โ†’ ๋žœ๋ค์ด ์•„๋‹ˆ๋ผ ์ˆ˜ํ•™์  ๊ณต์‹์œผ๋กœ ์ •์˜๋จ

2๏ธโƒฃ ์ดˆ๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์„ฑ (๋‚˜๋น„ํšจ๊ณผ)
โ†’ ์‹œ์ž‘์ ์˜ ์•„์ฃผ ์ž‘์€ ์ฐจ์ด๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ์™„์ „ํžˆ ๋ฐ”๊ฟˆ
โ†’ "๋ฒ ์ด์ง•์˜ ๋‚˜๋น„ ํ•œ ๋งˆ๋ฆฌ๊ฐ€ ๋‰ด์š•์— ํญํ’์„ ๋งŒ๋“ ๋‹ค"

3๏ธโƒฃ ์žฅ๊ธฐ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅ
โ†’ ๊ทœ์น™์„ ์•Œ์•„๋„ ๋ฏธ๋ž˜๋ฅผ ์ •ํ™•ํžˆ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์Œ
โ†’ ์ปดํ“จํ„ฐ๋กœ๋„ ๊ณ„์‚ฐ์˜ ํ•œ๊ณ„๊ฐ€ ์žˆ์Œ

4๏ธโƒฃ ์ŠคํŠธ๋ ˆ์ธ์ง€ ์–ดํŠธ๋ž™ํ„ฐ
โ†’ ๋ฌด์งˆ์„œ ์†์—์„œ ๋ฐœ๊ฒฌ๋˜๋Š” ์ˆจ๊ฒจ์ง„ ๊ตฌ์กฐ
โ†’ ์‹œ์Šคํ…œ์ด ํŠน์ • ํŒจํ„ด์œผ๋กœ ์ˆ˜๋ ดํ•˜๋ ค๋Š” ๊ฒฝํ–ฅ

5๏ธโƒฃ ํ”„๋ž™ํƒˆ ๊ตฌ์กฐ
โ†’ ์นด์˜ค์Šค ์‹œ์Šคํ…œ์€ ์ข…์ข… ํ”„๋ž™ํƒˆ ํŒจํ„ด์„ ์ƒ์„ฑ
โ†’ ์–ด๋–ค ์Šค์ผ€์ผ์—์„œ ๋ณด๋“  ๋น„์Šทํ•œ ๊ตฌ์กฐ๊ฐ€ ๋ฐ˜๋ณต๋จ


๐Ÿ”— ์ž์—ฐ ํ˜„์ƒ๊ณผ์˜ ์—ฐ๊ฒฐ

๐ŸŒช๏ธ ๋‚ ์”จ์ดˆ๊ธฐ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์˜ˆ์ธก์ด ๋ฉฐ์น  ์ด์ƒ ๋ถˆ๊ฐ€๋Šฅ
๐Ÿ’ง ๋‚œ๋ฅ˜๋ฌผ์ด๋‚˜ ๊ณต๊ธฐ์˜ ๋ณต์žกํ•œ ์†Œ์šฉ๋Œ์ด ํŒจํ„ด
๐Ÿ’“ ์‹ฌ์žฅ ๋ฐ•๋™๊ฑด๊ฐ•ํ•œ ์‹ฌ์žฅ์€ ์•ฝํ•œ ์นด์˜ค์Šค ํŒจํ„ด์„ ๋ณด์ž„
๐ŸŒŠ ์ฃผ์‹ ์‹œ์žฅ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ์š”์ธ์ด ์–ฝํ˜€ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅ
๐Ÿช 3์ฒด ๋ฌธ์ œ์„ธ ๊ฐœ์˜ ์ฒœ์ฒด๊ฐ€ ๋งŒ๋“œ๋Š” ์นด์˜ค์Šค์  ๊ถค๋„

๐Ÿ”น ์˜ˆ์ œ 1: ๋กœ์ง€์Šคํ‹ฑ ๋งต (Logistic Map)

๋กœ์ง€์Šคํ‹ฑ ๋งต์€ ์›๋ž˜ ๊ฐœ์ฒด๊ตฐ ๋™ํƒœ(Population Dynamics)๋ฅผ ๋ชจ๋ธ๋งํ•˜๊ธฐ ์œ„ํ•ด ์ƒ๋ฌผํ•™์—์„œ ๋„์ž…๋œ ๋‹จ์ˆœํ•œ 1์ฐจ์› ๋ฐ˜๋ณต ๋ฐฉ์ •์‹(Iterative Equation)์ž…๋‹ˆ๋‹ค.

1. ๋กœ์ง€์Šคํ‹ฑ ๋ฐฉ์ •์‹

์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ํ•ต์‹ฌ ์ˆ˜์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

xn+1=rxn(1โˆ’xn)x_{n+1} = r x_n (1 - x_n)

  • xnx_n (๊ฐœ์ฒด๊ตฐ ๋ฐ€๋„/๋น„์œจ): ํ˜„์žฌ ์‹œ์ (nn)์˜ ๊ฐœ์ฒด๊ตฐ ํฌ๊ธฐ๋ฅผ ์ตœ๋Œ€ ๊ฐœ์ฒด๊ตฐ ํฌ๊ธฐ์— ๋Œ€ํ•œ ๋น„์œจ๋กœ ๋‚˜ํƒ€๋‚ธ ๊ฐ’์ž…๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ 0๊ณผ 1 ์‚ฌ์ด์˜ ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค (0โ‰คxโ‰ค10 \le x \le 1). ์ฝ”๋“œ์—์„œ๋Š” x ๋ณ€์ˆ˜์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
  • xn+1x_{n+1}: ๋‹ค์Œ ์‹œ์ (n+1n+1)์˜ ๊ฐœ์ฒด๊ตฐ ๋ฐ€๋„์ž…๋‹ˆ๋‹ค.
  • rr (์„ฑ์žฅ๋ฅ  ํŒŒ๋ผ๋ฏธํ„ฐ): ๊ฐœ์ฒด๊ตฐ์˜ ์„ฑ์žฅ๋ฅ ๊ณผ ์ž์› ์ œ์•ฝ(resource limitation)์˜ ๋ณตํ•ฉ์ ์ธ ์˜ํ–ฅ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ๋Š” r ๋ณ€์ˆ˜์— ํ•ด๋‹นํ•˜๋ฉฐ, ๋งˆ์šฐ์Šค ์›€์ง์ž„์œผ๋กœ 0๋ถ€ํ„ฐ 4๊นŒ์ง€ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค.

2. ๋ฐฉ์ •์‹์˜ ์˜๋ฏธ

์ด ๋ฐฉ์ •์‹์€ ๊ฐœ์ฒด๊ตฐ์˜ ์„ฑ์žฅ์„ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์š”์†Œ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค:

  • ์„ฑ์žฅ (Growth): rxnr x_n ๋ถ€๋ถ„์€ ๊ฐœ์ฒด์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ฆ๊ฐ€ํ•˜๋Š” ์„ฑ์žฅ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. rr ๊ฐ’์ด ํด์ˆ˜๋ก ๋‹ค์Œ ์„ธ๋Œ€์˜ ๊ฐœ์ฒด์ˆ˜๊ฐ€ ๋” ์ปค์ง‘๋‹ˆ๋‹ค.
  • ์ œํ•œ (Limitation): (1โˆ’xn)(1 - x_n) ๋ถ€๋ถ„์€ ํ™˜๊ฒฝ ์šฉ๋Ÿ‰(carrying capacity)์— ์˜ํ•œ ์„ฑ์žฅ ์ œํ•œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. xnx_n์ด 1(์ตœ๋Œ€์น˜)์— ๊ฐ€๊นŒ์›Œ์งˆ์ˆ˜๋ก ์ด ํ•ญ์€ 0์— ๊ฐ€๊นŒ์›Œ์ ธ ๊ฐœ์ฒด๊ตฐ ์„ฑ์žฅ์„ ์–ต์ œํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์˜ p5.js ์ฝ”๋“œ๋Š” rr ๊ฐ’์— ๋”ฐ๋ฅธ ๊ฐœ์ฒด๊ตฐ ๋ฐ€๋„(xx)์˜ ์‹œ๊ฐ„ ํ๋ฆ„์„ ๊ทธ๋ž˜ํ”„๋กœ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • rr ๊ฐ’ ์กฐ์ •: r = map(mouseX, 0, width, 0, 4); ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๋งˆ์šฐ์Šค์˜ ๊ฐ€๋กœ ์œ„์น˜(mouseX)๋ฅผ 0๋ถ€ํ„ฐ 4๊นŒ์ง€์˜ rr ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ˜๋ณต ๊ณ„์‚ฐ: x = r * x * (1 - x); ์ฝ”๋“œ๊ฐ€ draw() ํ•จ์ˆ˜(ํ”„๋ ˆ์ž„๋งˆ๋‹ค ์‹คํ–‰) ๋‚ด์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ xx ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋กœ์ง€์Šคํ‹ฑ ๋งต์˜ ๋ฐ˜๋ณต ๊ณผ์ •์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ: ๊ณ„์‚ฐ๋œ xx ๊ฐ’์€ points ๋ฐฐ์—ด์— ์ถ”๊ฐ€๋˜๊ณ , ํ™”๋ฉด์„ ๋„˜์–ด๊ฐ€๋Š” ์˜ค๋ž˜๋œ ๊ฐ’์€ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค (points.shift()).
  • ์‹œ๊ฐํ™”: beginShape()์™€ endShape()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์˜ ๊ฐ’๋“ค์„ ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์„ ์œผ๋กœ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
    • ๊ฐ€๋กœ์ถ•(x์ถ•)์€ ์‹œ๊ฐ„์˜ ํ๋ฆ„ (ํ˜น์€ ๋ฐ˜๋ณต ํšŸ์ˆ˜)์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
    • ์„ธ๋กœ์ถ•(y์ถ•)์€ ๊ฐœ์ฒด๊ตฐ ๋ฐ€๋„ xx์˜ ๊ฐ’ (0๋ถ€ํ„ฐ 1 ์‚ฌ์ด)์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
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;
}

๐Ÿ”น ์˜ˆ์ œ 2: ๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ (Lorenz Attractor)

๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ๋Š” 1963๋…„ ๊ธฐ์ƒํ•™์ž ์—๋“œ์›Œ๋“œ ๋กœ๋ Œ์ธ (Edward Lorenz)๊ฐ€ ๋Œ€๊ธฐ์˜ ๋Œ€๋ฅ˜(convection) ํ˜„์ƒ์„ ๋ชจ๋ธ๋งํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ์ˆœํ™”ํ•œ ์„ธ ๊ฐœ์˜ ๋น„์„ ํ˜• ๋ฏธ๋ถ„ ๋ฐฉ์ •์‹์—์„œ ํƒ„์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

1. ๋กœ๋ Œ์ธ  ๋ฐฉ์ •์‹ (Lorentz Equations)

์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์„ธ ๊ฐœ์˜ ๋น„์„ ํ˜• ๋ฏธ๋ถ„ ๋ฐฉ์ •์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

{dxdt=ฯƒ(yโˆ’x)dydt=x(ฯโˆ’z)โˆ’ydzdt=xyโˆ’ฮฒz\begin{cases} \frac{dx}{dt} = \sigma (y - x) \\ \frac{dy}{dt} = x (\rho - z) - y \\ \frac{dz}{dt} = x y - \beta z \end{cases}

์ฝ”๋“œ๋Š” ์ด ๋ฏธ๋ถ„ ๋ฐฉ์ •์‹์„ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ dtdt ๋™์•ˆ ๊ทผ์‚ฌ์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ์˜ค์ผ๋Ÿฌ ๋ฐฉ๋ฒ•(Euler Method)์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:
dx = a (y - x) dt;
dy = (x (b - z) - y) dt;
dz = (x y - c z) * dt;
์—ฌ๊ธฐ์„œ aa, bb, cc๋Š” ์‹œ์Šคํ…œ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ด๋ฉฐ, ๊ฐ๊ฐ ฯƒ\sigma (์‹œ๊ทธ๋งˆ), ฯ\rho (๋กœ), ฮฒ\beta (๋ฒ ํƒ€)์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

2. ๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ์™€ ์นด์˜ค์Šค

๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ๋Š” ์ด์ƒํ•œ ๋Œ๊ฐœ(Strange Attractor)์˜ ๊ฐ€์žฅ ์œ ๋ช…ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

๐ŸŒ€์ด์ƒํ•œ ๋Œ๊ฐœ (Strange Attractor)

  • ๋Œ๊ฐœ(Attractor): ์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์  (x,y,z)(x, y, z)๊ฐ€ ์‹œ๊ฐ„์ด ํ๋ฆ„์— ๋”ฐ๋ผ ์ˆ˜๋ ดํ•˜๊ฑฐ๋‚˜ ์•ˆ์ •์ ์œผ๋กœ ์›€์ง์ด๋Š” ๊ณต๊ฐ„์ƒ์˜ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.
  • ์ด์ƒํ•œ(Strange): ๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ์˜ ๊ถค์ ์€ ํ”„๋ž™ํƒˆ ๊ตฌ์กฐ(Fractal Structure)๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ฆ‰, ์•„๋ฌด๋ฆฌ ํ™•๋Œ€ํ•ด๋„ ์ž๊ธฐ ์œ ์‚ฌ์„ฑ(Self-Similarity)์„ ๊ฐ€์ง€๋Š” ๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค.

์‹œ๊ฐ์ ์œผ๋กœ ์ด ์–ดํŠธ๋ž™ํ„ฐ๋Š” ๋‘ ๊ฐœ์˜ ๋‚ ๊ฐœ๋ฅผ ๊ฐ€์ง„ ๋‚˜๋น„ ๋ชจ์–‘์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋Š” ๋‘ ๋‚ ๊ฐœ ์‚ฌ์ด๋ฅผ ๋Š์ž„์—†์ด ๋ถˆ๊ทœ์น™ํ•˜๊ฒŒ ์ˆœํ™˜ํ•˜๋ฉฐ ๊ถค์ ์„ ๋‚จ๊น๋‹ˆ๋‹ค.

๐ŸŒ€์นด์˜ค์Šค์˜ ํŠน์ง• (๋‚˜๋น„ ํšจ๊ณผ์˜ ์‹œ์ดˆ)

๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ์˜ ์นด์˜ค์Šค์  ํ–‰๋™์€ ๋กœ์ง€์Šคํ‹ฑ ๋งต๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ดˆ๊ธฐ ์กฐ๊ฑด์— ๋Œ€ํ•œ ๊ทน๋„์˜ ๋ฏผ๊ฐ์„ฑ์œผ๋กœ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค.

  • ๋ฐœ๊ฒฌ ๋ฐฐ๊ฒฝ: ๋กœ๋ Œ์ธ ๊ฐ€ ์ดˆ๊ธฐ๊ฐ’์„ ์†Œ์ˆ˜์  6์ž๋ฆฌ ๋Œ€์‹  3์ž๋ฆฌ๋กœ ๋ฐ˜์˜ฌ๋ฆผํ•˜์—ฌ ๊ณ„์‚ฐ์„ ์‹œ์ž‘ํ–ˆ์„ ๋•Œ, ์‹œ๊ฐ„์ด ์ง€๋‚˜์ž ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์€ ์ฐจ์ด๊ฐ€ ์—„์ฒญ๋‚œ ์ฐจ์ด๋ฅผ ๋‚ณ๋Š” ํ˜„์ƒ์„ ํ›„์— ๋‚˜๋น„ ํšจ๊ณผ(Butterfly Effect)๋ผ๊ณ  ๋ช…๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์นด์˜ค์Šค์  ๊ถค์ : ๊ถค์ ์€ ๋Œ๊ฐœ๋ผ๋Š” ์ œํ•œ๋œ ๊ณต๊ฐ„ ์•ˆ์— ๋จธ๋ฌด๋ฅด์ง€๋งŒ, ์ ˆ๋Œ€ ์ž๊ธฐ ์ž์‹ ์„ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (๋น„์ฃผ๊ธฐ์ ). ๋‘ ๊ฐœ์˜ ๋‚ ๊ฐœ ์ค‘ ์–ด๋А ์ชฝ์œผ๋กœ ์–ผ๋งˆ๋‚˜ ๋จธ๋ฌด๋ฅผ์ง€ ์˜ˆ์ธกํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐ŸŒ€์ฝ”๋“œ์˜ ์‹œ๊ฐํ™”
์ฝ”๋“œ๋Š” ์ด 3์ฐจ์› ๊ถค์ ์„ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • ์  ๊ณ„์‚ฐ: ๋งค draw() ๋ฃจํ”„๋งˆ๋‹ค ์ƒˆ๋กœ์šด (x,y,z)(x, y, z) ์ขŒํ‘œ๊ฐ€ ๊ณ„์‚ฐ๋˜์–ด points ๋ฐฐ์—ด์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  • 3D ์บ”๋ฒ„์Šค: 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();
}

๐Ÿ”น ์˜ˆ์ œ 3: ์ดˆ๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์„ฑ (๋‚˜๋น„ํšจ๊ณผ)

์„ธ ์ž…์ž(x,yx, y)๊ฐ€ ๋ฏธ์„ธํ•œ ์ฐจ์ด์—์„œ ์ถœ๋ฐœํ•˜์—ฌ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ถค์ ์ด ๊ธ‰๊ฒฉํ•˜๊ฒŒ ๋ฒŒ์–ด์ง€๋Š” ์นด์˜ค์Šค ์‹œ์Šคํ…œ์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ์ด p5.js ์ฝ”๋“œ๋Š” ์ดˆ๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์„ฑ์„ ์‹œ๊ฐํ™”ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์‹œ์Šคํ…œ์ด ์–ผ๋งˆ๋‚˜ ๋น ๋ฅด๊ฒŒ ์นด์˜ค์Šค๋กœ ์ดํƒˆํ•˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ•ต์‹ฌ ์ง€ํ‘œ์ธ ๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜(Lyapunov Exponent)๋ฅผ ๊ทผ์‚ฌ์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

1. ์‹œ์Šคํ…œ ๋ฐ ์ดˆ๊ธฐ ์กฐ๊ฑด

  • ์‹œ์Šคํ…œ: ChaosParticle ํด๋ž˜์Šค ๋‚ด์—์„œ ๋กœ์ง€์Šคํ‹ฑ ๋งต์ด ๋‘ ์ฐจ์›(stateX, stateY)์— ๋…๋ฆฝ์ ์œผ๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

    • ํŒŒ๋ผ๋ฏธํ„ฐ rr์€ 3.99๋กœ ์„ค์ •๋˜์–ด, ๋กœ์ง€์Šคํ‹ฑ์Šค ๋งต์˜ ์™„์ „ํ•œ ์นด์˜ค์Šค ์˜์—ญ์— ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ•ต์‹ฌ ์›๋ฆฌ:

    1. ์ดˆ๊ธฐ ์ƒํƒœ: ์„ธ ์ž…์ž๋Š” 0๊ณผ 1 ์‚ฌ์ด์˜ ๋‚ด๋ถ€ ์ƒํƒœ (stateX, stateY)์—์„œ ์‹œ์ž‘ํ•˜๋ฉฐ, ๊ทธ ์ฐจ์ด๋Š” 1.0ร—10โˆ’6\mathbf{1.0 \times 10^{-6}}์ด๋ผ๋Š” ๊ทน๋„๋กœ ๋ฏธ์„ธํ•œ ๊ฐ’์ž…๋‹ˆ๋‹ค.
    2. ํ† ๋Ÿฌ์Šค ๊ฒฝ๊ณ„ ์ฒ˜๋ฆฌ: update() ํ•จ์ˆ˜์—์„œ ์œ„์น˜ ๊ฒฝ๊ณ„๋ฅผ ํ† ๋Ÿฌ์Šค(Torus) ํ˜•ํƒœ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ, ์ž…์ž๊ฐ€ ํ™”๋ฉด ๊ฐ€์žฅ์ž๋ฆฌ์—์„œ ์‚ฌ๋ผ์ง€๋ฉด ๋ฐ˜๋Œ€ํŽธ์—์„œ ๋‚˜ํƒ€๋‚˜ ๊ถค์ ์˜ ์—ฐ์†์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์‹œ๊ฐํ™”: ์ž…์ž์˜ ๋‚ด๋ถ€ ์ƒํƒœ ๋ณ€ํ™”(stateX, stateY)๊ฐ€ ์ž…์ž์˜ ์†๋„(vx, vy)๋กœ ๋ณ€ํ™˜๋˜์–ด ํ™”๋ฉด์ƒ์˜ ๊ถค์ ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

2. ๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜ (Lyapunov Exponent, ฮป\lambda)์˜ ์—ญํ• 

๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜๋Š” ์นด์˜ค์Šค ์ด๋ก ์—์„œ ์‹œ์Šคํ…œ์˜ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅ์„ฑ ์ •๋„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ฒ™๋„์ž…๋‹ˆ๋‹ค.

  • ์ •์˜: ์ดˆ๊ธฐ ์ƒํƒœ๊ฐ€ ฮด0\delta_0๋งŒํผ ๋–จ์–ด์ง„ ๋‘ ๊ถค์ ์ด ์‹œ๊ฐ„์ด tt๋งŒํผ ์ง€๋‚œ ํ›„ ฮดt\delta_t๋งŒํผ ๋–จ์–ด์ ธ ์žˆ์„ ๋•Œ, ์ง€์ˆ˜ ฮป\lambda๋Š” ๋‹ค์Œ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

    ฮดtโ‰ˆฮด0eฮปt\delta_t \approx \delta_0 e^{\lambda t}

  • ์นด์˜ค์Šค ํŒ๋ณ„:
    • ฮป>0\lambda > 0 (์–‘์ˆ˜): ์‹œ์Šคํ…œ์€ ์นด์˜ค์Šค์ž…๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ์˜ค์ฐจ๊ฐ€ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ์ง€์ˆ˜์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๋ฉฐ, ์žฅ๊ธฐ ์˜ˆ์ธก์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    • ฮปโ‰ค0\lambda \le 0 (์Œ์ˆ˜ ๋˜๋Š” 0): ์‹œ์Šคํ…œ์€ ์•ˆ์ •์ ์ด๊ฑฐ๋‚˜ ์ฃผ๊ธฐ์ ์ž…๋‹ˆ๋‹ค.

3. ์ฝ”๋“œ์˜ ๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜ ๊ณ„์‚ฐ

์ฝ”๋“œ์—์„œ ๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜๋ฅผ ๊ทผ์‚ฌ์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

// ๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜ ๊ณ„์‚ฐ
if (frameCount > 0 && maxDistance > 0) {
    let lyapunov = Math.log(maxDistance / 0.000001) / frameCount;
    text("๋ฆฌ์•„ํ‘ธ๋…ธํ”„ ์ง€์ˆ˜: " + nf(lyapunov, 0, 4), 20, 90);
}

์ด ์ฝ”๋“œ๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ ฮดtโ‰ˆฮด0eฮปt\delta_t \approx \delta_0 e^{\lambda t} ๊ณต์‹์„ ฮป\lambda์— ๋Œ€ํ•ด ์ •๋ฆฌํ•œ ํ›„, ์ด์‚ฐ์ ์ธ ์‹œ๊ฐ„ ๋‹จ๊ณ„(ํ”„๋ ˆ์ž„ ์ˆ˜ tt)์— ๋งž์ถฐ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

ฮปโ‰ˆ1tlnโก(ฮดtฮด0)\lambda \approx \frac{1}{t} \ln \left( \frac{\delta_t}{\delta_0} \right)

  • ฮดt\delta_t: ํ˜„์žฌ ์ž…์ž ๊ฐ„ ์ตœ๋Œ€ ๊ฑฐ๋ฆฌ (maxDistance)๋กœ ๊ทผ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
  • ฮด0\delta_0: ์ดˆ๊ธฐ ์ž…์ž ๊ฐ„ ๊ฑฐ๋ฆฌ์ธ 0.000001 (1.0e-6)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • tt: ๊ฒฝ๊ณผ๋œ ํ”„๋ ˆ์ž„ ์ˆ˜ (frameCount)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.์ด ๊ณ„์‚ฐ์€ ์„ธ ์ž…์ž์˜ ์ดํƒˆ ์†๋„๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‹œ์Šคํ…œ์˜ ์นด์˜ค์Šค ์ •๋„๋ฅผ ์ˆซ์ž๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ 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();
}

๐Ÿ”น ์˜ˆ์ œ 4: ์ด์ค‘ ์ง„์ž(Double Pendulum)

์ด์ค‘ ์ง„์ž๋Š” ๋‘ ๊ฐœ์˜ ์ง„์ž(pendulum)๊ฐ€ ์ฐจ๋ก€๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์ง„์ž๊ฐ€ ๊ณ ์ •๋œ ์ ์— ๋งค๋‹ฌ๋ ค ์žˆ๊ณ , ๋‘ ๋ฒˆ์งธ ์ง„์ž๊ฐ€ ์ฒซ ๋ฒˆ์งธ ์ง„์ž์˜ ๋์— ๋งค๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ค‘ ์ง„์ž๋Š” ๋‹จ์ˆœํ•œ ๋ฌผ๋ฆฌ ๋ฒ•์น™์œผ๋กœ๋„ ์–ผ๋งˆ๋‚˜ ๋ณต์žกํ•˜๊ณ  ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์›€์ง์ž„, ์ฆ‰ ์นด์˜ค์Šค(Chaos)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

1. ์นด์˜ค์Šค ์‹œ์Šคํ…œ์œผ๋กœ์„œ์˜ ์ด์ค‘ ์ง„์ž

  • ๋น„์„ ํ˜•์„ฑ: ์ด์ค‘ ์ง„์ž์˜ ์›€์ง์ž„์„ ์ง€๋ฐฐํ•˜๋Š” ์šด๋™ ๋ฐฉ์ •์‹์€ ์‚ผ๊ฐ ํ•จ์ˆ˜(sin, cos)๋ฅผ ํฌํ•จํ•˜๋Š” ๋ณต์žกํ•œ ๋น„์„ ํ˜• ๋ฏธ๋ถ„ ๋ฐฉ์ •์‹์ž…๋‹ˆ๋‹ค.
  • ์นด์˜ค์Šค ๋ฐœ์ƒ: ๋‹จ์ผ ์ง„์ž๋Š” ํ•ญ์ƒ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์ฃผ๊ธฐ์ ์ธ ์šด๋™(์ง„๋™)์„ ํ•˜์ง€๋งŒ, ์ด์ค‘ ์ง„์ž๋Š” ์—๋„ˆ์ง€ ์†์‹ค(๊ฐ์‡ )์ด ์—†๋‹ค๋ฉด ๋Œ€๋ถ€๋ถ„์˜ ์ดˆ๊ธฐ ์กฐ๊ฑด์—์„œ ์นด์˜ค์Šค์ ์ธ, ๋น„์ฃผ๊ธฐ์ ์ธ(Aperiodic) ์›€์ง์ž„์„ ๋ณด์ž…๋‹ˆ๋‹ค.

2. ์ฝ”๋“œ์˜ ํ•ต์‹ฌ ๋ฐฉ์ •์‹

์ฝ”๋“œ๊ฐ€ angleA1๊ณผ angleA2๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ถ€๋ถ„์€ ์ด์ค‘ ์ง„์ž์˜ ๊ฐ๊ฐ€์†๋„(ฮธยจ1\ddot{\theta}_1, ฮธยจ2\ddot{\theta}_2)๋ฅผ ๊ตฌํ•˜๋Š” ๋ณต์žกํ•œ ๊ณต์‹์ž…๋‹ˆ๋‹ค.

ฮธยจ1=โˆ’g(2m1+m2)sinโกฮธ1โˆ’m2gsinโก(ฮธ1โˆ’2ฮธ2)โˆ’2sinโก(ฮธ1โˆ’ฮธ2)m2(ฮธห™22r2+ฮธห™12r1cosโก(ฮธ1โˆ’ฮธ2))r1(2m1+m2โˆ’m2cosโก(2ฮธ1โˆ’2ฮธ2))\ddot{\theta}_1 = \frac{-g(2m_1+m_2)\sin\theta_1 - m_2 g \sin(\theta_1 - 2\theta_2) - 2 \sin(\theta_1 - \theta_2) m_2 (\dot{\theta}_2^2 r_2 + \dot{\theta}_1^2 r_1 \cos(\theta_1 - \theta_2))}{r_1 (2m_1+m_2 - m_2 \cos(2\theta_1 - 2\theta_2))}

ฮธยจ2=2sinโก(ฮธ1โˆ’ฮธ2)(ฮธห™12r1(m1+m2)+g(m1+m2)cosโกฮธ1+ฮธห™22r2m2cosโก(ฮธ1โˆ’ฮธ2))r2(2m1+m2โˆ’m2cosโก(2ฮธ1โˆ’2ฮธ2))\ddot{\theta}_2 = \frac{2 \sin(\theta_1 - \theta_2) (\dot{\theta}_1^2 r_1 (m_1+m_2) + g (m_1+m_2) \cos\theta_1 + \dot{\theta}_2^2 r_2 m_2 \cos(\theta_1 - \theta_2))}{r_2 (2m_1+m_2 - m_2 \cos(2\theta_1 - 2\theta_2))}

  • ฮธ1,ฮธ2\theta_1, \theta_2 (angle1, angle2): ๊ฐ ๋ง‰๋Œ€์˜ ์ˆ˜์ง์„ ๊ณผ์˜ ๊ฐ๋„.
  • ฮธห™1,ฮธห™2\dot{\theta}_1, \dot{\theta}_2 (angleV1, angleV2): ๊ฐ์†๋„.
  • ฮธยจ1,ฮธยจ2\ddot{\theta}_1, \ddot{\theta}_2 (angleA1, angleA2): ๊ฐ๊ฐ€์†๋„.

์ด ๋ณต์žกํ•œ ๊ณ„์‚ฐ์„ ํ†ตํ•ด ๊ฐ๊ฐ€์†๋„๋ฅผ ๊ตฌํ•˜๊ณ , ์ด๋ฅผ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์ ๋ถ„ํ•˜์—ฌ ๊ฐ์†๋„์™€ ๊ฐ๋„๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค:

angleV1 += angleA1; // ๊ฐ๊ฐ€์†๋„๋ฅผ ๊ฐ์†๋„์— ๋”ํ•จ
angleV2 += angleA2;
angle1 += angleV1;  // ๊ฐ์†๋„๋ฅผ ๊ฐ๋„์— ๋”ํ•จ
angle2 += angleV2;

3. ์ดˆ๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์„ฑ (๋‚˜๋น„ ํšจ๊ณผ) ์‹œ์—ฐ

์ด์ค‘ ์ง„์ž๋Š” ๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ, ๋กœ์ง€์Šคํ‹ฑ ๋งต๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ดˆ๊ธฐ ์กฐ๊ฑด ๋ฏผ๊ฐ์„ฑ์„ ๊ทน์ ์œผ๋กœ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

  • mousePressed() ํ•จ์ˆ˜:
angle1 = PI / 2 + random(-0.1, 0.1);
angle2 = PI / 2 + random(-0.1, 0.1);

์ด ์ฝ”๋“œ๋Š” ๋งˆ์šฐ์Šค๋ฅผ ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค ฯ€/2\pi/2 (์ˆ˜ํ‰) ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ -0.1์—์„œ 0.1 ๋ผ๋””์•ˆ ์‚ฌ์ด์˜ ๋งค์šฐ ์ž‘์€ ๋ฌด์ž‘์œ„ ํŽธ์ฐจ๋ฅผ ์ดˆ๊ธฐ ๊ฐ๋„์— ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.

  • ์‹œ๊ฐํ™”: ๋‘ ๋ฒˆ์งธ ์งˆ์ (m2)์˜ ๊ถค์ ์„ trail ๋ฐฐ์—ด์— ์ €์žฅํ•˜๊ณ  ํ™”๋ฉด์— ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. ํด๋ฆญ ํ›„ ๋ช‡ ์ดˆ ๋™์•ˆ์€ ๊ถค์ ์ด ๋น„์Šทํ•˜๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํด๋ฆญ์—์„œ ์‹œ์ž‘๋œ ๊ถค์ ๊ณผ๋Š” ์™„์ „ํžˆ ๋‹ค๋ฅธ ํŒจํ„ด์„ ์ƒ์„ฑํ•˜๋ฉฐ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ์›€์ง์ด๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. ๊ฐ์‡  ์ฒ˜๋ฆฌ

angleV1 *= 0.999;
angleV2 *= 0.999;

์ด ์ฝ”๋“œ๋Š” ๊ฐ์†๋„์— 0.999๋ฅผ ๊ณฑํ•˜์—ฌ ๊ณต๊ธฐ ์ €ํ•ญ์ด๋‚˜ ๋งˆ์ฐฐ๋กœ ์ธํ•œ ๊ฐ์‡ (Damping)๋ฅผ ๋ชจ๋ฐฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‡ ๊ฐ€ ์—†๋‹ค๋ฉด ์—๋„ˆ์ง€๊ฐ€ ๋ณด์กด๋˜์–ด ์˜์›ํžˆ ์›€์ง์ด์ง€๋งŒ, ํ˜„์‹ค์ ์ธ ๊ฐ์‡ ๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ๋ณต์žกํ•œ ์›€์ง์ž„์„ ๋ณด์ด๋‹ค๊ฐ€ ๊ฒฐ๊ตญ ์—๋„ˆ์ง€๋ฅผ ์žƒ๊ณ  ๋ฉˆ์ถ”๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

5. ์ดํ›„ ๋ฐœ์ „ ๋ฐฉํ–ฅ

ํ˜„์žฌ๋Š” ๊ถค์ ์ด ๋‹จ์ƒ‰์ด์ง€๋งŒ, ๊ถค์ ์˜ ์†๋„(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 = [];
}

๐Ÿ”น ์˜ˆ์ œ 5: ์นด์˜ค์Šค ๊ฒŒ์ž„๊ณผ ์นด์˜ค์Šค (Chaos Game and Chaos)

์ด ์ฝ”๋“œ์—์„œ๋Š” ์นด์˜ค์Šค ์ด๋ก ๊ณผ ํ”„๋ž™ํƒˆ ๊ธฐํ•˜ํ•™์ด ์–ด๋–ป๊ฒŒ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
์ด ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ํŒจํ„ด์€ ๋Œ€ํ‘œ์ ์ธ ํ”„๋ž™ํƒˆ์ธ ์‹œ์–ดํ•€์Šคํ‚ค ์‚ผ๊ฐํ˜•(Sierpinski Triangle)์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ํŒจํ„ด์ด '์นด์˜ค์Šค ๊ฒŒ์ž„'์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ถˆ๋ฆฌ๋Š” ์ด์œ ๋Š” ๊ทธ ์ƒ์„ฑ ๊ณผ์ •์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ๋Š” ์นด์˜ค์Šค ๊ฒŒ์ž„์ด๋ผ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•˜๋ฉฐ, ์ด ๊ณผ์ •์—์„œ ๋ฌด์ž‘์œ„์„ฑ(Randomness)๊ณผ ๊ฒฐ์ •๋ก ์  ๊ตฌ์กฐ(Deterministic Structure)๊ฐ€ ๊ฒฐํ•ฉ๋˜์–ด ์นด์˜ค์Šค์ ์ธ ์š”์†Œ๊ฐ€ ๋„์ž…๋ฉ๋‹ˆ๋‹ค.

1. ์นด์˜ค์Šค ๊ฒŒ์ž„์˜ ๊ทœ์น™ (์•Œ๊ณ ๋ฆฌ์ฆ˜)

  • ์‹œ์ž‘์ (P0P_0) ์„ค์ •: ํ™”๋ฉด ๋‚ด ์ž„์˜์˜ ํ•œ ์ (current)์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ผญ์ง“์ (ViV_i) ์„ ํƒ: ์‚ฌ์ „์— ์ •ํ•ด์ง„ ์ •์‚ผ๊ฐํ˜•์˜ ๊ผญ์ง“์  ์…‹ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋ฌด์ž‘์œ„๋กœ (random(vertices)) ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  • ์  ์ด๋™: ํ˜„์žฌ ์ (PnP_n)์—์„œ ์„ ํƒ๋œ ๊ผญ์ง“์ (ViV_i) ๋ฐฉํ–ฅ์œผ๋กœ ์ผ์ • ๋น„์œจ(0.5) ๋งŒํผ๋งŒ ์ด๋™ํ•˜์—ฌ ๋‹ค์Œ ์ (Pn+1P_{n+1})์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด ๊ณผ์ •์ด ๋ฐ”๋กœ ์ฝ”๋“œ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค: current = lerp(current.x, vertex.x, 0.5);

2. ์™œ '์นด์˜ค์Šค ๊ฒŒ์ž„'์ธ๊ฐ€?

์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด '์นด์˜ค์Šค'์™€ ๊ด€๋ จ๋˜๋Š” ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋ฌด์ž‘์œ„์„ฑ (์นด์˜ค์Šค์  ์š”์†Œ): ์ ์„ ์ด๋™์‹œํ‚ฌ ๋‹ค์Œ ๊ผญ์ง“์ ์„ ๋งค๋ฒˆ ๋ฌด์ž‘์œ„๋กœ ์„ ํƒํ•˜๋Š” ๊ณผ์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌด์ž‘์œ„์„ฑ์ด ์ด๋ฆ„์— '์นด์˜ค์Šค'๊ฐ€ ๋ถ™์€ ์ฃผ๋œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์ ์ด ์–ด๋””๋กœ ์ด๋™ํ• ์ง€ ๋‹จ๊ธฐ์ ์œผ๋กœ ์˜ˆ์ธกํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋†€๋ผ์šด ๊ฒฐ๊ณผ (๊ฒฐ์ •๋ก ์  ๊ตฌ์กฐ): ํ•˜์ง€๋งŒ ์ด ๋ฌด์ž‘์œ„์ ์ธ ๊ณผ์ •์„ ์ˆ˜์ฒœ ๋ฒˆ ์ด์ƒ ๋ฐ˜๋ณตํ•˜๋ฉด, ์ ๋“ค์€ ๋†€๋ž๊ฒŒ๋„ ๋ฐ˜๋“œ์‹œ ์‹œ์–ดํ•€์Šคํ‚ค ์‚ผ๊ฐํ˜•์ด๋ผ๋Š” ๊ณ ๋„๋กœ ์งˆ์„œ์ •์—ฐํ•˜๊ณ  ๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์นด์˜ค์Šค ๊ฒŒ์ž„์€ ๋‹จ๊ธฐ์ ์œผ๋กœ๋Š” ๋ฌด์ž‘์œ„์„ฑ(์นด์˜ค์Šค)์„ ๋ณด์ด์ง€๋งŒ, ์žฅ๊ธฐ์ ์œผ๋กœ๋Š” ๊ณ ์ •๋œ ํŒจํ„ด(์–ดํŠธ๋ž™ํ„ฐ/ํ”„๋ž™ํƒˆ)์œผ๋กœ ์ˆ˜๋ ดํ•˜๋Š”, ์งˆ์„œ ์†์˜ ๋ฌด์งˆ์„œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ์˜ ์นด์˜ค์Šค ๊ฒŒ์ž„์€ ์ •์‚ผ๊ฐํ˜•(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();
}

๐ŸŽจ ์‹คํ—˜ ์•„์ด๋””์–ด

  • ๋กœ์ง€์Šคํ‹ฑ ๋งต์˜ r ๊ฐ’์„ ์ฒœ์ฒœํžˆ ๋ฐ”๊พธ๋ฉฐ ์งˆ์„œโ†’์นด์˜ค์Šค ์ „ํ™˜์„ ๊ด€์ฐฐํ•˜์„ธ์š”
  • ๋”๋ธ” ํŽœ๋“ˆ๋Ÿผ์˜ ์ดˆ๊ธฐ ๊ฐ๋„๋ฅผ 0.001๋„๋งŒ ๋ฐ”๊ฟ”๋„ ๊ถค์ ์ด ์™„์ „ํžˆ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค
  • ๋กœ๋ Œ์ธ  ์–ดํŠธ๋ž™ํ„ฐ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์–ด๋–ค ๋ชจ์–‘์ด ๋‚˜์˜ฌ๊นŒ์š”?
  • ์นด์˜ค์Šค ๊ฒŒ์ž„์„ ์ •์‚ฌ๊ฐํ˜•, ์˜ค๊ฐํ˜•์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์–ด๋–ค ํ”„๋ž™ํƒˆ์ด ๋‚˜์˜ฌ๊นŒ์š”?
profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€