
"์๋ฌผ์ ์งํ ์๋ฆฌ(๋ณ์ด, ์ ํ, ๊ต๋ฐฐ)๋ฅผ ์ฝ๋๋ก ๊ตฌํํด์, ์ปดํจํฐ๊ฐ ์ค์ค๋ก '์ข์ ํด๋ต'์ ์ฐพ์๊ฐ๊ฒ ๋ง๋๋ ์๊ณ ๋ฆฌ์ฆ"์ด์์.
์ด๊ฒ์ ์ต์ ํ ๋ฌธ์ , ์์ฑ ๋์์ธ, ์ธ๊ณต์๋ช
์๋ฎฌ๋ ์ด์
๋ฑ์์ ์์ฐ์ ์งํ๋ฅผ ๋ชจ๋ฐฉํ๋ ํต์ฌ ์๋ฆฌ์
๋๋ค.
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ์ด๋ฆ | Genetic Algorithm (GA) |
| ์๋ฏธ | ์๋ฌผํ์ ์งํ(์ ์ , ๋์ฐ๋ณ์ด, ์์ฐ์ ํ)๋ฅผ ๋ชจ๋ฐฉํ ์ต์ ํ ์๊ณ ๋ฆฌ์ฆ |
| ํต์ฌ ์์ด๋์ด | ์ฌ๋ฌ ๊ฐ์ฒด๊ฐ ๊ฒฝ์ํ๊ณ , ์ฐ์ํ ๊ฐ์ฒด๋ผ๋ฆฌ ๊ต๋ฐฐ(crossover)ํ๊ณ ๋ณ์ด(mutation)๋ฅผ ๊ฑฐ์ณ ์ธ๋๋ฅผ ๊ฑฐ๋ญํ๋ฉฐ ์งํ |
| ๊ฒฐ๊ณผ ํจํด | ์ธ๋๊ฐ ์ง๋ ์๋ก ๋ชฉํ์ ๊ฐ๊น์์ง๋ ๊ฐ์ฒด ์ง๋จ์ '์ ์' |
| ๊ด๋ จ ๊ฐ๋ | ์์ฐ์ ํ(natural selection), ์ ํฉ๋(fitness), ๊ต๋ฐฐ(crossover), ๋์ฐ๋ณ์ด(mutation) |
โ ๋ฌด์์๋ก ์ฌ๋ฌ ๊ฐ์ฒด(individual)๋ฅผ ๋ง๋ฆ
(์: ๋ชฉํ ๋ฌธ์ฅ์ ์ฐพ๋ ๊ฒฝ์ฐ, ๋๋คํ ๋ฌธ์์ด์ ์ฌ๋ฌ ๊ฐ ์์ฑ)
โ ๊ฐ ๊ฐ์ฒด๊ฐ "๋ชฉํ์ ์ผ๋ง๋ ๊ฐ๊น์ด์ง" ์ ์๋ฅผ ๋งค๊น
(์: ๋ชฉํ ๋ฌธ์ฅ๊ณผ ๋ช ๊ธ์๊ฐ ์ผ์นํ๋์ง)
โ ์ ํฉ๋๊ฐ ๋์ ๊ฐ์ฒด๋ฅผ ๋ ๋ง์ด ์ ํํจ
โ ์์ฐ์ ํ(survival of the fittest)์ ๋ชจ๋ฐฉ
โ ์ ํ๋ ๋ ๋ถ๋ชจ์ ์ ์ ์๋ฅผ ์์ด ์์์ ๋ง๋ฆ
(์: ๋ถ๋ชจ A์ ์๋ถ๋ถ + ๋ถ๋ชจ B์ ๋ท๋ถ๋ถ)
โ ์ผ์ ํ๋ฅ ๋ก ์์์ ์ ์ ์ ์ผ๋ถ๋ฅผ ๋๋คํ๊ฒ ๋ฐ๊ฟ
โ ๋ค์์ฑ์ ์ ์งํ๊ณ ์ง์ญ ์ต์ ํด(local optimum)๋ฅผ ํ์ถ
โ ์๋ก์ด ์ง๋จ์ผ๋ก ๊ต์ฒดํ๊ณ 2๏ธโฃ๋ก ๋์๊ฐ
โ ๋ชฉํ์ ๋๋ฌํ๊ฑฐ๋ ์ผ์ ์ธ๋์๊น์ง ๋ฐ๋ณต
| ๐งฌ ์๋ฌผ ์งํ | ๊ฐ๋ผํ๊ณ ์ค ํ์น์๊ฐ ๋ถ๋ฆฌ ๋ชจ์์ ํ๊ฒฝ์ ๋ง๊ฒ ์งํ |
|---|---|
| ๐ฑ ์๋ฌผ ์ ์ | ์ ์ธ์ฅ์ด ๊ฑด์กฐํ ํ๊ฒฝ์ ์ ์ํ ํํ๋ก ์งํ |
| ๐ฆ ๊ณค์ถฉ์ ์ํ | ๋๋ญ์์ฒ๋ผ ๋ณด์ด๋๋ก ์งํํ ๋๋ฐฉ |
| ๐ ํฌ์์-ํผ์์ | ์นํ์ ์๋์ ๊ฐ์ ค์ ๋ฏผ์ฒฉ์ฑ์ด ์๋ก ๊ฒฝ์ํ๋ฉฐ ์งํ |
| ์ฃผ์ | ๊ด๊ณ |
|---|---|
| ๋๋ค(Randomness) | ๋์ฐ๋ณ์ด์ ์ด๊ธฐ ์ง๋จ ์์ฑ์ ๊ธฐ๋ฐ |
| ์์คํ (Systems) | ๊ฐ์ฒด๋ค์ ์ง๋จ์ ์ํธ์์ฉ์ผ๋ก ๋ณต์ก์ฑ ์์ฑ |
| ํํ & ๊ตฌ์กฐ(Form & Structure) | ์งํ๋ฅผ ํตํด ํํ๊ฐ ์ต์ ํ๋จ |
| ๋ฐ์ดํฐ(Data) | ์ ์ ์๋ฅผ ๋ฐ์ดํฐ๋ก ํํํ๊ณ ์กฐ์ |

let population = [];
let target = "BamgasiJM";
let mutationRate = 0.01;
let popSize = 200;
function setup() {
createCanvas(600, 250);
// ์ด๊ธฐ ์ง๋จ ์์ฑ
for (let i = 0; i < popSize; i++) {
population.push(new DNA(target.length));
}
}
function draw() {
background(15);
// ์ ํฉ๋ ๊ณ์ฐ
for (let dna of population) {
dna.calcFitness(target);
}
// ๋ค์ ์ธ๋ ์์ฑ
let matingPool = [];
for (let dna of population) {
let n = floor(dna.fitness * 100);
for (let i = 0; i < n; i++) {
matingPool.push(dna);
}
}
// ๊ต๋ฐฐ ๋ฐ ๋์ฐ๋ณ์ด
for (let i = 0; i < population.length; i++) {
let parentA = random(matingPool);
let parentB = random(matingPool);
let child = parentA.crossover(parentB);
child.mutate(mutationRate);
population[i] = child;
}
// ์ต๊ณ ๊ฐ์ฒด ํ์
let best = population[0];
for (let dna of population) {
if (dna.fitness > best.fitness) {
best = dna;
}
}
fill(210, 180, 0);
textSize(32);
textAlign(CENTER);
text("Target: " + target, width / 2, 70);
fill(30, 200, 190);
textSize(32);
textAlign(CENTER);
text("Best: " + best.genes, width / 2, 120);
fill(200);
textSize(18);
textAlign(CENTER);
text("Generation: " + frameCount, width / 2, 180);
text("Fitness: " + nf(best.fitness, 0, 4), width / 2, 210);
// ๋ชฉํ ๋ฌ์ฑ ์ ์ ์ง
if (best.genes === target) {
noLoop();
console.log("Completed! Number of Generations: " + frameCount);
}
}
class DNA {
constructor(len) {
this.genes = "";
this.fitness = 0;
for (let i = 0; i < len; i++) {
this.genes += this.randomChar();
}
}
randomChar() {
let c = floor(random(32, 128));
return String.fromCharCode(c);
}
calcFitness(target) {
let score = 0;
for (let i = 0; i < this.genes.length; i++) {
if (this.genes[i] === target[i]) {
score++;
}
}
this.fitness = score / target.length;
}
crossover(partner) {
let child = new DNA(this.genes.length);
let midpoint = floor(random(this.genes.length));
child.genes =
this.genes.substring(0, midpoint) + partner.genes.substring(midpoint);
return child;
}
mutate(rate) {
let genes = "";
for (let i = 0; i < this.genes.length; i++) {
if (random(1) < rate) {
genes += this.randomChar();
} else {
genes += this.genes[i];
}
}
this.genes = genes;
}
}

let population = [];
let popSize = 50;
let target;
let lifespan = 300;
let lifeCounter = 0;
let generation = 1;
function setup() {
createCanvas(600, 600);
target = createVector(width / 2, 50);
for (let i = 0; i < popSize; i++) {
population.push(new Rocket());
}
}
function draw() {
background(0);
// ๋ชฉํ ์ง์
fill(255, 0, 0);
circle(target.x, target.y, 20);
// ๋ก์ผ ์
๋ฐ์ดํธ
for (let rocket of population) {
rocket.update();
rocket.show();
}
lifeCounter++;
// ์ธ๋ ๊ต์ฒด
if (lifeCounter >= lifespan) {
lifeCounter = 0;
evaluate();
selection();
generation++;
}
// ์ ๋ณด ํ์
fill(255);
textAlign(LEFT);
text("Generation: " + generation, 10, 20);
text("Lifespan: " + lifeCounter + "/" + lifespan, 10, 40);
}
function evaluate() {
let maxFit = 0;
for (let rocket of population) {
rocket.calcFitness(target);
if (rocket.fitness > maxFit) {
maxFit = rocket.fitness;
}
}
// ์ ๊ทํ
for (let rocket of population) {
rocket.fitness /= maxFit;
}
}
function selection() {
let matingPool = [];
for (let rocket of population) {
let n = floor(rocket.fitness * 100);
for (let i = 0; i < n; i++) {
matingPool.push(rocket);
}
}
let newPopulation = [];
for (let i = 0; i < popSize; i++) {
let parentA = random(matingPool);
let parentB = random(matingPool);
let child = parentA.crossover(parentB);
child.mutate();
newPopulation.push(child);
}
population = newPopulation;
lifeCounter = 0;
}
class Rocket {
constructor(dna) {
this.pos = createVector(width / 2, height - 50);
this.vel = createVector();
this.acc = createVector();
this.completed = false;
this.crashed = false;
this.fitness = 0;
if (dna) {
this.dna = dna;
} else {
this.dna = [];
for (let i = 0; i < lifespan; i++) {
this.dna.push(p5.Vector.random2D().setMag(0.1));
}
}
}
update() {
if (!this.completed && !this.crashed) {
this.applyForce(this.dna[lifeCounter]);
this.vel.add(this.acc);
this.pos.add(this.vel);
this.acc.mult(0);
// ์ถฉ๋ ๊ฐ์ง
if (this.pos.x < 0 || this.pos.x > width ||
this.pos.y < 0 || this.pos.y > height) {
this.crashed = true;
}
// ๋ชฉํ ๋๋ฌ
if (dist(this.pos.x, this.pos.y, target.x, target.y) < 20) {
this.completed = true;
}
}
}
applyForce(force) {
this.acc.add(force);
}
show() {
push();
translate(this.pos.x, this.pos.y);
rotate(this.vel.heading());
if (this.completed) {
fill(0, 255, 0);
} else if (this.crashed) {
fill(255, 0, 0);
} else {
fill(255);
}
rectMode(CENTER);
rect(0, 0, 20, 5);
pop();
}
calcFitness(target) {
let d = dist(this.pos.x, this.pos.y, target.x, target.y);
this.fitness = map(d, 0, width, width, 0);
if (this.completed) {
this.fitness *= 10;
}
if (this.crashed) {
this.fitness /= 10;
}
}
crossover(partner) {
let newDNA = [];
let midpoint = floor(random(this.dna.length));
for (let i = 0; i < this.dna.length; i++) {
if (i < midpoint) {
newDNA.push(this.dna[i]);
} else {
newDNA.push(partner.dna[i]);
}
}
return new Rocket(newDNA);
}
mutate() {
let mutationRate = 0.01;
for (let i = 0; i < this.dna.length; i++) {
if (random(1) < mutationRate) {
this.dna[i] = p5.Vector.random2D().setMag(0.1);
}
}
}
}

let population = [];
let popSize = 50;
let target;
let obstacles = [];
let lifespan = 300;
let lifeCounter = 0;
let generation = 1;
function setup() {
createCanvas(600, 600);
target = createVector(width / 2, 50);
// ์ฅ์ ๋ฌผ ์์ฑ
obstacles.push(createVector(width / 2, height / 2));
obstacles.push(createVector(width / 2 - 100, height / 2 + 100));
obstacles.push(createVector(width / 2 + 100, height / 2 + 100));
for (let i = 0; i < popSize; i++) {
population.push(new Rocket());
}
}
function draw() {
background(0);
// ๋ชฉํ ์ง์
fill(0, 255, 0);
circle(target.x, target.y, 20);
// ์ฅ์ ๋ฌผ
fill(255, 0, 0);
for (let obs of obstacles) {
circle(obs.x, obs.y, 40);
}
// ๋ก์ผ ์
๋ฐ์ดํธ
for (let rocket of population) {
// ์ฅ์ ๋ฌผ ์ถฉ๋ ์ฒดํฌ
for (let obs of obstacles) {
if (dist(rocket.pos.x, rocket.pos.y, obs.x, obs.y) < 25) {
rocket.crashed = true;
}
}
rocket.update();
rocket.show();
}
lifeCounter++;
if (lifeCounter >= lifespan) {
lifeCounter = 0;
evaluate();
selection();
generation++;
}
fill(255);
textAlign(LEFT);
text("Generation: " + generation, 10, 20);
text("Lifespan: " + lifeCounter + "/" + lifespan, 10, 40);
}
function evaluate() {
let maxFit = 0;
for (let rocket of population) {
rocket.calcFitness(target);
if (rocket.fitness > maxFit) {
maxFit = rocket.fitness;
}
}
for (let rocket of population) {
rocket.fitness /= maxFit;
}
}
function selection() {
let matingPool = [];
for (let rocket of population) {
let n = floor(rocket.fitness * 100);
for (let i = 0; i < n; i++) {
matingPool.push(rocket);
}
}
let newPopulation = [];
for (let i = 0; i < popSize; i++) {
let parentA = random(matingPool);
let parentB = random(matingPool);
let child = parentA.crossover(parentB);
child.mutate();
newPopulation.push(child);
}
population = newPopulation;
lifeCounter = 0;
}
class Rocket {
constructor(dna) {
this.pos = createVector(width / 2, height - 50);
this.vel = createVector();
this.acc = createVector();
this.completed = false;
this.crashed = false;
this.fitness = 0;
if (dna) {
this.dna = dna;
} else {
this.dna = [];
for (let i = 0; i < lifespan; i++) {
this.dna.push(p5.Vector.random2D().setMag(0.1));
}
}
}
update() {
if (!this.completed && !this.crashed) {
this.applyForce(this.dna[lifeCounter]);
this.vel.add(this.acc);
this.pos.add(this.vel);
this.acc.mult(0);
if (this.pos.x < 0 || this.pos.x > width ||
this.pos.y < 0 || this.pos.y > height) {
this.crashed = true;
}
if (dist(this.pos.x, this.pos.y, target.x, target.y) < 20) {
this.completed = true;
}
}
}
applyForce(force) {
this.acc.add(force);
}
show() {
push();
translate(this.pos.x, this.pos.y);
rotate(this.vel.heading());
if (this.completed) {
fill(0, 255, 0);
} else if (this.crashed) {
fill(255, 0, 0, 50);
} else {
fill(255, 150);
}
rectMode(CENTER);
rect(0, 0, 20, 5);
pop();
}
calcFitness(target) {
let d = dist(this.pos.x, this.pos.y, target.x, target.y);
this.fitness = map(d, 0, width, width, 0);
if (this.completed) {
this.fitness *= 10;
}
if (this.crashed) {
this.fitness /= 10;
}
}
crossover(partner) {
let newDNA = [];
let midpoint = floor(random(this.dna.length));
for (let i = 0; i < this.dna.length; i++) {
if (i < midpoint) {
newDNA.push(this.dna[i]);
} else {
newDNA.push(partner.dna[i]);
}
}
return new Rocket(newDNA);
}
mutate() {
let mutationRate = 0.01;
for (let i = 0; i < this.dna.length; i++) {
if (random(1) < mutationRate) {
this.dna[i] = p5.Vector.random2D().setMag(0.1);
}
}
}
}

let population = [];
let popSize = 100;
let targetColor;
let targetSize = 50;
let generation = 1;
function setup() {
createCanvas(600, 600);
targetColor = color(255, 100, 150); // ๋ชฉํ ์์
for (let i = 0; i < popSize; i++) {
population.push(new Circle());
}
}
function draw() {
background(0);
// ๋ชฉํ ํ์
fill(targetColor);
circle(width / 2, 100, targetSize);
fill(255);
textAlign(CENTER);
text("Target", width / 2, 150);
// ํ์ฌ ์ธ๋ ํ์
for (let i = 0; i < population.length; i++) {
let x = (i % 10) * 60 + 30;
let y = floor(i / 10) * 60 + 200;
population[i].show(x, y);
}
// ์ ๋ณด
fill(255);
textAlign(LEFT);
text("Generation: " + generation, 10, 20);
// ํ ํ๋ ์๋ง๋ค ์งํ
if (frameCount % 60 === 0) {
evolve();
generation++;
}
}
function evolve() {
// ์ ํฉ๋ ๊ณ์ฐ
for (let circle of population) {
circle.calcFitness(targetColor, targetSize);
}
// ์ ๊ทํ
let maxFit = 0;
for (let circle of population) {
if (circle.fitness > maxFit) {
maxFit = circle.fitness;
}
}
for (let circle of population) {
circle.fitness /= maxFit;
}
// ์ ํ
let matingPool = [];
for (let circle of population) {
let n = floor(circle.fitness * 100);
for (let i = 0; i < n; i++) {
matingPool.push(circle);
}
}
// ๊ต๋ฐฐ ๋ฐ ๋์ฐ๋ณ์ด
let newPopulation = [];
for (let i = 0; i < popSize; i++) {
let parentA = random(matingPool);
let parentB = random(matingPool);
let child = parentA.crossover(parentB);
child.mutate();
newPopulation.push(child);
}
population = newPopulation;
}
class Circle {
constructor(r, g, b, size) {
if (r === undefined) {
this.r = random(255);
this.g = random(255);
this.b = random(255);
this.size = random(10, 80);
} else {
this.r = r;
this.g = g;
this.b = b;
this.size = size;
}
this.fitness = 0;
}
show(x, y) {
fill(this.r, this.g, this.b);
circle(x, y, this.size);
}
calcFitness(targetCol, targetSize) {
let dr = abs(this.r - red(targetCol));
let dg = abs(this.g - green(targetCol));
let db = abs(this.b - blue(targetCol));
let colorDist = (dr + dg + db) / 3;
let sizeDist = abs(this.size - targetSize);
let totalDist = colorDist + sizeDist;
this.fitness = map(totalDist, 0, 255 + 80, 255 + 80, 0);
}
crossover(partner) {
let childR = random(1) < 0.5 ? this.r : partner.r;
let childG = random(1) < 0.5 ? this.g : partner.g;
let childB = random(1) < 0.5 ? this.b : partner.b;
let childSize = random(1) < 0.5 ? this.size : partner.size;
return new Circle(childR, childG, childB, childSize);
}
mutate() {
let mutationRate = 0.05;
if (random(1) < mutationRate) {
this.r += random(-20, 20);
this.r = constrain(this.r, 0, 255);
}
if (random(1) < mutationRate) {
this.g += random(-20, 20);
this.g = constrain(this.g, 0, 255);
}
if (random(1) < mutationRate) {
this.b += random(-20, 20);
this.b = constrain(this.b, 0, 255);
}
if (random(1) < mutationRate) {
this.size += random(-5, 5);
this.size = constrain(this.size, 10, 80);
}
}
}