''' Created on Aug 29, 2015 @author: Brett Paufler Copyright Brett Paufler ''' from random import randint, choice def random_recipe(): '''Returns a random recipe formula in the form of a list six integers long. Ex: [1, 2, 7, 13, 8]''' flour = randint(1, 10) eggs = randint(1, 10) sugar = randint(1, 10) chips = randint(1, 25) walnuts = randint(0, 10) recipe = [flour, eggs, sugar, chips, walnuts] return recipe def score_recipe(recipe): '''Simplistic scoring for a chocolate chip recipe. Takes an integer recipe list, returns a signle integer value. Ex: recipe=[10, 9, 7, 12, 0], returns: 101''' flour, eggs, sugar, chips, walnuts = recipe lots_o_chips = chips * chips low_nuts = (chips - walnuts) * 10 things_are_expensive = - sugar * eggs carbs_suck = - pow(flour, 2) score = lots_o_chips + low_nuts + things_are_expensive + carbs_suck return score def seed_recipes(keepers): '''Returns a num long sorted list of (score, recipe) tuples. Ex: [(428, [4, 7, 1, 19, 10]), (347, [4, 4, 3, 15, 0])...''' seed = [random_recipe() for _ in range(keepers)] seed = [(score_recipe(s), s) for s in seed] seed = sorted(seed, reverse=True) return seed def recipe_mutator(seed, keepers): '''Genetic Algorithm applied to a recipe seed. 1) New random recipes are added to seed 2) All combinations of recipes are woven together 3) Only the best are returned Takes a sorted scored recipe list (the seed) and returns same. Keepers is length and controls extent of manipulations. Score of best returned recipe is always >= that of passed seed.''' seed = list(seed) print 'Passed Seed:', seed[:2] for n in range(keepers): print 'Recipe Mutator: Loop %d of %d' % (n + 1, keepers) seed += seed_recipes(keepers) mutations = [] for sR1 in seed: for sR2 in [s for s in seed if s != sR1]: mutations.append([choice(pair) for pair in zip(sR1, sR2)]) seed += mutations seed = sorted(seed, reverse=True) seed = seed[:keepers] print seed[:2] return seed def recipe_iterator(seed, keepers, target, i): '''Returns a scored recipe list whose best recipe exceeds target score, or throws an exception trying. No provision is made to limit recursion depth or insure score is mathematically obtainable.''' if seed[0][0] <= target: i += 1 seed = recipe_mutator(seed, keepers) return recipe_iterator(seed, keepers, target, i) else: print 'Recipe Iterator Loops: %d' % i return seed if __name__ == '__main__': #Eyeballing Scoring Criteria print 'Reasonable Recipe Score: %d' % (25 * 25 + 250 - 1 - 1) #Random Number, higher runs longer, gives better results keepers = 5 #Test run of function recipe = random_recipe() print 'recipe: ', recipe #Test run of function score = score_recipe(recipe) print 'score: ', score #Genetic Programming Demo Run seed = seed_recipes(keepers) rm_recipe = recipe_mutator(seed, keepers)[0] ri_recipe = recipe_iterator(seed, keepers, target=850, i=0)[0] print print rm_recipe print ri_recipe