164 lines
4.8 KiB
Python
164 lines
4.8 KiB
Python
import numpy as np
|
|
import pygame
|
|
import tiles
|
|
|
|
#Parameters for genetic algorithm
|
|
n_trashes = tiles.howManyMesses
|
|
n_population = 100
|
|
mutation_rate = 0.5
|
|
listDraft = []
|
|
|
|
#Some settings for the whole project window
|
|
pygame.display.set_caption('Inteligentny Kelner - projekt SI 2022')
|
|
Icon = pygame.image.load('waiter.png')
|
|
pygame.display.set_icon(Icon)
|
|
|
|
#Take data from tiles.py
|
|
for i in range(len(tiles.messesArray)):
|
|
# Generating a list of coordinates representing each trash
|
|
coordinates_list = [[x*32,y*32] for x,y in tiles.messesArray]
|
|
listDraft.append(tiles.coordsToNum(coordinates_list[i]))
|
|
|
|
#Add some data
|
|
names_list = np.array(listDraft)
|
|
trashes_dict = {x:y for x, y in zip(names_list, coordinates_list)}
|
|
|
|
#Testing:
|
|
#print(trashes_dict)
|
|
|
|
#Function computing the distance between two points by its coordinates
|
|
def compute_trash_distance_coordinates(a, b):
|
|
return ((a[0]-b[0])**2+(a[1]-b[1])**2)**0.5
|
|
|
|
def compute_trash_distance_numbers(trash_a, trash_b, trash_dict):
|
|
return compute_trash_distance_coordinates(trash_dict[trash_a], trash_dict[trash_b])
|
|
|
|
#First step is to create the first population set
|
|
def genesis(trash_list, n_population):
|
|
|
|
population_set = []
|
|
for i in range(n_population):
|
|
#Randomly generated new solution
|
|
sol_i = trash_list[np.random.choice(list(range(n_trashes)), n_trashes, replace=False)]
|
|
population_set.append(sol_i)
|
|
return np.array(population_set)
|
|
|
|
population_set = genesis(names_list, n_population)
|
|
#Testing
|
|
#print(population_set)
|
|
|
|
|
|
def fitness_eval(trash_list, trash_dict):
|
|
total = 0
|
|
for i in range(n_trashes - 1):
|
|
a = trash_list[i]
|
|
b = trash_list[i + 1]
|
|
total += compute_trash_distance_numbers(a, b, trash_dict)
|
|
return total
|
|
|
|
|
|
def get_all_fitnes(population_set, trash_dict):
|
|
fitnes_list = np.zeros(n_population)
|
|
|
|
#Looping over all solutions computing the fitness for each solution
|
|
for i in range(n_population):
|
|
fitnes_list[i] = fitness_eval(population_set[i], trash_dict)
|
|
|
|
return fitnes_list
|
|
|
|
fitnes_list = get_all_fitnes(population_set, trashes_dict)
|
|
#Testing
|
|
#print(fitnes_list)
|
|
|
|
|
|
def ancestors_choose(population_set, fitnes_list):
|
|
total_fit = fitnes_list.sum()
|
|
prob_list = fitnes_list / total_fit
|
|
pop_len = len(population_set)
|
|
ancestor_list_a = np.random.choice(list(range(pop_len)), pop_len, p=prob_list, replace=True)
|
|
ancestor_list_b = np.random.choice(list(range(pop_len)), pop_len, p=prob_list, replace=True)
|
|
|
|
ancestor_list_a = population_set[ancestor_list_a]
|
|
ancestor_list_b = population_set[ancestor_list_b]
|
|
|
|
return np.array([ancestor_list_a, ancestor_list_b])
|
|
|
|
|
|
ancestor_list = ancestors_choose(population_set, fitnes_list)
|
|
#print(ancestor_list[0][2])
|
|
|
|
|
|
def mate_ancestors(prog_a, prog_b):
|
|
offspring = prog_a[0:5]
|
|
|
|
for trash in prog_b:
|
|
if not trash in offspring:
|
|
offspring = np.concatenate((offspring, [trash]))
|
|
|
|
return offspring
|
|
|
|
|
|
def mate_population(progenitor_list):
|
|
new_population_set = []
|
|
for i in range(progenitor_list.shape[1]):
|
|
prog_a, prog_b = progenitor_list[0][i], progenitor_list[1][i]
|
|
offspring = mate_ancestors(prog_a, prog_b)
|
|
new_population_set.append(offspring)
|
|
|
|
return new_population_set
|
|
|
|
new_population_set = mate_population(ancestor_list)
|
|
#print(new_population_set[0])
|
|
|
|
|
|
def mutate_offspring(offspring):
|
|
for q in range(int(n_trashes * mutation_rate)):
|
|
a = np.random.randint(0, n_trashes)
|
|
b = np.random.randint(0, n_trashes)
|
|
|
|
offspring[a], offspring[b] = offspring[b], offspring[a]
|
|
|
|
return offspring
|
|
|
|
|
|
def mutate_population(new_population_set):
|
|
mutated_pop = []
|
|
for offspring in new_population_set:
|
|
mutated_pop.append(mutate_offspring(offspring))
|
|
return mutated_pop
|
|
|
|
|
|
mutated_pop = mutate_population(new_population_set)
|
|
#print(mutated_pop[0])
|
|
|
|
best_solution = [-1, np.inf, np.array([])]
|
|
for i in range(1001):
|
|
#What I put here: iteration number, minimal fitness value, average fitness value
|
|
if i % 100 == 0: print(i, fitnes_list.min(), fitnes_list.mean())
|
|
fitnes_list = get_all_fitnes(mutated_pop, trashes_dict)
|
|
|
|
#Saving the best solution
|
|
if fitnes_list.min() < best_solution[1]:
|
|
best_solution[0] = i
|
|
best_solution[1] = fitnes_list.min()
|
|
best_solution[2] = np.array(mutated_pop)[fitnes_list.min() == fitnes_list]
|
|
|
|
ancestor_list = ancestors_choose(population_set, fitnes_list)
|
|
new_population_set = mate_population(ancestor_list)
|
|
|
|
mutated_pop = mutate_population(new_population_set)
|
|
trashesList = []
|
|
|
|
for i in range(len(best_solution[2][0])):
|
|
trashesList.append(0)
|
|
|
|
for i in range(len(best_solution[2][0])):
|
|
trashesList[i] = best_solution[2][0][i]
|
|
|
|
#Prints some specs to recreate if needed
|
|
print(trashesList)
|
|
print(tiles.messesArray)
|
|
|
|
#Pass solution to draw
|
|
tiles.main(trashesList)
|