Skip to content

Commit c83c2a0

Browse files
author
Gal Malachi
committed
fitness calculation added.
1 parent 33d125c commit c83c2a0

File tree

2 files changed

+167
-101
lines changed

2 files changed

+167
-101
lines changed

package-lock.json

+16-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/genetic-algorithms/helper-service.js

+151-85
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,166 @@
11
import configuration from "./conf";
2+
import _ from "lodash";
23

34
class HelperService {
4-
5-
chromosomelngth = 40;
6-
neighborDirs = [
7-
[-1, -1],
8-
[0, -1],
9-
[1, -1],
10-
[-1, 0],
11-
[1, 0],
12-
[-1, 1],
13-
[0, 1],
14-
[1, 1]
15-
];
16-
17-
generateEnvironment = () => {
18-
const envSize = configuration.gridSize;
19-
const grid = new Array(envSize);
20-
21-
for (let i = 0; i < envSize; i++) {
22-
grid[i] = new Array(envSize);
23-
for (let j = 0; j < envSize; j++) {
24-
const cellIndex = i * envSize + j;
25-
26-
grid[i][j] = {
27-
index: cellIndex,
28-
type: this.getCellType(cellIndex, i, j)
29-
}
30-
}
31-
}
32-
return grid;
5+
CHROMOSOMELENGTH = 40;
6+
FITNESS_COEFFICIENT = 1000000;
7+
TARGET_COORDINATES = {
8+
x: configuration.gridSize - 1,
9+
y: configuration.gridSize - 1
10+
};
11+
obstacles = [];
12+
neighborDirs = [
13+
[-1, -1],
14+
[0, -1],
15+
[1, -1],
16+
[-1, 0],
17+
[1, 0],
18+
[-1, 1],
19+
[0, 1],
20+
[1, 1]
21+
];
22+
23+
generateEnvironment = () => {
24+
const envSize = configuration.gridSize;
25+
const grid = new Array(envSize);
26+
27+
for (let i = 0; i < envSize; i++) {
28+
grid[i] = new Array(envSize);
29+
for (let j = 0; j < envSize; j++) {
30+
const cellIndex = i * envSize + j;
31+
32+
grid[i][j] = {
33+
index: cellIndex,
34+
type: this.getCellType(cellIndex, i, j)
35+
};
36+
}
3337
}
34-
35-
generatePopulation = (grid) => {
36-
const population = [];
37-
const populationSize = configuration.populationSize;
38-
39-
for (let i = 0; i < populationSize; i++) {
40-
const chromosome = [{ x: 0, y: 0 }];
41-
42-
for (let j = 0; j < this.chromosomelngth - 1; j++) {
43-
const { x, y } = chromosome[j];
44-
const neighbors = this.getNeighbors(x, y, grid);
45-
chromosome[j + 1] = this.getRandomNeighborIndex(neighbors);
46-
}
47-
population.push(chromosome);
48-
}
49-
return population;
38+
return grid;
39+
};
40+
41+
generatePopulation = grid => {
42+
const population = [];
43+
const populationSize = configuration.populationSize;
44+
45+
for (let i = 0; i < populationSize; i++) {
46+
const chromosome = {
47+
coordinates: [{ x: 0, y: 0 }],
48+
distanceFromTarget: undefined,
49+
fitness: undefined
50+
};
51+
52+
for (let j = 0; j < this.CHROMOSOMELENGTH - 1; j++) {
53+
const { x, y } = chromosome.coordinates[j];
54+
const neighbors = this.getNeighbors(x, y, grid);
55+
chromosome.coordinates[j + 1] = this.getRandomNeighborCoordinates(
56+
neighbors
57+
);
58+
}
59+
chromosome.distanceFromTarget = this.getDistanceFromTarget(
60+
chromosome.coordinates[this.CHROMOSOMELENGTH - 1]
61+
);
62+
population.push(chromosome);
5063
}
5164

52-
getRandomNeighborIndex = (neighbors) => {
53-
const keys = Object.keys(neighbors)
54-
const neighbor = neighbors[keys[Math.floor(Math.random() * keys.length)]];
55-
return this.getCordinatesByIndex(neighbor.index);
65+
return this.calculatePopulationFitness(population);
66+
};
67+
68+
calculatePopulationFitness(population) {
69+
population.forEach(chromosome => {
70+
this.calculateChromosomeFitness(chromosome);
71+
});
72+
73+
return _.sortBy(population, ["fitness"]);
74+
}
75+
76+
calculateChromosomeFitness(chromosome) {
77+
let score = 0;
78+
const { coordinates } = chromosome;
79+
const hasObstacles = !_.isEmpty(
80+
_.intersectionWith(this.obstacles, coordinates, _.isEqual)
81+
);
82+
const indexOfTargetCoordinateInPath = _.findIndex(coordinates, coordinate =>
83+
_.isEqual(coordinate, this.TARGET_COORDINATES)
84+
);
85+
86+
const lastCoordinateInPath =
87+
indexOfTargetCoordinateInPath >= 0
88+
? coordinates[indexOfTargetCoordinateInPath]
89+
: coordinates[coordinates.length - 1];
90+
91+
const pathLength =
92+
indexOfTargetCoordinateInPath >= 0
93+
? indexOfTargetCoordinateInPath
94+
: this.CHROMOSOMELENGTH;
95+
96+
const distanceFromTarget = this.getDistanceFromTarget(lastCoordinateInPath);
97+
98+
score = pathLength / this.CHROMOSOMELENGTH;
99+
score = hasObstacles ? score + 1 : score;
100+
score =
101+
distanceFromTarget === 0
102+
? distanceFromTarget
103+
: distanceFromTarget / Math.pow(configuration.gridSize, 2);
104+
105+
chromosome.fitness = score;
106+
}
107+
108+
getDistanceFromTarget(coordinates) {
109+
return Math.sqrt(
110+
Math.pow(coordinates.x - this.TARGET_COORDINATES.x, 2) +
111+
Math.pow(coordinates.y - this.TARGET_COORDINATES.y, 2)
112+
);
113+
}
114+
115+
getRandomNeighborCoordinates = neighbors => {
116+
const keys = Object.keys(neighbors);
117+
const neighbor = neighbors[keys[Math.floor(Math.random() * keys.length)]];
118+
return this.getCoordinatesByIndex(neighbor.index);
119+
};
120+
121+
getCoordinatesByIndex = index => {
122+
return {
123+
x: Math.floor(index / configuration.gridSize),
124+
y: index % configuration.gridSize
125+
};
126+
};
127+
128+
getNeighbors = (x, y, grid) => {
129+
const neighbors = this.neighborDirs.map(([dX, dY]) => [x + dX, y + dY]);
130+
const gridNeighbors = neighbors.map(([i, j]) =>
131+
this.getFromGrid(grid, i, j)
132+
);
133+
return gridNeighbors.filter(v => v);
134+
};
135+
136+
getFromGrid = (grid, x, y) => (grid[x] || [])[y];
137+
138+
getCellType = (cellIndex, i, j) => {
139+
if (cellIndex === 0) {
140+
return "robot";
141+
} else if (cellIndex === Math.pow(configuration.gridSize, 2) - 1) {
142+
return "target";
143+
} else if (this.isObstacle(i, j)) {
144+
this.obstacles.push({ x: i, y: j });
145+
return "obstacle";
56146
}
147+
return "empty";
148+
};
57149

58-
getCordinatesByIndex = (index) => {
59-
return {
60-
x: Math.floor(index / configuration.gridSize),
61-
y: index % configuration.gridSize
62-
}
150+
isObstacle = i => {
151+
if (!configuration.hasObstacles) {
152+
return false;
63153
}
64154

65-
getNeighbors = (x, y, grid) => {
66-
const neighbors = this.neighborDirs.map(([dX, dY]) => [x + dX, y + dY]);
67-
const gridNeighbors = neighbors.map(([i, j]) =>
68-
this.getFromGrid(grid, i, j)
69-
);
70-
return gridNeighbors.filter(v => v);
71-
};
72-
73-
getFromGrid = (grid, x, y) => (grid[x] || [])[y];
74-
75-
getCellType = (cellIndex, i, j) => {
76-
if (cellIndex === 0) {
77-
return 'robot';
78-
} else if (cellIndex === (Math.pow(configuration.gridSize, 2) - 1)) {
79-
return 'target';
80-
} else if (this.isObstacle(i, j)) {
81-
return 'obstacle';
82-
}
83-
return 'empty';
155+
if (
156+
Math.floor(configuration.gridSize * 0.3) === i ||
157+
Math.floor(configuration.gridSize * 0.75) === i
158+
) {
159+
return Math.floor(Math.random() * 10 + 1) > 7;
84160
}
85161

86-
isObstacle = (i) => {
87-
if (!configuration.hasObstacles) {
88-
return false;
89-
}
90-
91-
if (Math.floor(configuration.gridSize * 0.3) === i || Math.floor(configuration.gridSize * 0.75) === i) {
92-
return Math.floor(Math.random() * 10 + 1) > 7;
93-
};
94-
95-
return false;
96-
}
162+
return false;
163+
};
97164
}
98165

99166
export default new HelperService();
100-

0 commit comments

Comments
 (0)