feat: generate initial field layout using genetic algorithm
This commit is contained in:
parent
d2ad851cab
commit
f7279fc846
123
src/generate_field.py
Normal file
123
src/generate_field.py
Normal file
@ -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])
|
Loading…
Reference in New Issue
Block a user