-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
182 lines (154 loc) · 5.42 KB
/
Program.cs
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
public const int CALORIES = 800;
public const int GRAMS_OF_CARBS = 100;
public const int GRAMS_OF_PROTEIN = 50;
public const int GRAMS_OF_FAT = 22;
public const int NUMBER_OF_MUTATIONS_PER_CYCLE = 15;
public const int NUMBER_OF_CYCLES_PER_SIMULATION = 1000;
public const int NUMBER_OF_SIMULATIONS = 100;
static void Main(string[] args)
{
var globalBestRecipe = GetBaseRecipe();
for (int simulationCount = 0; simulationCount < NUMBER_OF_SIMULATIONS; simulationCount++)
{
var simulationBestRecipe = GetBaseRecipe();
for (int cycleCount = 0; cycleCount < NUMBER_OF_CYCLES_PER_SIMULATION; cycleCount++)
{
var mutations = new List<List<RecipeLine>>();
for (int mutationCount = 0; mutationCount < NUMBER_OF_MUTATIONS_PER_CYCLE; mutationCount++)
{
var copyOfBase = simulationBestRecipe.Copy();
var mutationOfBase = Mutate(copyOfBase);
mutations.Add(mutationOfBase);
}
for (int mutationIndex = 0; mutationIndex < mutations.Count; mutationIndex++)
{
if (GetScore(mutations[mutationIndex]) < GetScore(simulationBestRecipe))
{
simulationBestRecipe = mutations[mutationIndex];
}
}
if (GetScore(simulationBestRecipe) == 0)
{
break;
}
}
if(GetScore(simulationBestRecipe) < GetScore(globalBestRecipe) )
{
globalBestRecipe = simulationBestRecipe;
}
}
DumpRecipe(globalBestRecipe);
}
public static double GetScore(List<RecipeLine> recipe)
{
return Math.Abs(recipe.Sum(s => s.Ingredient.CaloriesPerUnit * s.NumberOfUnits) - CALORIES) +
Math.Abs(recipe.Sum(s => s.Ingredient.ProteinPerUnit * s.NumberOfUnits) - GRAMS_OF_PROTEIN) +
Math.Abs(recipe.Sum(s => s.Ingredient.CarbsPerUnit * s.NumberOfUnits) - GRAMS_OF_CARBS) +
Math.Abs(recipe.Sum(s => s.Ingredient.FatPerUnit * s.NumberOfUnits) - GRAMS_OF_FAT);
}
public static List<RecipeLine> Mutate(List<RecipeLine> recipe)
{
var random = new Random();
var result = random.Next(1, 2);
switch (result)
{
case 1:
recipe = MutateRandomQuantity(recipe);
break;
}
return recipe;
}
public static List<RecipeLine> MutateRandomQuantity(List<RecipeLine> recipe)
{
var random = new Random();
var indexResult = random.Next(0, recipe.Count);
var directionResult = random.Next(0, 2);
recipe[indexResult].NumberOfUnits = (int)Math.Round(recipe[indexResult].NumberOfUnits * (directionResult == 1 ? 1.1 : 0.9));
return recipe;
}
public static void DumpRecipe(List<RecipeLine> recipe)
{
Debug.WriteLine("Recipe ======");
foreach (var line in recipe)
{
Debug.WriteLine(line.NumberOfUnits + line.Ingredient.UnitName + " of " + line.Ingredient.Name);
}
Debug.WriteLine("Score of " + GetScore(recipe));
Debug.WriteLine("=============");
}
public static List<Part> GetIngredients()
{
return new List<Part>{
new Part{
Name="Whey Powder",
UnitName="g",
CaloriesPerUnit=3.75,
CarbsPerUnit=0.09375,
ProteinPerUnit=0.75,
FatPerUnit=0.046875
},
new Part{
Name="Oat Flour",
UnitName="g",
CaloriesPerUnit=4.04,
CarbsPerUnit=0.66,
ProteinPerUnit=0.15,
FatPerUnit=.091
},
new Part{
Name="Oil",
UnitName="g",
CaloriesPerUnit=8,
CarbsPerUnit=.94,
ProteinPerUnit=0,
FatPerUnit=.9
}
};
}
public static List<RecipeLine> GetBaseRecipe()
{
var availableParts = GetIngredients();
var recipe = new List<RecipeLine>();
foreach(var part in availableParts)
{
recipe.Add(new RecipeLine { NumberOfUnits = 10, Ingredient = part });
}
return recipe;
}
}
public static class Extensions
{
public static List<RecipeLine> Copy(this List<RecipeLine> original)
{
return original.Select(item => (RecipeLine)item.Clone()).ToList();
}
}
public class Part
{
public string Name;
public string UnitName;
public double CaloriesPerUnit;
public double CarbsPerUnit;
public double ProteinPerUnit;
public double FatPerUnit;
}
public class RecipeLine : ICloneable
{
public int NumberOfUnits;
public Part Ingredient;
public object Clone()
{
return new RecipeLine { Ingredient = this.Ingredient, NumberOfUnits = this.NumberOfUnits };
}
}
}