Last active
March 25, 2018 02:42
-
-
Save TheCherry/2e71893d01bc54c65ee22b17c173ef27 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file is part of DEAP. | |
# | |
# DEAP is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU Lesser General Public License as | |
# published by the Free Software Foundation, either version 3 of | |
# the License, or (at your option) any later version. | |
# | |
# DEAP is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU Lesser General Public License for more details. | |
# | |
# You should have received a copy of the GNU Lesser General Public | |
# License along with DEAP. If not, see <http://www.gnu.org/licenses/>. | |
# example which maximizes the sum of a list of integers | |
# each of which can be 0 or 1 | |
path_to_food = "Food/" | |
ban_items = [ | |
"Ecoylent" | |
, "Transglutaminase" | |
, "Milk" | |
# , "Bear S U P R E M E" | |
# , "Elk Wellington" | |
# , "Fried Hare Haunches" | |
# , "Boiled Sausage" | |
# , "Seared Meat" | |
# , "Corn Fritters" | |
] | |
craftstations = [ | |
"CampfireObject" | |
, "BakeryOvenObject" | |
, "StoveObject" | |
, "CastIronStoveObject" | |
, "ButcheryTableObject" | |
, "MillObject" | |
, "KitchenObject" | |
# , "LaboratoryObject" | |
] | |
global max_food_combinations, ban_items | |
generations = 250 | |
max_food_combinations = 8 | |
import random | |
from deap import base | |
from deap import creator | |
from deap import tools | |
import multiprocessing | |
from os import listdir | |
import re | |
REGEX_FOOD = r"FriendlyName\s*{\s*get\s*{\s*return\s*\"(?P<name>.*?)\";\s*}\s*}.*Carbs\s*=\s*(?P<carbs>\d*),\s*Fat\s*=\s*(?P<fat>\d*),\s*Protein\s*=\s*(?P<protein>\d*),\s*Vitamins\s*=\s*(?P<vitamins>\d*).*float\s*Calories\s*{\s*get\s*{\s*return\s*(?P<calories>\d*);\s*}\s*}.*CraftingComponent.AddRecipe\(typeof\((?P<craft>.*?)\),\s*this\);" | |
def load_data(path): | |
global ban_items | |
# get file-list | |
data = [] | |
for _file in listdir(path): | |
with open(path + _file) as f: | |
cs_txt = f.read() | |
m = re.finditer(REGEX_FOOD, cs_txt, re.DOTALL) | |
for matchNum, match in enumerate(m): | |
matchNum = matchNum + 1 | |
if(match.group("name") not in ban_items): | |
if(len(only_craft) == 0 or match.group("craft") in craftstations): | |
if(not (int(match.group("carbs")) == 0 and \ | |
int(match.group("fat")) == 0 and \ | |
int(match.group("protein")) == 0 and \ | |
int(match.group("vitamins")) == 0)): # dont add zero food | |
data.append({ | |
"name": match.group("name"), | |
"craft": match.group("craft"), | |
"carbs": int(match.group("carbs")), | |
"fat": int(match.group("fat")), | |
"protein": int(match.group("protein")), | |
"vitamins": int(match.group("vitamins")), | |
"calories": int(match.group("calories")), | |
"nutrients": int(match.group("carbs")) + int(match.group("fat")) + int(match.group("protein")) + int(match.group("vitamins")) | |
}) | |
return data | |
global data | |
data = load_data(path_to_food) | |
creator.create("FitnessMax", base.Fitness, weights=(1.0,)) | |
creator.create("Individual", list, fitness=creator.FitnessMax) | |
toolbox = base.Toolbox() | |
pool = multiprocessing.Pool() | |
toolbox.register("map", pool.map) | |
# Attribute generator | |
# define 'attr_bool' to be an attribute ('gene') | |
# which corresponds to integers sampled uniformly | |
# from the range [0,1] (i.e. 0 or 1 with equal | |
# probability) | |
toolbox.register("attr_bool", random.randint, 0, len(data)+1) | |
# Structure initializers | |
# define 'individual' to be an individual | |
# consisting of 100 'attr_bool' elements ('genes') | |
toolbox.register("individual", tools.initRepeat, creator.Individual, | |
toolbox.attr_bool, max_food_combinations) | |
# define the population to be a list of individuals | |
toolbox.register("population", tools.initRepeat, list, toolbox.individual) | |
# the goal ('fitness') function to be maximized | |
def evalOneMax(gene): | |
""" | |
Helper method used to return the fitness for the chromosome based | |
on its gene. | |
""" | |
all_nutrients_cal = 0 | |
all_cal = 0 | |
weight_fat = 0 | |
weight_carbs = 0 | |
weight_protein = 0 | |
weight_vitamins = 0 | |
modificator = 0 | |
for gen in gene: | |
if(gen < len(data)): | |
all_nutrients_cal += (data[gen]["nutrients"] * data[gen]["calories"]) | |
all_cal += data[gen]["calories"] | |
weight_fat += (data[gen]["calories"] * data[gen]["fat"]) | |
weight_carbs += (data[gen]["calories"] * data[gen]["carbs"]) | |
weight_protein += (data[gen]["calories"] * data[gen]["protein"]) | |
weight_vitamins += (data[gen]["calories"] * data[gen]["vitamins"]) | |
modificator -= 0.2 # less is more! | |
if(all_cal == 0): | |
return 0, | |
fat = weight_fat / all_cal | |
carbs = weight_carbs / all_cal | |
protein = weight_protein / all_cal | |
vitamins = weight_vitamins / all_cal | |
balance = (sum([fat, carbs, protein, vitamins]) / (max([fat, carbs, protein, vitamins])*4))*2.0 | |
return (((all_nutrients_cal / all_cal) * balance)+modificator), | |
#---------- | |
# Operator registration | |
#---------- | |
# register the goal / fitness function | |
toolbox.register("evaluate", evalOneMax) | |
# register the crossover operator | |
toolbox.register("mate", tools.cxTwoPoint) | |
# register a mutation operator with a probability to | |
# flip each attribute/gene of 0.05 | |
toolbox.register("mutate", tools.mutFlipBit, indpb=0.1) | |
# operator for selecting individuals for breeding the next | |
# generation: each individual of the current generation | |
# is replaced by the 'fittest' (best) of three individuals | |
# drawn randomly from the current generation. | |
toolbox.register("select", tools.selTournament, tournsize=3) | |
#---------- | |
def main(): | |
# random.seed(64) | |
# create an initial population of 300 individuals (where | |
# each individual is a list of integers) | |
pop = toolbox.population(n=2500) | |
# CXPB is the probability with which two individuals | |
# are crossed | |
# | |
# MUTPB is the probability for mutating an individual | |
CXPB, MUTPB = 0.5, 0.5 | |
print("Start of evolution") | |
# Evaluate the entire population | |
fitnesses = list(map(toolbox.evaluate, pop)) | |
for ind, fit in zip(pop, fitnesses): | |
ind.fitness.values = fit | |
print(" Evaluated %i individuals" % len(pop)) | |
# Extracting all the fitnesses of | |
fits = [ind.fitness.values[0] for ind in pop] | |
# Variable keeping track of the number of generations | |
g = 0 | |
best_ind = None | |
best_fit = 0 | |
# Begin the evolution | |
while g < generations: | |
# A new generation | |
g = g + 1 | |
print("-- Generation %i --" % g) | |
# Select the next generation individuals | |
offspring = toolbox.select(pop, len(pop)) | |
# Clone the selected individuals | |
offspring = list(map(toolbox.clone, offspring)) | |
# Apply crossover and mutation on the offspring | |
for child1, child2 in zip(offspring[::2], offspring[1::2]): | |
# cross two individuals with probability CXPB | |
if random.random() < CXPB: | |
toolbox.mate(child1, child2) | |
# fitness values of the children | |
# must be recalculated later | |
del child1.fitness.values | |
del child2.fitness.values | |
for mutant in offspring: | |
# mutate an individual with probability MUTPB | |
if random.random() < MUTPB: | |
toolbox.mutate(mutant) | |
del mutant.fitness.values | |
# Evaluate the individuals with an invalid fitness | |
invalid_ind = [ind for ind in offspring if not ind.fitness.valid] | |
fitnesses = map(toolbox.evaluate, invalid_ind) | |
for ind, fit in zip(invalid_ind, fitnesses): | |
ind.fitness.values = fit | |
print(" Evaluated %i individuals" % len(invalid_ind)) | |
# The population is entirely replaced by the offspring | |
pop[:] = offspring | |
# Gather all the fitnesses in one list and print the stats | |
fits = [ind.fitness.values[0] for ind in pop] | |
length = len(pop) | |
mean = sum(fits) / length | |
sum2 = sum(x*x for x in fits) | |
std = abs(sum2 / length - mean**2)**0.5 | |
print(" Min %s" % min(fits)) | |
print(" Max %s" % max(fits)) | |
print(" Avg %s" % mean) | |
print(" Std %s" % std) | |
if(max(fits) > best_fit): | |
best_ind = tools.selBest(pop, 1)[0] | |
best_fit = best_ind.fitness.values[0] | |
print("-- End of (successful) evolution --") | |
# best_ind = tools.selBest(pop, 1)[0] | |
print("Best individual is %s, %s" % (best_ind, best_ind.fitness.values)) | |
for val in best_ind: | |
if(val < len(data)): | |
print(data[val]["name"]) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
trying to run this on windows machine... getting errors:
doesn't look like only_craft is defined anywhere, if I remove the only_craft part in the if statement i think it loops indefinitely.
is their any requirements that I may be missing ?
Python 2.7.14
installed deap via pip: