2024-06-08 22:05:54 +02:00
|
|
|
from random import randint, choices, random
|
|
|
|
from kb import tractor_kb, multi_sasiedzi
|
|
|
|
import pytholog as pl
|
2024-06-09 16:31:11 +02:00
|
|
|
from numpy.random import choice as npchoice
|
2024-06-08 22:05:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
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])
|
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
mod = multi_sasiedzi(field[index], neighbours)[0]["Mul"]
|
|
|
|
if mod > 10:
|
|
|
|
print(mod, '= multi(', field[index], ', ', neighbours, ')')
|
|
|
|
score += mod
|
2024-06-08 22:05:54 +02:00
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
score = score / 256
|
2024-06-08 22:05:54 +02:00
|
|
|
return score
|
|
|
|
|
|
|
|
|
|
|
|
def choose_parents(population):
|
2024-06-09 16:31:11 +02:00
|
|
|
total_weights = sum(entity[0] for entity in population)
|
|
|
|
|
|
|
|
weights = [entity[0] / total_weights for entity in population]
|
2024-06-08 22:05:54 +02:00
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
selection = npchoice(len(population), size=2, replace=False, p=weights)
|
2024-06-08 22:05:54 +02:00
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
parents = [population[i] for i in selection]
|
2024-06-08 22:05:54 +02:00
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
return parents[0], parents[1]
|
2024-06-08 22:05:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
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):
|
2024-06-09 16:31:11 +02:00
|
|
|
ValueError("offspring length is not equal to mom length")
|
2024-06-08 22:05:54 +02:00
|
|
|
|
|
|
|
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)
|
2024-06-09 16:31:11 +02:00
|
|
|
# print('offspring score', offspring_score, 'for parents', mom[0], 'and', dad[0])
|
2024-06-08 22:05:54 +02:00
|
|
|
|
|
|
|
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])
|
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
for iteration in range(iterations):
|
2024-06-08 22:05:54 +02:00
|
|
|
population.sort(key=lambda x: x[0], reverse=True)
|
2024-06-09 16:31:11 +02:00
|
|
|
print('\n=====\n\n💪 Best individual in iteration', iteration, 'has a score of', population[0][0])
|
|
|
|
population = population[:population_size//2]
|
2024-06-08 22:05:54 +02:00
|
|
|
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 = []
|
2024-06-09 16:31:11 +02:00
|
|
|
# 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)"))]
|
2024-06-08 22:05:54 +02:00
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
for _ in range(100):
|
2024-06-08 22:05:54 +02:00
|
|
|
field = [vegetables[randint(0, 24)] for _ in range(256)]
|
|
|
|
for index in water_tile_indexes:
|
|
|
|
field[index] = "water"
|
2024-06-09 16:31:11 +02:00
|
|
|
for index in grass_tile_indexes:
|
|
|
|
field[index] = "grass"
|
|
|
|
|
2024-06-08 22:05:54 +02:00
|
|
|
# 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])
|
|
|
|
|
2024-06-09 16:31:11 +02:00
|
|
|
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')
|