diff --git a/AI_brain/genetic_algorytm.py b/AI_brain/genetic_algorytm.py index f8c3075..ef1ec04 100644 --- a/AI_brain/genetic_algorytm.py +++ b/AI_brain/genetic_algorytm.py @@ -1,6 +1,9 @@ +import copy import random import configparser import math + +import pygame from domain.entities.entity import Entity @@ -9,6 +12,7 @@ config.read("config.ini") from domain.world import World from AI_brain.rotate_and_go_aStar import RotateAndGoAStar, State +from random import randint hits = 0 @@ -44,9 +48,7 @@ class Path: permutation = generate_random_permutation(len(dusts)) self.permutation = permutation - self.walk = addStartAndStation( - permutation, config.getint("CONSTANT", "BananaFilling") - ) + self.walk = addStartAndStation(permutation) def calculate_distance(self, world: World): distance = 0 @@ -145,8 +147,8 @@ def generate_random_permutation(n): # BUG solution: inverse direction at the last step -def addStartAndStation(permutation: list[int], bananaFilling: int): - frequency = math.ceil(100 / bananaFilling) +def addStartAndStation(permutation: list[int]): + frequency = math.ceil(100 / config.getint("CONSTANT", "BananaFilling")) numer_of_stops = math.ceil(len(permutation) / frequency) walk = permutation.copy() @@ -186,6 +188,16 @@ class GeneticAlgorytm: path.calculate_distance(self.world) self.paths.append(path) + def print_top(self): + print( + "Best path: ", + self.best_path.walk, + "Distance: ", + self.best_path.distance, + ) + for path in self.paths[1:]: + print(path.walk, path.distance) + def evaluate_population(self): self.paths.sort(key=lambda x: x.distance, reverse=False) @@ -207,9 +219,7 @@ class GeneticAlgorytm: if item not in child.permutation: child.permutation.append(item) - child.walk = addStartAndStation( - child.permutation, config.getint("CONSTANT", "BananaFilling") - ) + child.walk = addStartAndStation(child.permutation) child.calculate_distance(self.world) @@ -220,7 +230,6 @@ class GeneticAlgorytm: for i in range(self.iteration_number): self.crossover() - # self.mutate() self.evaluate_population() self.best_real_path = self.paths[0].get_real_path(self.world) @@ -229,6 +238,25 @@ class GeneticAlgorytm: print(hits / (misses + hits)) + def mutate(self, mutant: Path) -> Path: + random_number = randint(0, len(mutant.permutation) - 1) + random_number2 = random_number + while random_number == random_number2: + random_number2 = randint(0, len(mutant.permutation) - 1) + + mutant.permutation[random_number], mutant.permutation[random_number2] = ( + mutant.permutation[random_number2], + mutant.permutation[random_number], + ) + + if tuple(mutant.permutation) in self.checked_permutations: + return self.mutate(mutant) + + mutant.walk = addStartAndStation(mutant.permutation) + + mutant.calculate_distance(self.world) + return mutant + def crossover(self): for i in range(self.descendants_number): parent1 = self.paths[random.randint(0, self.population_size - 1)] @@ -244,4 +272,10 @@ class GeneticAlgorytm: self.checked_permutations[tuple(child.permutation)] = True self.paths.append(child) + mutant = Path() + mutant.permutation = child.permutation.copy() + mutant = self.mutate(mutant) + self.checked_permutations[tuple(mutant.permutation)] = True + self.paths.append(mutant) + self.evaluate_population() diff --git a/config.ini b/config.ini index 366c466..3300dc8 100644 --- a/config.ini +++ b/config.ini @@ -4,12 +4,12 @@ movement = robot #accept: human, robot [CONSTANT] -NumberOfBananas = 5 -NumberOfEarrings = 3 +NumberOfBananas = 15 +NumberOfEarrings = 0 NumberOfPlants = 5 BananaFilling = 25 -RobotStartPosition = 1, 1 -DockStationStartPosition = 9, 8 +RobotStartPosition = 5, 5 +DockStationStartPosition = 5, 6 #9,8 [NEURAL_NETWORK] @@ -21,6 +21,6 @@ mode = full_clean [GENETIC_ALGORITHM] PopulationSize = 20 -DescendantsNumber = 5 -MutationProbability = 0.1 -IterationNumber = 100 +DescendantsNumber = 6 +MutationProbability = 0.3 +IterationNumber = 1_000 diff --git a/domain/commands/vacuum_move_command.py b/domain/commands/vacuum_move_command.py index d72b327..f485b12 100644 --- a/domain/commands/vacuum_move_command.py +++ b/domain/commands/vacuum_move_command.py @@ -27,6 +27,7 @@ class VacuumMoveCommand(Command): if self.vacuum.get_container_filling() < 100: self.vacuum.increase_container_filling() self.world.delete_entities_at_Of_type(item.x, item.y, item.type) + self.world.dust[end_x][end_y].remove(item) if self.world.is_docking_station_at(end_x, end_y): self.vacuum.dump_trash() diff --git a/main.py b/main.py index 44ff3db..0a4c6ae 100644 --- a/main.py +++ b/main.py @@ -70,11 +70,7 @@ class Main: genetic_searcher = GeneticAlgorytm(self.world) genetic_searcher.run() - print( - str(genetic_searcher.best_path.walk) - + ": " - + str(genetic_searcher.best_distance) - ) + genetic_searcher.print_top() robot_actions = genetic_searcher.best_path.real_path @@ -190,9 +186,15 @@ def generate_world(tiles_x: int, tiles_y: int) -> World: world.add_entity(Entity(9, 3, "PLANT3")) numberOfEarrings = config.getint("CONSTANT", "NumberOfEarrings") - world.add_entity(Earring(9, 7)) - world.add_entity(Earring(5, 5)) - world.add_entity(Earring(4, 6)) + for _ in range(numberOfEarrings): + temp_x = randint(0, tiles_x - 1) + temp_y = randint(0, tiles_y - 1) + + while world.is_entity_at(temp_x, temp_y): + temp_x = randint(0, tiles_x - 1) + temp_y = randint(0, tiles_y - 1) + + world.add_entity(Earring(temp_x, temp_y)) for _ in range(config.getint("CONSTANT", "NumberOfBananas")): temp_x = randint(0, tiles_x - 1) @@ -248,7 +250,7 @@ def generate_world(tiles_x: int, tiles_y: int) -> World: if world.garbage_at(x, y): world.costs[x][y] = 1 else: - world.costs[x][y] = 10 + world.costs[x][y] = 2 return world