|
|
|
import pygame
|
|
import sys
|
|
import os
|
|
import neat
|
|
import numpy as np
|
|
import pickle
|
|
import random
|
|
import time
|
|
import settings as s
|
|
from environment import Environment
|
|
from agent_coev import AgentCoEv
|
|
|
|
|
|
def eval_simulation(genome_red, config_red, genome_blue, config_blue):
|
|
"""
|
|
Bir kırmızı ve bir mavi genom arasındaki tek bir maçı simüle eder.
|
|
Her iki koloninin topladığı yem miktarını döndürür.
|
|
"""
|
|
|
|
net_red = neat.nn.FeedForwardNetwork.create(genome_red, config_red)
|
|
net_blue = neat.nn.FeedForwardNetwork.create(genome_blue, config_blue)
|
|
|
|
|
|
environment = Environment(s.SCREEN_WIDTH, s.SCREEN_HEIGHT)
|
|
|
|
|
|
agents_red = [AgentCoEv(genome_red, config_red, environment, s.COLONY_ID_RED) for _ in range(s.NUM_AGENTS_PER_COLONY)]
|
|
agents_blue = [AgentCoEv(genome_blue, config_blue, environment, s.COLONY_ID_BLUE) for _ in range(s.NUM_AGENTS_PER_COLONY)]
|
|
all_agents = agents_red + agents_blue
|
|
|
|
|
|
for step in range(s.SIMULATION_STEPS_PER_GEN):
|
|
environment.update()
|
|
|
|
random.shuffle(all_agents)
|
|
for agent in all_agents:
|
|
|
|
agent.update(all_agents)
|
|
|
|
|
|
food_red = sum(agent.food_collected_count for agent in agents_red)
|
|
food_blue = sum(agent.food_collected_count for agent in agents_blue)
|
|
|
|
return food_red, food_blue
|
|
|
|
|
|
def run_coev(config_file):
|
|
"""
|
|
İki popülasyon için NEAT ko-evrim sürecini yönetir.
|
|
"""
|
|
|
|
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
|
|
neat.DefaultSpeciesSet, neat.DefaultStagnation,
|
|
config_file)
|
|
|
|
|
|
checkpoint_dir_red = 'swarm_mind_v4/checkpoints_red'
|
|
checkpoint_dir_blue = 'swarm_mind_v4/checkpoints_blue'
|
|
os.makedirs(checkpoint_dir_red, exist_ok=True)
|
|
os.makedirs(checkpoint_dir_blue, exist_ok=True)
|
|
|
|
try:
|
|
p_red = neat.Checkpointer.restore_checkpoint(os.path.join(checkpoint_dir_red, 'neat-checkpoint-'))
|
|
print("Kırmızı popülasyon checkpoint'ten yüklendi.")
|
|
except Exception:
|
|
print("Kırmızı popülasyon checkpoint bulunamadı, yeni oluşturuluyor.")
|
|
p_red = neat.Population(config)
|
|
|
|
try:
|
|
p_blue = neat.Checkpointer.restore_checkpoint(os.path.join(checkpoint_dir_blue, 'neat-checkpoint-'))
|
|
print("Mavi popülasyon checkpoint'ten yüklendi.")
|
|
except Exception:
|
|
print("Mavi popülasyon checkpoint bulunamadı, yeni oluşturuluyor.")
|
|
p_blue = neat.Population(config)
|
|
|
|
|
|
|
|
p_red.add_reporter(neat.StdOutReporter(True))
|
|
stats_red = neat.StatisticsReporter()
|
|
p_red.add_reporter(stats_red)
|
|
p_red.add_reporter(neat.Checkpointer(generation_interval=5, filename_prefix=os.path.join(checkpoint_dir_red, 'neat-checkpoint-')))
|
|
|
|
|
|
|
|
stats_blue = neat.StatisticsReporter()
|
|
p_blue.add_reporter(stats_blue)
|
|
p_blue.add_reporter(neat.Checkpointer(generation_interval=5, filename_prefix=os.path.join(checkpoint_dir_blue, 'neat-checkpoint-')))
|
|
|
|
|
|
for generation in range(s.NUM_GENERATIONS):
|
|
start_time = time.time()
|
|
print(f"\n****** Ko-Evrim Nesil {generation} Başladı ******")
|
|
|
|
|
|
genomes_red_dict = p_red.population
|
|
genomes_blue_dict = p_blue.population
|
|
|
|
genomes_red_list = list(genomes_red_dict.items())
|
|
genomes_blue_list = list(genomes_blue_dict.items())
|
|
|
|
|
|
|
|
genome_scores_red = {gid: [] for gid, _ in genomes_red_list}
|
|
genome_scores_blue = {gid: [] for gid, _ in genomes_blue_list}
|
|
|
|
|
|
eval_count = 0
|
|
|
|
for gid_r, genome_r in genomes_red_list:
|
|
|
|
num_opponents = min(s.NUM_OPPONENTS_PER_EVAL, len(genomes_blue_list))
|
|
opponents = random.sample(genomes_blue_list, num_opponents)
|
|
|
|
for gid_b, genome_b in opponents:
|
|
|
|
food_r, food_b = eval_simulation(genome_r, config, genome_b, config)
|
|
eval_count += 1
|
|
|
|
|
|
genome_scores_red[gid_r].append((food_r, food_b))
|
|
genome_scores_blue[gid_b].append((food_b, food_r))
|
|
|
|
print(f"Nesil {generation}: {eval_count} eşleşme değerlendirildi.")
|
|
|
|
|
|
|
|
for gid, genome in genomes_red_dict.items():
|
|
scores = genome_scores_red[gid]
|
|
if not scores:
|
|
genome.fitness = 0.0
|
|
continue
|
|
avg_my_food = np.mean([s[0] for s in scores])
|
|
avg_opp_food = np.mean([s[1] for s in scores])
|
|
|
|
if s.FITNESS_METHOD == 'competitive':
|
|
genome.fitness = avg_my_food - avg_opp_food
|
|
else:
|
|
genome.fitness = avg_my_food
|
|
|
|
|
|
for gid, genome in genomes_blue_dict.items():
|
|
scores = genome_scores_blue[gid]
|
|
if not scores:
|
|
genome.fitness = 0.0
|
|
continue
|
|
avg_my_food = np.mean([s[0] for s in scores])
|
|
avg_opp_food = np.mean([s[1] for s in scores])
|
|
|
|
if s.FITNESS_METHOD == 'competitive':
|
|
genome.fitness = avg_my_food - avg_opp_food
|
|
else:
|
|
genome.fitness = avg_my_food
|
|
|
|
|
|
|
|
best_genome_red = max(genomes_red_dict.values(), key=lambda g: g.fitness)
|
|
best_genome_blue = max(genomes_blue_dict.values(), key=lambda g: g.fitness)
|
|
|
|
p_red.reporters.post_evaluate(config, genomes_red_dict, p_red.species, best_genome_red)
|
|
p_blue.reporters.post_evaluate(config, genomes_blue_dict, p_blue.species, best_genome_blue)
|
|
|
|
p_red.reporters.end_generation(config, genomes_red_dict, p_red.species)
|
|
p_blue.reporters.end_generation(config, genomes_blue_dict, p_blue.species)
|
|
|
|
|
|
p_red.population = p_red.reproduction.reproduce(config, p_red.species, config.pop_size, generation)
|
|
p_blue.population = p_blue.reproduction.reproduce(config, p_blue.species, config.pop_size, generation)
|
|
|
|
|
|
if not p_red.species or not p_blue.species:
|
|
p_red.species = config.species_set_type(config, p_red.reporters)
|
|
p_blue.species = config.species_set_type(config, p_blue.reporters)
|
|
p_red.species.speciate(config, p_red.population, generation)
|
|
p_blue.species.speciate(config, p_blue.population, generation)
|
|
|
|
|
|
p_red.reporters.start_generation(generation + 1)
|
|
p_blue.reporters.start_generation(generation + 1)
|
|
|
|
end_time = time.time()
|
|
print(f"Nesil {generation} tamamlandı. Süre: {end_time - start_time:.2f} saniye")
|
|
|
|
|
|
|
|
print('\nKo-Evrim tamamlandı.')
|
|
|
|
|
|
|
|
|
|
try:
|
|
winner_red = max(p_red.population.values(), key=lambda g: g.fitness if g.fitness is not None else -float('inf'))
|
|
winner_blue = max(p_blue.population.values(), key=lambda g: g.fitness if g.fitness is not None else -float('inf'))
|
|
|
|
print('\nEn İyi Kırmızı Genom:')
|
|
print(winner_red)
|
|
print('\nEn İyi Mavi Genom:')
|
|
print(winner_blue)
|
|
|
|
|
|
os.makedirs('swarm_mind_v4/best_genomes', exist_ok=True)
|
|
with open('swarm_mind_v4/best_genomes/winner_red.pkl', 'wb') as f:
|
|
pickle.dump(winner_red, f)
|
|
with open('swarm_mind_v4/best_genomes/winner_blue.pkl', 'wb') as f:
|
|
pickle.dump(winner_blue, f)
|
|
print("En iyi genomlar 'best_genomes' klasörüne kaydedildi.")
|
|
|
|
|
|
if s.VISUALIZE_BEST_GENOMES:
|
|
visualize_simulation(winner_red, config, winner_blue, config)
|
|
|
|
except Exception as e:
|
|
print(f"\nEvrim sonrası hata (En iyi genom bulunamadı veya kaydedilemedi): {e}")
|
|
|
|
|
|
|
|
def visualize_simulation(genome_red, config_red, genome_blue, config_blue):
|
|
"""
|
|
İki rakip genomun davranışını Pygame ile görselleştirir.
|
|
"""
|
|
print("\nEn iyi Kırmızı ve Mavi genomların maçı görselleştiriliyor...")
|
|
pygame.init()
|
|
screen = pygame.display.set_mode((s.SCREEN_WIDTH, s.SCREEN_HEIGHT))
|
|
pygame.display.set_caption(f"{s.WINDOW_TITLE} - Best Genomes Match")
|
|
clock = pygame.time.Clock()
|
|
|
|
environment = Environment(s.SCREEN_WIDTH, s.SCREEN_HEIGHT)
|
|
net_red = neat.nn.FeedForwardNetwork.create(genome_red, config_red)
|
|
net_blue = neat.nn.FeedForwardNetwork.create(genome_blue, config_blue)
|
|
agents_red = [AgentCoEv(genome_red, config_red, environment, s.COLONY_ID_RED) for _ in range(s.NUM_AGENTS_PER_COLONY)]
|
|
agents_blue = [AgentCoEv(genome_blue, config_blue, environment, s.COLONY_ID_BLUE) for _ in range(s.NUM_AGENTS_PER_COLONY)]
|
|
all_agents = agents_red + agents_blue
|
|
|
|
running = True
|
|
sim_step = 0
|
|
max_vis_steps = s.SIMULATION_STEPS_PER_GEN * 2
|
|
while running and sim_step < max_vis_steps:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT: running = False; break
|
|
if event.type == pygame.KEYDOWN:
|
|
if event.key == pygame.K_p: s.DEBUG_DRAW_PHEROMONES = not s.DEBUG_DRAW_PHEROMONES
|
|
if event.key == pygame.K_ESCAPE: running = False; break
|
|
if not running: break
|
|
|
|
environment.update()
|
|
random.shuffle(all_agents)
|
|
for agent in all_agents:
|
|
agent.update(all_agents)
|
|
|
|
screen.fill(s.COLOR_BACKGROUND)
|
|
environment.draw(screen)
|
|
for agent in all_agents:
|
|
agent.draw(screen)
|
|
|
|
|
|
font = pygame.font.SysFont(None, 24)
|
|
food_r = sum(a.food_collected_count for a in agents_red)
|
|
food_b = sum(a.food_collected_count for a in agents_blue)
|
|
info_text = font.render(f"Adım: {sim_step}/{max_vis_steps} | Kırmızı Yem: {food_r} | Mavi Yem: {food_b}", True, (255, 255, 255))
|
|
screen.blit(info_text, (10, 10))
|
|
|
|
pygame.display.flip()
|
|
clock.tick(s.VISUALIZATION_FPS)
|
|
sim_step += 1
|
|
|
|
pygame.quit()
|
|
print("Görselleştirme tamamlandı.")
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
local_dir = os.path.dirname(__file__)
|
|
config_path = os.path.join(local_dir, 'neat_config_v4.txt')
|
|
|
|
if not os.path.exists(config_path):
|
|
print(f"HATA: NEAT config dosyası bulunamadı: {config_path}")
|
|
sys.exit(1)
|
|
|
|
print("SwarmMind V4.0 - Co-evolutionary Competition başlatılıyor...")
|
|
print(f"NEAT Yapılandırması: {config_path}")
|
|
print(f"Jenerasyon Sayısı: {s.NUM_GENERATIONS}")
|
|
print(f"Popülasyon Büyüklüğü/Koloni: (config dosyasında belirtilir)")
|
|
print(f"Simülasyon Adım Sayısı/Eşleşme: {s.SIMULATION_STEPS_PER_GEN}")
|
|
print(f"Ajan Sayısı/Koloni: {s.NUM_AGENTS_PER_COLONY}")
|
|
print(f"Rakip Sayısı/Değerlendirme: {s.NUM_OPPONENTS_PER_EVAL}")
|
|
print(f"Fitness Yöntemi: {s.FITNESS_METHOD}")
|
|
|
|
|
|
os.makedirs('swarm_mind_v4/checkpoints_red', exist_ok=True)
|
|
os.makedirs('swarm_mind_v4/checkpoints_blue', exist_ok=True)
|
|
os.makedirs('swarm_mind_v4/best_genomes', exist_ok=True)
|
|
|
|
run_coev(config_path) |