/
genetic.py
116 lines (96 loc) · 4.38 KB
/
genetic.py
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
import random
from orderedset import OrderedSet
from move_list import MoveList
from players import PLAYERS
from config import DEBUG
from battle_simulation import battle_simulation
import time
def genetic(players = None,
population_size = 600,
iterations_limit = 240,
retain_parents = .1,
mutation_rate = .7,
radiation_amount = 50):
# Logging for debug purposes
if DEBUG:
genetic_log = open('genetic.log', 'w')
def log_genetic_data(string):
genetic_log.write(string + "\n")
# If needed, generate random players
if players is None:
first_player = random.choice(PLAYERS)
second_player = random.choice(PLAYERS)
else:
first_player, second_player = players
# Create the evaluation function
simulation_results_cache = {}
prior = time.time()
def evaluate_population(population):
"""
Given a list of move lists (the population),
Returns a list of (move list, value of move list, corresponding battle_id)
that is sorted by the values.
"""
population_values = []
duplicates = 0
for move_list in population:
if move_list.short_string() in simulation_results_cache:
value, battle_id = simulation_results_cache[move_list.short_string()]
duplicates += 1
else:
value, battle_id = battle_simulation(move_list,
first_player(move_list),
second_player(move_list))
simulation_results_cache[move_list.short_string()] = (value, battle_id)
population_values.append( (move_list, value, battle_id) )
population_values.sort(key = lambda item: -item[1]) # sort by value
if DEBUG:
log_genetic_data("\tDuplicates: %d" % (duplicates,))
return population_values
# Generate the new population
population = [MoveList() for x in xrange(population_size)]
# Iterate through the Genetic Algorithm
for iteration in xrange(iterations_limit):
# Log this iteration
if DEBUG: log_genetic_data("Iteration: %d" % (1+iteration,))
# Calculate the size of the segments of our new population
parents_retained = int(round(retain_parents * population_size))
mutants_generated = int(round(mutation_rate * population_size))
# Run the simulation on each move_list, and sort by best
population_values = evaluate_population(population)
# Log the values and battle ids
if DEBUG:
for move_list, value, battle_id in population_values:
log_genetic_data("\tValue: %d, Battle: %d, Move List: %s" %
(value, battle_id, move_list.short_string()))
# create our new population
population = OrderedSet()
top_perfomers = population_values[:parents_retained]
# Retain the top performers of the old generation
for move_list, value, battle_id in top_perfomers:
population.add(move_list)
# Add in the mutants!
while len(population) - parents_retained < mutants_generated:
mutant, value, battle_id = random.choice(top_perfomers)
for r in xrange(radiation_amount):
mutant = mutant.mutate()
population.add(mutant)
# Add in the children!
while len(population) < population_size:
dad, mom = random.sample(population, 2)
child = dad.cross_over(mom).mutate()
population.add(child)
# Report to the user that we've finished an iteration!
print "Iteration", str(iteration+1), "Time:", round(time.time() - prior, 3)
prior = time.time()
# Calculate the final resulting population
results = evaluate_population(population)
# Close up the log
if DEBUG:
log_genetic_data("Final Results")
for move_list, value, battle_id in population_values:
log_genetic_data("\tValue: %d, Battle: %d, Move List: %s" %
(value, battle_id, move_list.short_string()))
if DEBUG: genetic_log.close()
# Return the best state
return results[0][0]