-
Notifications
You must be signed in to change notification settings - Fork 0
/
dna.js
133 lines (114 loc) · 3.1 KB
/
dna.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Daniel Shiffman
// Nature of Code: Intelligence and Learning
// https://github.com/shiffman/NOC-S17-2-Intelligence-Learning
// Evolve Traveling Salesperson
// A generic function to swap two elements in an array
function swap(a, i, j) {
var temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// A DNA object is an order through the cities
function DNA(total, order) {
// Start assuming it's distance is infinity and fitness is zero
this.dist = Infinity;
this.fitness = 0;
// Is this being made from another DNA object?
if (order instanceof Array) {
// Just copy the order
this.order = order.slice();
// Mutation
// 50% of the time shuffle one spot to see if it improves
if (random(1) < 0.05) {
this.shuffle();
}
} else {
// Create a random order
this.order = [];
for (var i = 0; i < total; i++) {
this.order[i] = i;
}
// Shuffle randomly 100 times
// Is this good enough for variation?
for (var n = 0; n < 100; n++) {
this.shuffle();
}
}
}
// Shuffle array one time
DNA.prototype.shuffle = function() {
var i = floor(random(this.order.length));
var j = floor(random(this.order.length));
swap(this.order, i, j);
}
// How long is this particular path?
DNA.prototype.calcDistance = function() {
var sum = 0;
for (var i = 0; i < this.order.length - 1; i++) {
var cityAIndex = this.order[i];
var cityA = cities[cityAIndex];
var cityBIndex = this.order[i + 1];
var cityB = cities[cityBIndex];
var d = dist(cityA.x, cityA.y, cityB.x, cityB.y);
sum += d;
}
this.dist = sum;
return this.dist;
}
// Map the fitess where shortest is best, longest is worst
DNA.prototype.mapFitness = function(minD, maxD) {
this.fitness = map(this.dist, minD, maxD, 1, 0);
return this.fitness;
}
// Normalize against total fitness
DNA.prototype.normalizeFitness = function(total) {
this.fitness /= total;
}
// Draw the path
DNA.prototype.show = function() {
// Lines
stroke(255);
strokeWeight(1);
noFill();
beginShape();
for (var i = 0; i < this.order.length; i++) {
var n = this.order[i];
vertex(cities[n].x, cities[n].y);
}
endShape();
// Cities
fill('#6C63FF');
for (var i = 0; i < this.order.length; i++) {
var n = this.order[i];
ellipse(cities[n].x, cities[n].y, 10, 10);
}
}
// This is one way to crossover two paths
DNA.prototype.crossover = function(other) {
// Grab two orders
var order1 = this.order;
var order2 = other.order;
// Pick a random start and endpoint
var start = floor(random(order1.length));
var end = floor(random(start + 1, order1.length + 1));
// Grab part of the the first order
var neworder = order1.slice(start, end);
// How many spots do we need to add?
var leftover = order1.length - neworder.length;
// Go through order 2
var count = 0;
var i = 0;
// As long as we aren't finished
while (count < leftover) {
// Take a city from order2
var city = order2[i];
// If it isn't part of the new child path yet
if (!neworder.includes(city)) {
// Add it!
neworder.push(city);
count++;
}
i++;
}
return neworder;
}