-
Notifications
You must be signed in to change notification settings - Fork 16
/
Recipe.js
89 lines (71 loc) · 3.15 KB
/
Recipe.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
/**
* A Recipe is responsible for specifying the amount of each ingredient that should be used.
*/
var Recipe = function(soylent, ingredientAmounts) {
this.soylent = soylent;
if (ingredientAmounts) {
this.ingredientAmounts = ingredientAmounts;
}
else {
this.ingredientAmounts = [];
// Initialize the recipe with random amounts of each ingredient.
for (var i = 0; i < this.soylent.ingredients.length; i++){
this.ingredientAmounts.push(Math.random() * this.soylent.ingredients[i].maxAmount);
}
}
this.calculateCompleteness();
};
/**
* This function 'mates' two recipes, producing a 'child' recipe.
* The child recipe contains most of it's parents chromosomes, with a few of them mutated slightly.
*/
Recipe.prototype.createChildWith = function(mate) {
// Pick random ingredient amounts from each parent.
var pos = Math.floor(Math.random() * this.soylent.ingredients.length);
var childIngredientAmounts = [];this.ingredientAmounts.slice(0, pos).concat(mate.ingredientAmounts.slice(pos));
for (var i=0; i< this.soylent.ingredients.length; i++) {
var randomParent = Math.random() > 0.5 ? this : mate;
childIngredientAmounts.push(randomParent.ingredientAmounts[i]);
}
// Pick some random ingredient in the recipe to mutate.
// A mutation is defined as increasing or decreasing the amount of an ingredient by the mutationMultiplier.
while (Math.random() < this.soylent.mutationProbability){
var ingredientToMutate = Math.floor(Math.random() * this.soylent.ingredients.length);
var mutationMultiplier = Math.random() > 0.5 ? (1 - this.soylent.mutationMultiplier) : (1 + this.soylent.mutationMultiplier);
childIngredientAmounts[ingredientToMutate] = childIngredientAmounts[ingredientToMutate] * mutationMultiplier;
}
return new Recipe(this.soylent, childIngredientAmounts);
};
/**
* Sets the current nutrient totals for the recipe.
*/
Recipe.prototype.calculateTotalNutrients = function() {
var nutrients = _.keys(this.soylent.targetNutrients);
this.nutrientTotals = {};
_.each(this.soylent.ingredients, function(ingredient, idx) {
_.each(nutrients, function(nutrient) {
var ingredientNutrient = ingredient[nutrient] * this.ingredientAmounts[idx];
this.nutrientTotals[nutrient] = this.nutrientTotals[nutrient] || 0;
this.nutrientTotals[nutrient] += ingredientNutrient;
}, this);
}, this);
};
/**
* Returns the recipes score. The closer the number is to 0, the better.
*/
Recipe.prototype.calculateCompleteness = function() {
var nutrients = _.keys(this.soylent.targetNutrients);
this.calculateTotalNutrients();
var nutrientCompleteness = 0;
_.each(nutrients, function(nutrient) {
var completeness = this.nutrientTotals[nutrient] / this.soylent.targetNutrients[nutrient] * 100;
if (completeness > 100) {
completeness = completeness - 100;
}
else {
completeness = 100 - completeness;
}
nutrientCompleteness += completeness;
}, this);
this.completenessScore = -nutrientCompleteness;
};