diff --git a/src/generate_field.py b/src/generate_field.py new file mode 100644 index 00000000..9d7fb069 --- /dev/null +++ b/src/generate_field.py @@ -0,0 +1,123 @@ +from random import randint, choices, random +from kb import tractor_kb, multi_sasiedzi +import pytholog as pl + + +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]) + + score += multi_sasiedzi(field[index], neighbours)[0]["Mul"] + + return score + + +def choose_parents(population): + weights = [x[0] for x in population] + + weights_sum = 0 + for weight in weights: + weights_sum += weight + + weights = [weight/weights_sum for weight in weights] + + mom = choices(population, cum_weights=weights, k=1)[0] + remaining_elements = [el for el in population if el != mom] + remaining_weights = [weights[population.index(el)] for el in remaining_elements] + dad = choices(remaining_elements, weights=remaining_weights, k=1)[0] + + return mom, dad + + +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 lenght 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) + + 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 _ in range(iterations): + population.sort(key=lambda x: x[0], reverse=True) + population = population[:5] + 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] + + +vegetables = [x['Nazwa_warzywa'] for x in tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)"))] +# water tiles locations +# _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +# _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +# _ _ X X _ _ _ _ _ _ X X X _ _ _ +# _ X X X _ _ _ _ _ X X X _ _ _ _ +# _ _ X _ _ _ _ _ _ _ _ _ _ _ _ _ +# _ _ X _ _ _ _ X X _ X X _ _ _ _ +# _ _ _ _ _ _ X X X X X X _ _ _ _ +# _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ +# _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ +# _ _ _ _ X _ _ _ _ _ _ _ _ _ _ _ +# _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ +# _ _ _ _ X _ _ _ _ _ X _ _ _ _ _ +# _ _ _ _ _ _ _ _ X X X X _ _ _ _ +# _ _ _ X _ _ _ _ _ X X X _ _ _ _ +# _ X _ _ _ _ _ _ _ _ _ _ _ _ _ _ +# _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +water_tile_indexes = [37, 38, 45, 46, 47, 53, 54, 55, 61, 62, 63, 71, 88, 93, 94, 96, 97, 109, 110, 111, 112, 113, 114, 126, 127, 144, 145, 158, 175, 176, 192, 198, 213, 214, 215, 216, 225, 231, 232, 233, 240] +population = [] + +for _ in range(10): + field = [vegetables[randint(0, 24)] for _ in range(256)] + for index in water_tile_indexes: + field[index] = "water" + # 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, 10) +print('final field layout', best[1]) +print('final field multiplier score', best[0])