import random def make_population(population_s, field_s): population = [] crops = ['apple', 'cauliflower', 'radish', 'wheat', 'rock_dirt', 'dirt'] for _ in range(population_s): i = [] for _ in range(field_s): row = random.choices(crops, k=field_s) i.append(row) population.append(i) return population def calculate_fitness(individual): cost = 0 for i in range(len(individual)): for j in range(len(individual[i])): crop = individual[i][j] neighbors = [ individual[x][y] for x in range(max(0, i-1), min(len(individual), i+2)) for y in range(max(0, j-1), min(len(individual), j+2)) if (x,y) != (i,j) ] for n in neighbors: if crop == 'wheat' and n == 'apple': cost += 2 elif crop == 'cauliflower' and n == 'radish': cost += 4 fitness = 1/(1+cost) return fitness def select_parents(population, fitnesses): fitnesses_sum = sum(fitnesses) selection_parts = [fitness / fitnesses_sum for fitness in fitnesses] parents = random.choices(population, weights=selection_parts, k=2) return parents def crossover(parent_1, parent_2): crossover_point = random.randint(1, (len(parent_1)-1)) child_1 = parent_1[:crossover_point] + parent_2[crossover_point:] child_2 = parent_2[:crossover_point] + parent_1[crossover_point:] return child_1, child_2 def mutation(individual, chance): crops = ['apple', 'cauliflower', 'radish', 'wheat', 'rock_dirt', 'dirt'] if random.random() < chance: row = random.randint(0, len(individual) - 1) column = random.randint(0, len(individual[0]) - 1) individual[row][column] = random.choice(crops) return individual def genetic_algorithm(population_s, field_s, chance, limit): population = make_population(population_s, field_s) best_fitness = 0 count = 0 while best_fitness < 1: fitnesses = [calculate_fitness(individual) for individual in population] new_population = [] for _ in range(population_s // 2): parent_1, parent_2 = select_parents(population, fitnesses) p1c = calculate_fitness(parent_1) p2c = calculate_fitness(parent_2) print("p1c: ",p1c,"\np2c: ",p2c) child_1, child_2 = crossover(parent_1, parent_2) child_1 = mutation(child_1, chance) child_2 = mutation(child_2, chance) new_population.append(child_1) new_population.append(child_2) combined_population = population + new_population combined_population = sorted(combined_population, key=calculate_fitness, reverse=True) population = combined_population[:population_s] current_best_fitness = calculate_fitness(population[0]) if current_best_fitness > best_fitness: best_fitness = current_best_fitness count = 0 else: count += 1 if count >= limit: break best_child = max(population, key=calculate_fitness) bsf = calculate_fitness(best_child) print("bsf: ", bsf) return best_child