from random import randint, choices, random from kb import tractor_kb, multi_sasiedzi import pytholog as pl from numpy.random import choice as npchoice def score_field(field): score = 0 for index in range(len(field)): neighbours = [] if index >= 16 and field[index-16] != 'water': neighbours.append(field[index-16]) if index % 15 != 0 and field[index+1] != 'water': neighbours.append(field[index+1]) if index < 240 and field[index+16] != 'water': neighbours.append(field[index+16]) if index % 16 != 0 and field[index-1] != 'water': neighbours.append(field[index-1]) mod = multi_sasiedzi(field[index], neighbours)[0]["Mul"] if mod > 10: print(mod, '= multi(', field[index], ', ', neighbours, ')') score += mod score = score / 256 return score def choose_parents(population): total_weights = sum(entity[0] for entity in population) weights = [entity[0] / total_weights for entity in population] selection = npchoice(len(population), size=2, replace=False, p=weights) parents = [population[i] for i in selection] return parents[0], parents[1] def breed_and_mutate(mom, dad): crossover_point = randint(1, len(mom[1]) - 2) offspring = mom[1][:crossover_point] + dad[1][crossover_point:] if len(offspring) != len(mom): ValueError("offspring length is not equal to mom length") if random() < 0.1: mutation_index = randint(0, len(offspring) - 1) while offspring[mutation_index] == 'water': mutation_index = randint(0, len(offspring) - 1) mutation = get_random_vegetable() while mutation == offspring[mutation_index]: mutation = get_random_vegetable() offspring[mutation_index] = mutation offspring_score = score_field(offspring) # print('offspring score', offspring_score, 'for parents', mom[0], 'and', dad[0]) return [offspring_score, offspring] def get_random_vegetable(): vegetables = [x['Nazwa_warzywa'] for x in tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)"))] return vegetables[randint(0,len(vegetables)-1)] def genetic_algorithm(population, iterations): population_size = len(population) for entity in population: entity[0] = score_field(entity[1]) for iteration in range(iterations): population.sort(key=lambda x: x[0], reverse=True) print('\n=====\n\n💪 Best individual in iteration', iteration, 'has a score of', population[0][0]) population = population[:population_size//2] new_offspring = [] while len(population) + len(new_offspring) < population_size: mom, dad = choose_parents(population) child = breed_and_mutate(mom, dad) new_offspring.append(child) population.extend(new_offspring) return population[0] population = [] # each field has unmutable locations of water and grass tiles water_tile_indexes = [1, 2, 3, 34, 37, 44, 45, 53, 60, 61, 69, 81, 82, 83, 84, 119, 120, 121, 136, 152, 187, 194, 202, 203, 204, 210, 219, 226, 227, 228] grass_tile_indexes = [0, 39, 40, 56, 71, 72, 73, 86, 88, 114, 115, 130, 146, 147, 163, 164, 166, 167, 180, 181, 182, 231, 232, 233] vegetables = [x['Nazwa_warzywa'] for x in tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)"))] for _ in range(100): field = [vegetables[randint(0, 24)] for _ in range(256)] for index in water_tile_indexes: field[index] = "water" for index in grass_tile_indexes: field[index] = "grass" # entities of the population are stored with two properties # the first being the average score of the field # and the second being the layout of the field population.append([0, field]) best = genetic_algorithm(population, 20) print('\n=====\n\nfinal field multiplier score is', best[0]) with open('field', 'w', encoding='utf-8') as file: file.write(str(best[1])) file.close print('final field layout saved to file "field" in the current working directory\n')