오늘은 mutation 돌연변이 생성을 하는 날이예요~^^*
공연 1 작품 편안하게 보고 계셔요~^^* 코딩 공부 정리해서 돌아올게요~^^* 쓩~~^^*
돌연변이 생성 작업 전에요~~^^*
Rocket 로켓의 성능 향상 작업을 하나 더 해보도록 할게요~^^*
현재로서는~^^* 목표물에 닿은 로켓이 있더라도 그 로켓은 목표물을 관통하여 이동을 계속하게 되는데요~^^*
우리의 궁극적인 목표는 이 목표물에 닿는 것이니까~^^* 목표물에 닿아서 움직이지 않아야 할 것 같아요~~^^*
그래서요~~^^* 목표물에 아주 가까이 다가갔다면 목표물에 닿은 것이라고 간주하고 로켓의 위치를 목표물의 위치와 일치하도록 해 볼까 합니다~^^*
하나. target 목표물에 아주 가까이 왔다는 기준을 거리 10 으로 설정해 볼게요~
둘. 거리 10이 되면 임무가 완수되었다고 판단해 볼게요. 그러기 위해서 상태 진리값 변수 <<completed>> 를 준비해 보겠습니다~
셋. 상태진리값 <<completed>>가 ‘true’ ‘참’이 되면 rocket 로켓의 위치값에 target 목표물의 위치값을 저장해 볼게요~
function Rocket(dna) {
this.pos = createVector(width/2, height);
this.vel = createVector();
this.acc = createVector();
this.completed = false;
//로켓과 목표물과의 거리가 <<10 이하>>가 되면 임무완수로 보고 "true"값으로 바꾸겠습니다.
this.update = function() {
var d = dist(this.pos.x, this.pos.y, target.x, target.y);
if (d < 10) {
this.completed = true;
this.pos = target.copy();
}
//로켓과 목표물과의 거리가 <<10 이하>>가 되면 this.complete 진리값이 "true"가 되고, 로켓의 위치에 목표물의 위치값을 저장합니다.
this.applyForce(this.dna.genes[this.count]);
//this.dna.genes[this.count]에 서로 다른 속도가 저장되어 있으므로
//프레임마다 서로 다른 속도값이 힘에 적용되어 가속도에 더해집니다.
this.count++;
if(!this.completed) {
this.vel.add(this.acc);
this.pos.add(this.vel);
this.acc.mult(0);
}
//로켓과 목표물 사이 거리가 <<10보다 큰>> 경우에만 로켓은 계속 움직입니다.
}
.
.
.
}
성능이 향상 되어 목표물에 정확하게 안착하는 Rocket 로켓을 보러 가실까요~~^^*
성능 향상 작업 하나만 더 해보도록 할게요~^^* 임무를 완수한 Rocket 로켓의 fitness 적합성 수치를 10배 키워보겠습니다. 그러면, 다음 세대부터, 임무를 완수해 내는 Rocket 로켓들이 엄청 많아질 것 같아요..
function Rocket() {
.
.
.
this.calcFitness = function() {
var d = dist(this.pos.x, this.pos.y, target.x, target.y);
this.fitness = map( d, 0, width*2, width*2, 0);
if(this.completed) {
this.fitness *= 10;
}
.
.
.
}
네~^^* 그럼 mutation 돌연변이 생성 작업을 해서 또 다시 돌아올게요~^^* 로켓의 모습 재미있게 구경하고 계셔요~^^* 쓩~~^^*
네~^^* 돌연변이 발생 확률을 0.01로 설정해 보겠습니다. 변수 mutateR에 이 값을 저장하겠습니다~^^*
var mutateR = 0.01;
function DNA(genes) {
.
.
.
this.mutation = function() {
for(i = 0; i < this.genes.length; i++) {
if(random(1) < mutateR) {
this.genes[i] = p5.Vector.random2D();
this.genes[i].setMag(0.01);
}
}
}
//무작위 수를 뽑아 mutateR보다 작은 경우, 무작위 방향과 0.01 크기의 힘을 가진 벡터를 this.genes[i]에 저장하겠습니다.
.
.
.
}
function Population() {
.
.
.
this.selection = function() {
var newRockets = [];
for (var i = 0; i < this.rockets.length; i++) {
var parentA = random(this.matingpool).dna;
var parentB = random(this.matingpool).dna;
var child = parentA.crossover(parentB);
child.mutation();
newRockets[i] = new Rocket(child);
}
this.rockets = newRockets;
}
//교차작업을 통해 만들어진 child에 돌연변이생성 작업을 더한 후 새로운 Rocket집단을 이루어 세대교체를 하겠습니다.
.
.
.
}
로켓성능 향상 작업과 돌연변이 생성 작업을 통해, 목표물에 잘 안착하면서도 천편일률적이지 않고 자연스러운 대형을 선보이는 멋진 로켓집단이 탄생된 것 같습니다~~^^*
var lifespan = 200; //200 프레임 동안 살아보겠습니다.
var population;
var lifeP; //살아온 날 count 수치를 pharagraph 문단으로 보여줍니다.
var count = 0; //살아온 날
var target; //드디어 우리에게 추구하고픈 목표가 생겼어요!!
var mutateR = 0.01; //돌연변이 발생 확률입니다.
function setup(){
createCanvas(400, 400);
population = new Population();
lifeP = createP();
target = createVector(width/2, 100);
}
function draw(){
background(0);
population.run();
lifeP.html(count);
count++;
if (count == lifespan) {
population.evaluate();
population.selection();
count = 0;
}
//200 frame이 되면 로켓들의 적합성을 기반으로 부모를 선정하여 유전자 교차 작업을 통해 다음세대 로켓을 생성합니다.
ellipse(target.x, target.y, 16, 16);
}
function DNA(genes) {
if(genes) {
this.genes = genes;
} else {
this.genes = [];
for(var i = 0; i < lifespan; i++) {
this.genes[i] = p5.Vector.random2D();
this.genes[i].setMag(0.1);
}
}
this.crossover = function(partner) {
var newgenes = [];
var mid = floor(random(this.genes.length));
for(i = 0; i < this.genes.length; i++) {
if(i > mid) {
newgenes[i] = this.genes[i];
} else {
newgenes[i] = partner.genes[i]
}
}
return new DNA(newgenes);
}
this.mutation = function() {
for(i = 0; i < this.genes.length; i++) {
if(random(1) < mutateR) {
this.genes[i] = p5.Vector.random2D();
this.genes[i].setMag(0.01);
}
}
}
//무작위 수를 뽑아 mutateR보다 작은 경우, 무작위 방향과 0.01 크기의 힘을 가진 벡터를 this.genes[i]에 저장하겠습니다.
}
//맨처음 세대는 무작위로 genes 데이터를 만들어 DNA를 생성하고, 다음 세대 DNA 생성을 할 때는 genes 정보를 전달 받아 생성합니다.
function Rocket(dna) {
this.pos = createVector(width/2, height);
this.vel = createVector();
this.acc = createVector();
this.completed = false;
if (dna) {
this.dna = dna;
} else {
this.dna = new DNA();
}
this.fitness = 0;
this.count = 0;
//this.dna.genes[this.count]에 쓰이며, 배열의 순서를 나타내게 될 것입니다.
this.calcFitness = function() {
var d = dist(this.pos.x, this.pos.y, target.x, target.y);
this.fitness = map( d, 0, width*2, width*2, 0);
if(this.completed) {
this.fitness *= 10;
}
}
this.applyForce = function(force) {
this.acc.add(force);
}
this.update = function() {
var d = dist(this.pos.x, this.pos.y, target.x, target.y);
if (d < 10) {
this.completed = true;
this.pos = target.copy();
}
//로켓과 목표물과의 거리가 <<10 이하>>가 되면 this.complete 진리값이 "true"가 되고, 로켓의 위치에 목표물의 위치값을 저장합니다.
this.applyForce(this.dna.genes[this.count]);
//this.dna.genes[this.count]에 서로 다른 속도가 저장되어 있으므로
//프레임마다 서로 다른 속도값이 힘에 적용되어 가속도에 더해집니다.
this.count++;
if(!this.completed) {
this.vel.add(this.acc);
this.pos.add(this.vel);
this.acc.mult(0);
}
//로켓과 목표물 사이 거리가 <<10보다 큰>> 경우에만 로켓은 계속 움직입니다.
}
this.show = function() {
push();
noStroke();
fill(255, 150);
translate(this.pos.x, this.pos.y);
rotate(this.vel.heading());
rectMode(CENTER);
rect(0, 0, 25, 5);
pop();
}
}
//첫 세대 로켓은 무작위 DNA로 다음 세대 로켓부터는 교차작업을 통해 만들어진 DNA 정보로 생성합니다.
//목표물에 가장 가까운 로켓이 가장 큰 fitness값을 가질 수 있도록, 로켓과 목표물 사이의 거리 <0 - width*2>를 <width*2 - 0>으로 mapping합니다.
function Population () {
this.rockets = [];
this.popsize = 200;
this.matingpool = [];
for (var i = 0; i < this.popsize; i++) {
this.rockets[i] = new Rocket();
}
this.evaluate = function() {
var maxfit = 0;
for (var i = 0; i < this.popsize; i++) {
this.rockets[i].calcFitness();
if (this.rockets[i].fitness > maxfit) {
maxfit = this.rockets[i].fitness;
}
}
createP(maxfit);
console.log(this.rockets);
for (var i = 0; i < this.popsize; i++) {
this.rockets[i].fitness /= maxfit;
}
this.matingpool = [];
for (var i = 0; i < this.popsize; i++) {
var n = this.rockets[i].fitness * 100;
for (var j = 0; j < n; j++) {
this.matingpool.push(this.rockets[i]);
}
}
}
//로켓들의 최고 fitness 값을 기반으로 각 로켓의 fitness 값을 <0-1>로 정규화하고, 이를 바탕으로 높은 fitness 값을 가진 로켓들을 후보자군에 더 많이 넣습니다.
this.selection = function() {
var newRockets = [];
for (var i = 0; i < this.rockets.length; i++) {
var parentA = random(this.matingpool).dna;
var parentB = random(this.matingpool).dna;
var child = parentA.crossover(parentB);
child.mutation();
newRockets[i] = new Rocket(child);
}
this.rockets = newRockets;
}
//후보자군에서 무작위로 부모를 선택하여 교차작업을 합니다.
//교차작업을 통해 만들어진 child에 돌연변이생성 작업을 더한 후 자녀 로켓을 생성합니다. 로켓집합의 세대교체를 합니다.
this.run = function() {
for (var i = 0; i < this.popsize; i++) {
this.rockets[i].update();
this.rockets[i].show();
}
}
}
//로켓의 움직임 변화를 반영하여 시각화합니다.
오늘 우리도 미션 완수~~~!!!! YEAH~~!!!
오늘 저와 함께 임무완수를 해내어 주셔서 감사합니다~^^*
멋진 오후 보내시고요~~^^*
우리 내일은 편안하게 음악 함께 듣고요~~^^*
화요일엔, 장애물 하나를 만들어 넣어 볼까요~~^^* 좀 더 흥미진진해질 것 같아요~~^^*
장애물을 넘어 우리의 여정을 완수해 내는 멋진 항해를 2025년에 해나가 볼까요~^^*
오늘도 멋진 하루 보내시고요~^^*
우리 내일 또 만나요~~^^* YEAH~~^^*
네~^^* 꿈은 이루어 집니다~^^*
댓글 남기기