Merge pull request 'Created genetic algorithm. Added returned matrix of genetic algorithm into settings file. Replaced fields with map generated by algorithm.' (#14) from genetic_algorithm into main
Reviewed-on: s473634/TurboTraktor#14
This commit is contained in:
commit
6cba5133a3
BIN
genetic_algorithm_matrix.pkl
Normal file
BIN
genetic_algorithm_matrix.pkl
Normal file
Binary file not shown.
3
main.py
3
main.py
@ -1,7 +1,7 @@
|
|||||||
import pygame
|
import pygame
|
||||||
import sys
|
import sys
|
||||||
import random
|
import random
|
||||||
from settings import SIZE, directions, draw_lines_on_window
|
from settings import SIZE, directions, draw_lines_on_window, matrix_plants_type
|
||||||
from src.map import drawRoads, seedForFirstTime, return_fields_list, WORLD_MATRIX, get_type_by_position
|
from src.map import drawRoads, seedForFirstTime, return_fields_list, WORLD_MATRIX, get_type_by_position
|
||||||
from src.Tractor import Tractor
|
from src.Tractor import Tractor
|
||||||
from src.bfs import Astar
|
from src.bfs import Astar
|
||||||
@ -45,6 +45,7 @@ def recognize_plants(fields, destination):
|
|||||||
print(pred)
|
print(pred)
|
||||||
return pred
|
return pred
|
||||||
|
|
||||||
|
|
||||||
# pygame initialization
|
# pygame initialization
|
||||||
pygame.init()
|
pygame.init()
|
||||||
clock = pygame.time.Clock()
|
clock = pygame.time.Clock()
|
||||||
|
10
settings.py
10
settings.py
@ -1,6 +1,11 @@
|
|||||||
from cmath import sqrt
|
from cmath import sqrt
|
||||||
import pygame
|
import pygame
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
def load_matrix(filename):
|
||||||
|
with open(filename, 'rb') as file:
|
||||||
|
matrix = pickle.load(file)
|
||||||
|
return matrix
|
||||||
|
|
||||||
screen_width = 1368
|
screen_width = 1368
|
||||||
screen_height = 936
|
screen_height = 936
|
||||||
@ -18,6 +23,7 @@ field_width = 4
|
|||||||
field_height = 4
|
field_height = 4
|
||||||
field_size = field_width*field_height
|
field_size = field_width*field_height
|
||||||
fields_amount = 25
|
fields_amount = 25
|
||||||
|
matrix_plants_type = load_matrix("genetic_algorithm_matrix.pkl")
|
||||||
|
|
||||||
directions = {0: 'UP', 90: 'RIGHT', 180: 'DOWN', 270: 'LEFT'}
|
directions = {0: 'UP', 90: 'RIGHT', 180: 'DOWN', 270: 'LEFT'}
|
||||||
|
|
||||||
@ -29,4 +35,6 @@ def draw_lines_on_window(background):
|
|||||||
pygame.draw.line(background, (0, 0, 0), (968, 285), (1336 , 285))
|
pygame.draw.line(background, (0, 0, 0), (968, 285), (1336 , 285))
|
||||||
pygame.draw.line(background, (0, 0, 0), (968, 649), (1336 , 649))
|
pygame.draw.line(background, (0, 0, 0), (968, 649), (1336 , 649))
|
||||||
pygame.draw.line(background, (0, 0, 0), (968, 285), (968, 649))
|
pygame.draw.line(background, (0, 0, 0), (968, 285), (968, 649))
|
||||||
pygame.draw.line(background, (0, 0, 0), (1336, 285), (1336, 649))
|
pygame.draw.line(background, (0, 0, 0), (1336, 285), (1336, 649))
|
||||||
|
|
||||||
|
|
||||||
|
161
src/genetic_algorithm.py
Normal file
161
src/genetic_algorithm.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import random
|
||||||
|
import copy
|
||||||
|
import pickle
|
||||||
|
import numpy
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
GRID_SIZE = 5
|
||||||
|
PLANT_TYPES = [1, 2, 3]
|
||||||
|
POPULATION_SIZE = 1000
|
||||||
|
MAX_GENERATIONS = 100
|
||||||
|
MUTATION_RATE = 0.1
|
||||||
|
|
||||||
|
def generate_random_chromosome():
|
||||||
|
# Generate a random chromosome (random matrix)
|
||||||
|
chromosome = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]
|
||||||
|
|
||||||
|
for row in range(GRID_SIZE):
|
||||||
|
for col in range(GRID_SIZE):
|
||||||
|
available_types = PLANT_TYPES.copy()
|
||||||
|
chromosome[row][col] = random.choice(available_types)
|
||||||
|
|
||||||
|
return chromosome
|
||||||
|
|
||||||
|
def calculate_fitness(chromosome):
|
||||||
|
# Calculate the fitness by counting the number of adjacent fields with the same plant type
|
||||||
|
fitness = 0
|
||||||
|
appearances = [0,0,0]
|
||||||
|
|
||||||
|
for row in range(GRID_SIZE):
|
||||||
|
for col in range(GRID_SIZE):
|
||||||
|
plant_type = chromosome[row][col]
|
||||||
|
|
||||||
|
# Check left neighbor
|
||||||
|
if col > 0 and chromosome[row][col - 1] == plant_type:
|
||||||
|
fitness += 1
|
||||||
|
# Check top neighbor
|
||||||
|
if row > 0 and chromosome[row - 1][col] == plant_type:
|
||||||
|
fitness += 1
|
||||||
|
|
||||||
|
|
||||||
|
for row in chromosome:
|
||||||
|
appearances[0] = appearances[0] + row.count(1)
|
||||||
|
appearances[1] = appearances[1] + row.count(2)
|
||||||
|
appearances[2] = appearances[2] + row.count(3)
|
||||||
|
|
||||||
|
for i in range(len(appearances)):
|
||||||
|
if appearances[i] < 7 and appearances[i] > 9:
|
||||||
|
fitness = fitness + abs(appearances[i]-8)
|
||||||
|
return fitness
|
||||||
|
|
||||||
|
def selection(population):
|
||||||
|
# Perform tournament selection to choose parents for reproduction
|
||||||
|
tournament_size = 5
|
||||||
|
parents = []
|
||||||
|
|
||||||
|
for _ in range(len(population)):
|
||||||
|
tournament = random.sample(population, tournament_size)
|
||||||
|
tournament.sort(key=lambda chromosome: calculate_fitness(chromosome))
|
||||||
|
parents.append(tournament[0])
|
||||||
|
|
||||||
|
return parents
|
||||||
|
|
||||||
|
def crossover(parent1, parent2):
|
||||||
|
# Perform single-point crossover to create two offspring
|
||||||
|
crossover_point = random.randint(0, (GRID_SIZE*GRID_SIZE)-1)
|
||||||
|
|
||||||
|
row = crossover_point // GRID_SIZE
|
||||||
|
column = crossover_point % GRID_SIZE
|
||||||
|
offspring1 = []
|
||||||
|
offspring2 = []
|
||||||
|
counter = 0
|
||||||
|
while counter<row:
|
||||||
|
offspring1.append(parent1[counter])
|
||||||
|
offspring2.append(parent2[counter])
|
||||||
|
counter += 1
|
||||||
|
# The place, where the parents are 'cutten' is here
|
||||||
|
offspring1.append(parent1[counter][:column] + parent2[counter][column:])
|
||||||
|
offspring2.append(parent2[counter][:column] + parent1[counter][column:])
|
||||||
|
|
||||||
|
while counter<GRID_SIZE-1:
|
||||||
|
offspring1.append(parent2[counter])
|
||||||
|
offspring2.append(parent1[counter])
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
return offspring1, offspring2
|
||||||
|
|
||||||
|
|
||||||
|
def genetic_algorithm():
|
||||||
|
|
||||||
|
results = []
|
||||||
|
population = [generate_random_chromosome() for _ in range(POPULATION_SIZE)]
|
||||||
|
|
||||||
|
# Main loop
|
||||||
|
for gen in range(MAX_GENERATIONS):
|
||||||
|
parents = selection(population)
|
||||||
|
offspring = []
|
||||||
|
|
||||||
|
# Crossover
|
||||||
|
for i in range(0, len(parents), 2):
|
||||||
|
parent1 = parents[i]
|
||||||
|
parent2 = parents[i + 1]
|
||||||
|
child1, child2 = crossover(parent1, parent2)
|
||||||
|
offspring.append(child1)
|
||||||
|
offspring.append(child2)
|
||||||
|
|
||||||
|
# Replacement
|
||||||
|
population = offspring
|
||||||
|
|
||||||
|
# Count best fitness of each population
|
||||||
|
best_chromosome = min(population, key=lambda chromosome: calculate_fitness(chromosome))
|
||||||
|
best_fitness = calculate_fitness(best_chromosome)
|
||||||
|
results.append((copy.deepcopy(best_chromosome), best_fitness))
|
||||||
|
if best_fitness == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
results.sort(key = lambda x: x[1])
|
||||||
|
best_tuple = results[0]
|
||||||
|
best_chromosome, best_fitness = best_tuple
|
||||||
|
return best_chromosome
|
||||||
|
|
||||||
|
# Replacing numbers into plants:
|
||||||
|
def replace_numbers(number_matrix):
|
||||||
|
return_matrix = number_matrix.copy()
|
||||||
|
for row in range(GRID_SIZE):
|
||||||
|
for col in range(GRID_SIZE):
|
||||||
|
if number_matrix[row][col] == 1:
|
||||||
|
return_matrix[row][col] = "carrot"
|
||||||
|
elif number_matrix[row][col] == 2:
|
||||||
|
return_matrix[row][col] = "potato"
|
||||||
|
elif number_matrix[row][col] == 3:
|
||||||
|
return_matrix[row][col] = "wheat"
|
||||||
|
else:
|
||||||
|
number_matrix[row][col] = "error"
|
||||||
|
return return_matrix
|
||||||
|
|
||||||
|
# Make the matrix as a list:
|
||||||
|
def list_of_matrix(plant_matrix):
|
||||||
|
return_list = []
|
||||||
|
for i in range(len(plant_matrix)):
|
||||||
|
return_list += plant_matrix[i]
|
||||||
|
return return_list
|
||||||
|
|
||||||
|
# Run the genetic algorithm
|
||||||
|
best_solution = genetic_algorithm()
|
||||||
|
|
||||||
|
# Print the best solution found
|
||||||
|
print("Best Solution:")
|
||||||
|
for row in best_solution:
|
||||||
|
print(row)
|
||||||
|
print("Best fitness: ", calculate_fitness(best_solution))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
replaced_matrix = replace_numbers(best_solution)
|
||||||
|
print("Replaced Matrix:")
|
||||||
|
for row in replaced_matrix:
|
||||||
|
print(row)
|
||||||
|
return_list = list_of_matrix(replaced_matrix)
|
||||||
|
|
||||||
|
|
||||||
|
with open("genetic_algorithm_matrix.pkl", "wb") as file:
|
||||||
|
pickle.dump(return_list, file)
|
@ -1,6 +1,6 @@
|
|||||||
from cmath import sqrt
|
from cmath import sqrt
|
||||||
import pygame
|
import pygame
|
||||||
from settings import screen_height, screen_width, SIZE, SPECIES, block_size, tile, road_coords, fields_amount, field_size, field_height, field_width
|
from settings import screen_height, screen_width, SIZE, SPECIES, block_size, tile, road_coords, fields_amount, field_size, field_height, field_width, matrix_plants_type
|
||||||
from src.Plant import Plant
|
from src.Plant import Plant
|
||||||
import random
|
import random
|
||||||
from src.Field import Field
|
from src.Field import Field
|
||||||
@ -60,9 +60,11 @@ def drawRoads(screen):
|
|||||||
return screen
|
return screen
|
||||||
|
|
||||||
def seedForFirstTime():
|
def seedForFirstTime():
|
||||||
|
plants_type = matrix_plants_type
|
||||||
|
|
||||||
plant_group = pygame.sprite.Group()
|
plant_group = pygame.sprite.Group()
|
||||||
for field in range(fields_amount):
|
for field in range(fields_amount):
|
||||||
plant_name = random.choice(SPECIES)
|
plant_name = matrix_plants_type[field]
|
||||||
blocks_seeded_in_field = 0
|
blocks_seeded_in_field = 0
|
||||||
while (blocks_seeded_in_field < field_size):
|
while (blocks_seeded_in_field < field_size):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user