import numpy as np import random import pygame from constant import width, height, size, rows, cols from board import Board from tractor import Tractor routes_num = 20 # Ilość ścieżek board = Board() weed_positions = board.get_weed_positions() weed_count = len(weed_positions) def manhattan(a, b): return abs(a[0] - b[0]) + abs(a[1] - b[1]) def find_routes(routes_num): population_set = [] # zapisujemy trasy - losowe ułóżenia for i in range(routes_num): # losowo wygenerowane kolejności na trasie single_route = np.random.choice(list(range(weed_count)), weed_count, replace=False) population_set.append(single_route) return np.array(population_set) #zwracamy 20 roznych losowych tras def sum_up_for_route(route_indices): sum = 0 for i in range(len(route_indices) - 1): current_weed = weed_positions[route_indices[i]] next_weed = weed_positions[route_indices[i + 1]] sum += manhattan(current_weed, next_weed) return sum #zwracamy odleglosc (ilosc pol) dla danej trasy manhatanem def routes_sum(population_set): # zapisujemy na liście finalne sumy odległości dla każdej z tras list_of_sums = np.zeros(routes_num) for i in range(routes_num): list_of_sums[i] = sum_up_for_route(population_set[i]) # wywołujemy dla każdej trasy na liście return list_of_sums def calculate_fitness(distances): # odwrotność odległości jako fitness # dodajemy małą wartość (np. 1) aby uniknąć dzielenia przez zero return 1 / (distances + 1) def selection(population_set, list_of_sums): #RULETKA - czesciowo faworyzuje rozwiaznaia, wiekszy fitness wieksze szanse # obliczamy wartości fitness (przystosowania) dla każdej trasy fitness_values = calculate_fitness(list_of_sums)#krotsze trasy maja miec wyzsze wartosci # normalizujemy wartości fitness, aby sumowały się do 1 (wymagane dla np.random.choice) probabilities = fitness_values / fitness_values.sum() # wybieramy indeksy rodziców na podstawie prawdopodobieństw progenitor_indices_a = np.random.choice(range(len(population_set)), len(population_set), p=probabilities, replace=True) progenitor_indices_b = np.random.choice(range(len(population_set)), len(population_set), p=probabilities, replace=True) # finalne trasy progenitor_a = population_set[progenitor_indices_a] progenitor_b = population_set[progenitor_indices_b] return np.array([progenitor_a, progenitor_b]) #zwracami listy przodkow-rodzicow def one_point_crossover(parent_a, parent_b): #krzyzowanie jednopunktowe crossover_point = np.random.randint(1, len(parent_a)) child = np.concatenate((parent_a[:crossover_point], [x for x in parent_b if x not in parent_a[:crossover_point]])) return child #loosyw punkt przeciecia ktory skleja nam nowa trase, wieksza szans na lepsza tarse def population_mating(progenitor_list): new_population_set = [] for i in range(len(progenitor_list[0])): progenitor_a, progenitor_b = progenitor_list[0][i], progenitor_list[1][i] child = one_point_crossover(progenitor_a, progenitor_b) new_population_set.append(child) return new_population_set # lista potomkow po krzyzowaniu def mutation_of_child(child, mutation_rate=0.2):#procent moze pomoc w niezaklucaniu trasy gdy jesy duza trasa ale idk num_mutations = int(len(child) * mutation_rate) for _ in range(num_mutations): x = np.random.randint(0, len(child))#losowa szansa zamiany - mutacja y = np.random.randint(0, len(child)) child[x], child[y] = child[y], child[x] return child#zwrocenie bardziej roznorodnych potomkow def mutate_population(new_population_set): final_mutated_population = [] for child in new_population_set: final_mutated_population.append(mutation_of_child(child)) # dodajemy zmutowane dziecko do finalnej listy return final_mutated_population if __name__ == '__main__': pygame.init() WIN = pygame.display.set_mode((width, height)) pygame.display.set_caption('Trasa Traktora') clock = pygame.time.Clock() board = Board() board.load_images() weed_positions = [(col, row) for col in range(cols) for row in range(rows) if board.is_weed(col, row)] weed_count = len(weed_positions) board.set_grass(9, 9) # pozycja startowa tractor = Tractor(9, 9) # Start traktora # Inicjalizacja final_route final_route = [0, float('inf'), np.array([])] # [0]: indeks iteracji, [1]: najlepsza suma odległości, [2]: najlepsza trasa population_set = find_routes(routes_num) list_of_sums = routes_sum(population_set) progenitor_list = selection(population_set, list_of_sums) new_population_set = population_mating(progenitor_list) final_mutated_population = mutate_population(new_population_set) final_route = [-1, np.inf, np.array([])] # format listy for i in range(20): list_of_sums = routes_sum(final_mutated_population) # zapisujemy najlepsze rozwiązanie if list_of_sums.min() < final_route[1]: final_route[0] = i final_route[1] = list_of_sums.min() final_route[2] = np.array(final_mutated_population)[list_of_sums.min() == list_of_sums] progenitor_list = selection(population_set, list_of_sums) new_population_set = population_mating(progenitor_list) final_mutated_population = mutate_population(new_population_set) print(f"Najlepsza trasa znaleziona w iteracji: {final_route[0]}") print(f"Minimalna suma odległości: {final_route[1]}") run = True current_target_index = 0 best_routes = final_route[2] #tablica z najlepszymi trasami visited_fields = [] while run: clock.tick(2) # FPS for event in pygame.event.get(): if event.type == pygame.QUIT: run = False for route in best_routes: if current_target_index < len(route): current_weed = weed_positions[route[current_target_index]] # ruch w kierunku bieżącego celu if tractor.col < current_weed[0]: tractor.col += 1 tractor.direction = "right" elif tractor.col > current_weed[0]: tractor.col -= 1 tractor.direction = "left" elif tractor.row < current_weed[1]: tractor.row += 1 tractor.direction = "down" elif tractor.row > current_weed[1]: tractor.row -= 1 tractor.direction = "up" current_position = (tractor.col, tractor.row) if current_position not in visited_fields: visited_fields.append(current_position) # Jeśli traktor dotarł do celu if (tractor.col, tractor.row) == current_weed: current_target_index += 1 # Aktualizacja planszy if board.is_weed(tractor.col, tractor.row): board.set_carrot(tractor.col, tractor.row) board.draw_cubes(WIN) tractor.draw(WIN) pygame.display.update() print("Odwiedzone pola:") for field in visited_fields: print(field) pygame.quit()