diff --git a/.gitignore b/.gitignore index 4932e41..b25a44d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ __pycache__ #PyCharm -.idea/ \ No newline at end of file +.idea/ +AI_brain/model.h5 diff --git a/AI_brain/genetic_algorytm.py b/AI_brain/genetic_algorytm.py new file mode 100644 index 0000000..ef1ec04 --- /dev/null +++ b/AI_brain/genetic_algorytm.py @@ -0,0 +1,281 @@ +import copy +import random +import configparser +import math + +import pygame +from domain.entities.entity import Entity + + +config = configparser.ConfigParser() +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 +misses = 0 + + +class Cashed_sub_paths(dict): + def __init__(self): + super().__init__() + + def __missing__(self, key): + self[key] = Cashed_sub_paths() + return self[key] + + +class Cashed_sub_path: + def __init__(self, sub_path: list[str] = [], distance: int = 0): + self.sub_path = sub_path + self.distance = distance + + +steps_distance_cashed: dict[tuple[int, int], Cashed_sub_path] = Cashed_sub_paths() + + +class Path: + def __init__(self): + self.walk = [] + self.permutation = [] + self.real_path = [] + self.distance = 0 + + def random_walk(self, dusts: list[Entity]): + permutation = generate_random_permutation(len(dusts)) + self.permutation = permutation + + self.walk = addStartAndStation(permutation) + + def calculate_distance(self, world: World): + distance = 0 + for i in range(len(self.walk) - 1): + next_distance, next_real_path = self.step_distance( + self.walk[i], self.walk[i + 1], world + ) + distance += next_distance + + # BUG this part is not working and is not used, B.1 must be resolved + self.real_path = self.real_path + ["DEFAULT_ROTATION"] + next_real_path + + self.distance = distance + + def step_distance( + self, from_id: int, to_id: int, world: World + ) -> tuple[int, list[str]]: + global hits, misses + if (from_id, to_id) in steps_distance_cashed: + hits += 1 + distance = steps_distance_cashed[(from_id, to_id)].distance + sub_path = steps_distance_cashed[(from_id, to_id)].sub_path + return distance, sub_path + + misses += 1 + path_searcher = RotateAndGoAStar( + world, + self.getPosition(from_id, world.dustList), + self.getPosition(to_id, world.dustList), + ) + path_searcher.search() + + steps_distance_cashed[(from_id, to_id)] = Cashed_sub_path( + path_searcher.actions, path_searcher.cost + ) + + # BUG B.1 inverse path + inverse_sub_path = path_searcher.actions.copy() + steps_distance_cashed[(to_id, from_id)] = Cashed_sub_path( + inverse_sub_path, path_searcher.cost + ) + return path_searcher.cost, path_searcher.actions + + def inverse_sub_path(sub_path: list[str]) -> list[str]: + sub_path.reverse() + for command in sub_path: + command.replace("RL", "RR") + command.replace("RR", "RR") + + def getPosition( + self, + number: int, + dustList: list[Entity], + ) -> State: + if number == -1: + dock_start_x, dock_start_y = config.get( + "CONSTANT", "DockStationStartPosition" + ).split(",") + dock_start_x, dock_start_y = int(dock_start_x), int(dock_start_y) + + return State(dock_start_x, dock_start_y) + + if number == -2: + vacuum_start_x, vacuum_start_y = config.get( + "CONSTANT", "RobotStartPosition" + ).split(",") + + vacuum_start_x, vacuum_start_y = int(vacuum_start_x), int(vacuum_start_y) + return State(vacuum_start_x, vacuum_start_y) + + return State(dustList[number].x, dustList[number].y) + + def get_real_path(self, world: World): + full_path = [] + + for index_place in range(len(self.walk) - 1): + path_searcher = RotateAndGoAStar( + world, + self.getPosition(self.walk[index_place], world.dustList), + self.getPosition(self.walk[index_place + 1], world.dustList), + ) + path_searcher.search() + full_path = full_path + ["DEFAULT_ROTATION"] + path_searcher.actions + + self.real_path = full_path + + +def generate_random_permutation(n): + # Create a list of numbers from 1 to n + numbers = list(range(0, n)) + + # Shuffle the list using the random.shuffle function + random.shuffle(numbers) + + return numbers + + +# BUG solution: inverse direction at the last step +def addStartAndStation(permutation: list[int]): + frequency = math.ceil(100 / config.getint("CONSTANT", "BananaFilling")) + numer_of_stops = math.ceil(len(permutation) / frequency) + walk = permutation.copy() + + for i in range(1, numer_of_stops): + walk.insert((frequency + 1) * i - 1, -1) + walk.insert(len(walk), -1) + walk.insert(0, -2) + + return walk + + +class GeneticAlgorytm: + def __init__(self, world: World): + self.world = world + self.population_size = config.getint("GENETIC_ALGORITHM", "PopulationSize") + self.mutation_probability = config.getfloat( + "GENETIC_ALGORITHM", "MutationProbability" + ) + self.iteration_number = config.getint("GENETIC_ALGORITHM", "IterationNumber") + self.descendants_number = config.getint( + "GENETIC_ALGORITHM", "DescendantsNumber" + ) + self.dusts = world.dustList + self.doc_station = world.doc_station + self.paths: list[Path] = [] + self.checked_permutations = {} + + self.best_path = None + self.best_distance = math.inf + self.best_real_path = [] + + def generate_population(self): + for i in range(self.population_size): + path = Path() + path.random_walk(self.dusts) + self.checked_permutations[tuple(path.permutation)] = True + 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) + + self.best_distance = self.paths[0].distance + self.best_path = self.paths[0] + + for path in self.paths[self.population_size :]: + del self.checked_permutations[tuple(path.permutation)] + + self.paths = self.paths[: self.population_size] + + def create_child(self, parent1: Path, parent2: Path) -> Path: + child = Path() + + child.permutation = parent1.permutation[: len(parent1.permutation) // 2] + + # Add missing items from parent2 in the order they appear + for item in parent2.permutation: + if item not in child.permutation: + child.permutation.append(item) + + child.walk = addStartAndStation(child.permutation) + + child.calculate_distance(self.world) + + return child + + def run(self): + self.generate_population() + + for i in range(self.iteration_number): + self.crossover() + + self.evaluate_population() + self.best_real_path = self.paths[0].get_real_path(self.world) + + print(hits, (misses + hits)) + + 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)] + + parent2 = self.paths[random.randint(0, self.population_size - 1)] + + child = self.create_child(parent1, parent2) + while tuple(child.permutation) in self.checked_permutations: + parent1 = self.paths[random.randint(0, self.population_size - 1)] + parent2 = self.paths[random.randint(0, self.population_size - 1)] + child = self.create_child(parent1, parent2) + + 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/AI_brain/image_recognition.py b/AI_brain/image_recognition.py index 47f766f..99bf249 100644 --- a/AI_brain/image_recognition.py +++ b/AI_brain/image_recognition.py @@ -5,18 +5,19 @@ from tensorflow import keras import cv2 import random -#You can download model from https://uam-my.sharepoint.com/:f:/g/personal/pavbia_st_amu_edu_pl/EmBHjnETuk5LiCZS6xk7AnIBNsnffR3Sygf8EX2bhR1w4A -#Change the path to model + to datasets (string 12 + strings 35,41,47,53) +# You can download model from https://uam-my.sharepoint.com/:f:/g/personal/pavbia_st_amu_edu_pl/EmBHjnETuk5LiCZS6xk7AnIBNsnffR3Sygf8EX2bhR1w4A +# Change the path to model + to datasets (string 12 + strings 35,41,47,53) + class VacuumRecognizer: - model = keras.models.load_model('AI_brain\model.h5') #Neuron model path + model = keras.models.load_model("AI_brain\model.h5") # Neuron model path def recognize(self, image_path) -> str: - class_names = ['Banana', 'Cat', 'Earings', 'Plant'] + class_names = ["Banana", "Cat", "Earings", "Plant"] img = cv2.imread(image_path, flags=cv2.IMREAD_GRAYSCALE) cv2.waitKey(0) - img = (np.expand_dims(img, 0)) + img = np.expand_dims(img, 0) predictions = self.model.predict(img)[0].tolist() @@ -31,31 +32,43 @@ class VacuumRecognizer: return class_names[predictions.index(max(predictions))] def get_random_dir(self, type) -> str: - if type == 'Plant': - plant_image_paths = 'C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Plant' #Plant dataset path + if type == "Plant": + plant_image_paths = "C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Plant" # Plant dataset path plant_dirs = os.listdir(plant_image_paths) - full_path = plant_image_paths + '\\' + plant_dirs[random.randint(0, len(plant_dirs)-1)] + full_path = ( + plant_image_paths + + "\\" + + plant_dirs[random.randint(0, len(plant_dirs) - 1)] + ) print(full_path) return full_path - elif type == 'Earings': - earnings_image_paths = 'C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Earings' #Earings dataset path + elif type == "Earings": + earnings_image_paths = "C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Earings" # Earings dataset path earning_dirs = os.listdir(earnings_image_paths) - full_path = earnings_image_paths + '\\' + earning_dirs[random.randint(0, len(earning_dirs)-1)] + full_path = ( + earnings_image_paths + + "\\" + + earning_dirs[random.randint(0, len(earning_dirs) - 1)] + ) print(full_path) return full_path - elif type == 'Banana': - banana_image_paths = 'C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Banana' #Banana dataset path + elif type == "Banana": + banana_image_paths = "C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Banana" # Banana dataset path banana_dirs = os.listdir(banana_image_paths) - full_path = banana_image_paths + '\\' + banana_dirs[random.randint(0, len(banana_dirs)-1)] + full_path = ( + banana_image_paths + + "\\" + + banana_dirs[random.randint(0, len(banana_dirs) - 1)] + ) print(full_path) return full_path - elif type == 'Cat': - cat_image_paths = 'C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Cat' #Cat dataset path + elif type == "Cat": + cat_image_paths = "C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Cat" # Cat dataset path cat_dir = os.listdir(cat_image_paths) -#For testing the neuron model -'''image_paths = [] +# For testing the neuron model +"""image_paths = [] image_paths.append('C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Banana') image_paths.append('C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Cat') image_paths.append('C:\\Users\\Pavel\\Desktop\\AI\\Machine_learning_2023\\AI_brain\\Image_datasetJPGnewBnW\\check\\Earings') @@ -65,4 +78,4 @@ uio = VacuumRecognizer() for image_path in image_paths: dirs = os.listdir(image_path) for i in range(3): - print(uio.recognize(image_path + '\\' + dirs[random.randint(0, len(dirs)-1)]))''' \ No newline at end of file + print(uio.recognize(image_path + '\\' + dirs[random.randint(0, len(dirs)-1)]))""" diff --git a/AI_brain/rotate_and_go_aStar.py b/AI_brain/rotate_and_go_aStar.py index 3550c10..a3f7eb6 100644 --- a/AI_brain/rotate_and_go_aStar.py +++ b/AI_brain/rotate_and_go_aStar.py @@ -3,11 +3,10 @@ from domain.world import World class State: - def __init__(self, x, y, direction=(1, 0), entity=None): + def __init__(self, x: int, y: int, direction=(1, 0), entity=None): self.x = x self.y = y self.direction = direction - def __hash__(self): return hash((self.x, self.y)) @@ -19,7 +18,7 @@ class State: and self.direction == other.direction ) - def heuristic(self, goal_state): + def heuristic(self, goal_state) -> int: return abs(self.x - goal_state.x) + abs(self.y - goal_state.y) @@ -53,19 +52,19 @@ class RotateAndGoAStar: self.enqueued_states = set() self.explored = set() self.actions = [] + self.cost = 0 - def get_g_score(self, state): + def get_g_score(self, state) -> int: return self.world.get_cost(state.x, state.y) def search(self): - heapq.heappush( - self.fringe, Node(self.start_state, 0, self.goal_state) - ) + heapq.heappush(self.fringe, Node(self.start_state, 0, self.goal_state)) while self.fringe: - elem = heapq.heappop(self.fringe) + elem: Node = heapq.heappop(self.fringe) if self.is_goal(elem.state): self.actions = action_sequence(elem) + self.cost = elem.g_score return True self.explored.add(elem.state) @@ -73,7 +72,7 @@ class RotateAndGoAStar: if state in self.explored: continue - new_g_score = new_g_score = elem.g_score + self.world.get_cost(state.x, state.y) + new_g_score = elem.g_score + self.world.get_cost(state.x, state.y) if state not in self.enqueued_states: next_node = Node(state, new_g_score, self.goal_state) next_node.action = action @@ -84,12 +83,12 @@ class RotateAndGoAStar: for node in self.fringe: if node.state == state: node.g_score = new_g_score - node.f_score = ( - new_g_score + node.state.heuristic(self.goal_state) + node.f_score = new_g_score + node.state.heuristic( + self.goal_state ) node.parent = elem node.action = action - heapq.heapify(self.fringe) + heapq.heapify(self.fringe) break return False @@ -102,12 +101,12 @@ class RotateAndGoAStar: next_x = state.x + state.direction[0] next_y = state.y + state.direction[1] if self.world.accepted_move(next_x, next_y): - new_successors.append( - ("GO", State(next_x, next_y, state.direction)) - ) + new_successors.append(("GO", State(next_x, next_y, state.direction))) return new_successors - + def is_goal(self, state: State) -> bool: - return ( - state.x == self.goal_state.x - and state.y == self.goal_state.y ) \ No newline at end of file + return state.x == self.goal_state.x and state.y == self.goal_state.y + + def number_of_moves_forward(self) -> int: + go_count = self.actions.count("GO") + return go_count diff --git a/config.ini b/config.ini index 42cac05..3300dc8 100644 --- a/config.ini +++ b/config.ini @@ -4,9 +4,23 @@ movement = robot #accept: human, robot [CONSTANT] -NumberOfBananas = 10 -NumberOfEarrings = 3 +NumberOfBananas = 15 +NumberOfEarrings = 0 NumberOfPlants = 5 +BananaFilling = 25 +RobotStartPosition = 5, 5 +DockStationStartPosition = 5, 6 +#9,8 [NEURAL_NETWORK] -is_nural_network_off = True \ No newline at end of file +is_neural_network_off = True + +[AI_BRAIN] +mode = full_clean +#accept: full_clean, to_station + +[GENETIC_ALGORITHM] +PopulationSize = 20 +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 7cbb760..f485b12 100644 --- a/domain/commands/vacuum_move_command.py +++ b/domain/commands/vacuum_move_command.py @@ -21,12 +21,13 @@ class VacuumMoveCommand(Command): if not self.world.accepted_move(end_x, end_y): return - tmp = self.world.is_garbage_at(end_x, end_y) - if len(tmp) > 0: - for t in tmp: + garbage = self.world.garbage_at(end_x, end_y) + if len(garbage) > 0: + for item in garbage: if self.vacuum.get_container_filling() < 100: self.vacuum.increase_container_filling() - self.world.dust[end_x][end_y].remove(t) + 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/domain/entities/vacuum.py b/domain/entities/vacuum.py index b34d8c0..bc0a479 100644 --- a/domain/entities/vacuum.py +++ b/domain/entities/vacuum.py @@ -1,5 +1,9 @@ from domain.entities.entity import Entity from domain.world import World +import configparser + +config = configparser.ConfigParser() +config.read("config.ini") class Vacuum(Entity): @@ -11,7 +15,7 @@ class Vacuum(Entity): self.container_filling = 0 def increase_container_filling(self) -> None: - self.container_filling += 5 + self.container_filling += config.getint("CONSTANT", "BananaFilling") def dump_trash(self) -> None: self.container_filling = 0 diff --git a/domain/world.py b/domain/world.py index caf17f8..40d3cf0 100644 --- a/domain/world.py +++ b/domain/world.py @@ -8,7 +8,9 @@ class World: self.width = width self.height = height self.dust = [[[] for j in range(height)] for i in range(width)] + self.dustList: list[Entity] = [] self.obstacles = [[[] for j in range(height)] for i in range(width)] + self.entity = [[[] for j in range(height)] for i in range(width)] self.vacuum = None self.cat = None @@ -19,8 +21,10 @@ class World: self.doc_station = entity elif entity.type == "PEEL": self.dust[entity.x][entity.y].append(entity) + self.dustList.append(Entity(entity.x, entity.y, "PEEL")) elif entity.type == "EARRING": self.dust[entity.x][entity.y].append(entity) + self.dustList.append(Entity(entity.x, entity.y, "EARRING")) elif entity.type == "VACUUM": self.vacuum = entity elif entity.type == "CAT": @@ -29,10 +33,27 @@ class World: else: self.obstacles[entity.x][entity.y].append(entity) + self.entity[entity.x][entity.y].append(entity) + + def is_entity_at( + self, + x: int, + y: int, + ) -> bool: + if len(self.entity[x][y]) > 0: + return True + return False + + def delete_entities_at_Of_type(self, x: int, y: int, type: str): + entities = self.entity[x][y] + for entity in entities: + if entity.type == type: + entities.remove(entity) + def is_obstacle_at(self, x: int, y: int) -> bool: return bool(self.obstacles[x][y]) - def is_garbage_at(self, x: int, y: int): + def garbage_at(self, x: int, y: int) -> list[Entity]: if len(self.dust[x][y]) == 0: return [] return [i for i in self.dust[x][y] if evaluate([i.properties])[0] == 1] @@ -54,5 +75,5 @@ class World: return True - def get_cost(self, x, y): + def get_cost(self, x, y) -> float: return self.costs[x][y] diff --git a/main.py b/main.py index f94b1df..0a4c6ae 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,9 @@ from random import randint import pygame import configparser +config = configparser.ConfigParser() +config.read("config.ini") + from domain.commands.random_cat_move_command import RandomCatMoveCommand from domain.commands.vacuum_move_command import VacuumMoveCommand from domain.entities.cat import Cat @@ -13,17 +16,16 @@ from domain.entities.earring import Earring from domain.entities.docking_station import Doc_Station from domain.world import World from view.renderer import Renderer -from AI_brain.image_recognition import VacuumRecognizer +from AI_brain.genetic_algorytm import GeneticAlgorytm, Path + +if not config.getboolean("NEURAL_NETWORK", "is_neural_network_off"): + from AI_brain.image_recognition import VacuumRecognizer # from AI_brain.movement import GoAnyDirectionBFS, State # from AI_brain.rotate_and_go_bfs import RotateAndGoBFS, State from AI_brain.rotate_and_go_aStar import RotateAndGoAStar, State -config = configparser.ConfigParser() -config.read("config.ini") - - class Main: def __init__(self): tiles_x = 10 @@ -51,24 +53,38 @@ class Main: def run_robot(self): self.renderer.render(self.world) - start_state = State(self.world.vacuum.x, self.world.vacuum.y) - end_state = State(self.world.doc_station.x, self.world.doc_station.y) + if config["AI_BRAIN"]["mode"] == "to_station": + start_state = State(self.world.vacuum.x, self.world.vacuum.y) + end_state = State(self.world.doc_station.x, self.world.doc_station.y) - # path_searcher = GoAnyDirectionBFS(self.world, start_state, end_state) - # path_searcher = RotateAndGoBFS(self.world, start_state, end_state) - path_searcher = RotateAndGoAStar(self.world, start_state, end_state) - if not path_searcher.search(): - print("No solution") + path_searcher = RotateAndGoAStar(self.world, start_state, end_state) + + if not path_searcher.search(): + print("No solution") + exit(0) + print(path_searcher.actions) + print(path_searcher.cost) + robot_actions = path_searcher.actions + + elif config["AI_BRAIN"]["mode"] == "full_clean": + genetic_searcher = GeneticAlgorytm(self.world) + genetic_searcher.run() + + genetic_searcher.print_top() + + robot_actions = genetic_searcher.best_path.real_path + + else: + print("Wrong mode") exit(0) - path_searcher.actions.reverse() while self.running: for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False - if len(path_searcher.actions) > 0: - action_direction = path_searcher.actions.pop() + if len(robot_actions) > 0: + action_direction = robot_actions.pop(0) # self.handle_action1(action_direction) self.handle_action2(action_direction) @@ -113,6 +129,8 @@ class Main: self.world.vacuum.direction[1], -self.world.vacuum.direction[0], ) + elif action == "DEFAULT_ROTATION": + self.world.vacuum.direction = (1, 0) def process_input(self): for event in pygame.event.get(): @@ -145,35 +163,59 @@ class Main: def generate_world(tiles_x: int, tiles_y: int) -> World: - if config.getboolean("NEURAL_NETWORK", "is_nural_network_off"): + if config.getboolean("NEURAL_NETWORK", "is_neural_network_off"): world = World(tiles_x, tiles_y) - for _ in range(config.getint("CONSTANT", "NumberOfBananas")): - temp_x = randint(0, tiles_x - 1) - temp_y = randint(0, tiles_y - 1) - world.add_entity(Garbage(temp_x, temp_y)) - world.vacuum = Vacuum(1, 1) - world.doc_station = Doc_Station(9, 8) + + x, y = config.get("CONSTANT", "RobotStartPosition").split(",") + x, y = int(x), int(y) + world.vacuum = Vacuum(x, y) + + x, y = config.get("CONSTANT", "DockStationStartPosition").split(",") + x, y = int(x), int(y) + world.doc_station = Doc_Station(x, y) if config.getboolean("APP", "cat"): world.cat = Cat(7, 8) world.add_entity(world.cat) + + world.add_entity(world.doc_station) + world.add_entity(world.vacuum) world.add_entity(Entity(2, 8, "PLANT1")) world.add_entity(Entity(4, 1, "PLANT1")) world.add_entity(Entity(3, 4, "PLANT2")) world.add_entity(Entity(8, 8, "PLANT2")) world.add_entity(Entity(9, 3, "PLANT3")) - world.add_entity(Earring(9, 7)) - world.add_entity(Earring(5, 5)) - world.add_entity(Earring(4, 6)) + + numberOfEarrings = config.getint("CONSTANT", "NumberOfEarrings") + 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) + 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(Garbage(temp_x, temp_y)) else: - def world_adder(x,y,object,style=None): + + def world_adder(x, y, object, style=None): print(object) - if object == 'Plant': + if object == "Plant": world.add_entity(Entity(x, y, f"PLANT{randint(1, 3)}")) - if object == 'Earings': + if object == "Earings": world.add_entity(Earring(x, y)) - if object == 'Banana': + if object == "Banana": world.add_entity(Garbage(temp_x, temp_y)) - if object == 'Cat' and config.getboolean("APP", "cat"): + if object == "Cat" and config.getboolean("APP", "cat"): world.add_entity(Cat(x, y)) neural_network = VacuumRecognizer() @@ -188,28 +230,27 @@ def generate_world(tiles_x: int, tiles_y: int) -> World: for _ in range(config.getint("CONSTANT", "NumberOfPlants")): temp_x = randint(0, tiles_x - 1) temp_y = randint(0, tiles_y - 1) - path = VacuumRecognizer.get_random_dir(neural_network,'Plant') + path = VacuumRecognizer.get_random_dir(neural_network, "Plant") world_adder(temp_x, temp_y, neural_network.recognize(path)) for _ in range(config.getint("CONSTANT", "NumberOfEarrings")): temp_x = randint(0, tiles_x - 1) temp_y = randint(0, tiles_y - 1) - path = VacuumRecognizer.get_random_dir(neural_network,'Earings') + path = VacuumRecognizer.get_random_dir(neural_network, "Earings") world_adder(temp_x, temp_y, neural_network.recognize(path)) for _ in range(config.getint("CONSTANT", "NumberOfBananas")): temp_x = randint(0, tiles_x - 1) temp_y = randint(0, tiles_y - 1) - path = VacuumRecognizer.get_random_dir(neural_network,'Banana') + path = VacuumRecognizer.get_random_dir(neural_network, "Banana") world_adder(temp_x, temp_y, neural_network.recognize(path)) - for x in range(world.width): for y in range(world.height): - if world.is_garbage_at(x, y): + if world.garbage_at(x, y): world.costs[x][y] = 1 else: - world.costs[x][y] = 10 + world.costs[x][y] = 2 return world diff --git a/view/renderer.py b/view/renderer.py index 241f5d2..d0863cc 100644 --- a/view/renderer.py +++ b/view/renderer.py @@ -94,7 +94,7 @@ class Renderer: self.tile_height + self.tile_height / 4, ), ), - "EARRING": pygame.transform.scale( + "EARRING": pygame.transform.scale( pygame.image.load("media/sprites/earrings.webp"), ( self.tile_width + self.tile_width / 4, @@ -115,16 +115,8 @@ class Renderer: self.render_board() for x in range(world.width): for y in range(world.height): - for entity in world.dust[x][y]: + for entity in world.entity[x][y]: self.draw_entity(entity) - for x in range(world.width): - for y in range(world.height): - for entity in world.obstacles[x][y]: - self.draw_entity(entity) - self.draw_entity(world.vacuum) - self.draw_entity(world.doc_station) - if config.getboolean("APP", "cat"): - self.draw_entity(world.cat) pygame.display.update() def line(self, x_1, y_1, x_2, y_2, color=None):