def __init__(self, surface, b_config, e_config): # UI stuff self.stfont = pygame.font.SysFont('Consolas', 15, bold=False) self.drawing = True self.surface = surface # neat-python variables self.b_conf = b_config self.e_conf = e_config self.b_pop = neat.Population(b_config) self.e_pop = neat.Population(e_config) self.b_brains = [ neat.nn.FeedForwardNetwork.create(self.b_pop.population[i], b_config) for i in self.b_pop.population ] self.e_brains = [ neat.nn.FeedForwardNetwork.create(self.e_pop.population[i], e_config) for i in self.e_pop.population ] # game objects self.bow_gen = [ BowCreature(self.surface, GameObjects.Bow(self.surface)) for i in range(0, len(self.b_pop.population)) ] self.enemy_gen = [ SquareCreature(self.surface, GameObjects.Enemy(self.surface, 100)) for i in range(0, len(self.e_pop.population)) ] self.managers = [ GameObjects.WaveManager([self.enemy_gen[i].game_model], self.bow_gen[i].game_model) for i in range(0, len(self.bow_gen)) ] self.timers = [0 for i in range(0, len(self.bow_gen))] # statistics self.generations = 1 self.avg_b_fitness = [] self.avg_e_fitness = [] self.kills = [] self.e_stdev = None self.b_stdev = None self.b_gen_fitness = [] self.e_gen_fitness = []
def multicycle(self): """Runs and draws a game cycle on multiple enemies and bows. Restarts when all timers reach 100/all enemies die.""" view_single = False mp = pygame.mouse.get_pos() mouse_ind = None # check if viewing a single bow-enemy pair if int(mp[1]) in range(12, 12 + 10 * len(self.bow_gen)) and int( mp[0]) in range(860, 990): mouse_ind = (mp[1] - 12) // 10 view_single = True # game loop for i in range(0, len(self.bow_gen)): if self.timers[i] < 100: # updating game objects b = self.bow_gen[i].game_model e = self.enemy_gen[i].game_model self.managers[i].detectCollisions() self.enemy_gen[i].avoided = self.managers[i].missed # setting input for enemy neural networks e_inp = [ b.draw_dx, b.draw_dy, (e.pos[0] - 255), (e.pos[1] - 255) ] for q in e.quadstat: if q: e_inp.append(100) else: e_inp.append(0) self.e_brains[i].activate(e_inp) # setting input for bow neural networks b_inp = [b.draw_dx, b.draw_dy] b_inp.extend([(e.pos[0] - 255), (e.pos[1] - 255), e.vel[0] * 3, e.vel[1] * 3]) self.b_brains[i].activate(b_inp) # drawing game objects and timer bars time_rect = pygame.Rect(860, 12 + 10 * i, (100 - self.timers[i]) * 1.3, 5) # check for high bow fitness, highlight timer bars c = (0, 255, 0) if self.generations > 1 and self.bow_gen[i].set_fitness( self.managers[i].avg_dist ) > self.avg_b_fitness[-1] + self.b_stdev * 1.2: c = (255, 0, 0) pygame.draw.rect(self.surface, c, time_rect) # listening for NN interaction, and updating game models b_out = [self.b_brains[i].values[ind] for ind in range(0, 3)] e_out = [self.e_brains[i].values[ind] for ind in range(0, 4)] self.enemy_gen[i].move_model(e_out) arrow = self.bow_gen[i].move_model(b_out) if arrow is not None: self.managers[i].add_arrow(arrow) # check if viewing a single bow-enemy pair, draw respective stats if (not view_single) or (i == mouse_ind): self.managers[i].draw() if view_single: self.enemy_gen[i].set_fitness() self.enemy_gen[i].draw_fitness(self.stfont, (600, 60)) self.bow_gen[i].set_fitness(self.managers[i].avg_dist) self.bow_gen[i].draw_fitness(self.stfont, (600, 400)) self.draw_nn(i, b_out) self.draw_nn(i, e_out, True) # countdown when stuck/unstuck, ending timer when enemy dies if len(self.managers[i].enemies) < 1: self.timers[i] = 150 self.bow_gen[i].killed = True elif not e.is_moving() or self.managers[ i].failed_shots > 15 or b.arrows > 18 or b.time_between_shots > 300: self.timers[i] += 0.2 else: self.timers[i] = 0 self.drawstats() # checking all generations finished, select, breed, and mutate for i in self.timers: if i < 100: return None self.b_gen_fitness, self.e_gen_fitness = [], [] self.b_pop.run(self.bow_ff, 1) self.e_pop.run(self.enemy_ff, 1) self.shuffle_pops() # update kill count for generation k = 0 for m in self.managers: if len(m.enemies) < 1: k += 1 self.kills.append(k) # reset timers and game models, brains self.bow_gen = [ BowCreature(self.surface, GameObjects.Bow(self.surface)) for i in range(0, len(self.b_pop.population)) ] self.enemy_gen = [ SquareCreature(self.surface, GameObjects.Enemy(self.surface, 100)) for i in range(0, len(self.e_pop.population)) ] self.managers = [ GameObjects.WaveManager([self.enemy_gen[i].game_model], self.bow_gen[i].game_model) for i in range(0, len(self.bow_gen)) ] self.timers = [0 for i in range(0, len(self.bow_gen))] self.b_brains = [ neat.nn.FeedForwardNetwork.create(self.b_pop.population[i], self.b_conf) for i in self.b_pop.population ] self.e_brains = [ neat.nn.FeedForwardNetwork.create(self.e_pop.population[i], self.e_conf) for i in self.e_pop.population ] self.generations += 1