genetic algorithms
This commit is contained in:
parent
7eaf166f2a
commit
704f19c23a
3
.idea/.gitignore
vendored
Normal file
3
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
10
.idea/Intelegentny_Pszczelarz.iml
Normal file
10
.idea/Intelegentny_Pszczelarz.iml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
4
.idea/misc.xml
Normal file
4
.idea/misc.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Intelegentny_Pszczelarz.iml" filepath="$PROJECT_DIR$/.idea/Intelegentny_Pszczelarz.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
213
src/GeneticAlgorithm.py
Normal file
213
src/GeneticAlgorithm.py
Normal file
@ -0,0 +1,213 @@
|
||||
import copy
|
||||
import random
|
||||
from Field import Field, Neighbors
|
||||
import heapq as h
|
||||
|
||||
FLOWER = 0
|
||||
SHORT = 1
|
||||
TALL = 80
|
||||
TREE = 100
|
||||
population_size = 50
|
||||
num_of_trees = 30
|
||||
crossover_rate = 0.8
|
||||
mutation_rate = 0.1
|
||||
tilemapSizeX = 12
|
||||
tilemapSizeY = 12
|
||||
SHORT_VALUE = 1
|
||||
TALL_VALUE = 100
|
||||
TREE_VALUE = 200
|
||||
tilemap_values = []
|
||||
class Individual:
|
||||
def __init__(self, genes):
|
||||
self.genes = genes
|
||||
self.fitness = 0
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.genes[index]
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self.genes[index] = value
|
||||
|
||||
|
||||
class GA:
|
||||
def __init__(self, population_size, generations, flower_positions, tilemap):
|
||||
self.population_size = population_size
|
||||
self.generations = generations
|
||||
self.population = []
|
||||
self.mutation_rate = mutation_rate
|
||||
self.crossover_rate = crossover_rate
|
||||
self.flower_positions = flower_positions
|
||||
self.tilemap = tilemap
|
||||
|
||||
def initialize_population(self):
|
||||
# Generate random individuals representing tree arrangements
|
||||
for _ in range(self.population_size):
|
||||
individual = self.generate_individual()
|
||||
self.population.append(individual)
|
||||
|
||||
def generate_individual(self):
|
||||
# Generate a random tree arrangement
|
||||
individual = []
|
||||
available_positions = [(x, y) for x in range(1, tilemapSizeX - 1) for y in range(1, tilemapSizeY - 1)]
|
||||
random.shuffle(available_positions)
|
||||
|
||||
for i in range(num_of_trees):
|
||||
individual.append(available_positions[i])
|
||||
|
||||
return Individual(individual)
|
||||
|
||||
def evaluate_fitness(self):
|
||||
for individual in self.population:
|
||||
individual.fitness = self.calculate_average_distance(individual.genes)
|
||||
print(f"Fitness for individual {individual}: {individual.fitness}")
|
||||
|
||||
def calculate_average_distance(self, individual):
|
||||
tilemap_values = []
|
||||
local_tile_map = copy.deepcopy(self.tilemap)
|
||||
total_distance = 0
|
||||
|
||||
# Set trees on the local tile map
|
||||
for tree_x, tree_y in individual:
|
||||
local_tile_map[tree_x][tree_y] = TREE
|
||||
|
||||
for X in range(0, len(local_tile_map)):
|
||||
tilemap_values.append([])
|
||||
for Y in range(0, len(local_tile_map[X])):
|
||||
if local_tile_map[X][Y] == SHORT:
|
||||
value = SHORT_VALUE
|
||||
elif local_tile_map[X][Y] == TALL:
|
||||
value = TALL_VALUE
|
||||
elif local_tile_map[X][Y] == TREE:
|
||||
value = TREE_VALUE
|
||||
elif local_tile_map[X][Y] == FLOWER:
|
||||
value = 1
|
||||
tilemap_values[X].append(value)
|
||||
|
||||
field = Field(local_tile_map, tilemap_values)
|
||||
|
||||
for flower_x, flower_y in self.flower_positions:
|
||||
totalFlowerDistance = 0
|
||||
for flower2_x, flower2_y in self.flower_positions:
|
||||
if flower_x == flower2_x and flower_y == flower2_y:
|
||||
continue
|
||||
|
||||
pathAstar = A_star(field, (flower_x, flower_y, 3), (flower2_x, flower2_y))
|
||||
if pathAstar is None:
|
||||
continue
|
||||
|
||||
# Check for trees in the path
|
||||
has_tree = False
|
||||
for x, y, _ in pathAstar:
|
||||
if local_tile_map[x][y] == TREE:
|
||||
has_tree = True
|
||||
break
|
||||
|
||||
if has_tree:
|
||||
continue
|
||||
|
||||
# Calculate the unique positions in the path
|
||||
check_path_A = []
|
||||
for x, y, _ in pathAstar:
|
||||
if (x, y) not in check_path_A:
|
||||
check_path_A.append((x, y))
|
||||
totalFlowerDistance += len(check_path_A)
|
||||
|
||||
total_distance += totalFlowerDistance
|
||||
|
||||
average_distance = total_distance / (len(self.flower_positions))
|
||||
return average_distance
|
||||
|
||||
def selection(self):
|
||||
# Select individuals based on their fitness
|
||||
weights = [individual.fitness for individual in self.population]
|
||||
selected = random.choices(self.population, weights=weights, k=self.population_size)
|
||||
# Copy the selected individuals as the new population
|
||||
self.population = selected
|
||||
|
||||
def crossover(self):
|
||||
# Perform crossover between selected individuals to create offspring
|
||||
offspring = []
|
||||
while len(offspring) < self.population_size:
|
||||
parent1, parent2 = random.sample(self.population, 2)
|
||||
child = self.perform_crossover(parent1, parent2)
|
||||
offspring.append(child)
|
||||
self.population = offspring
|
||||
|
||||
def perform_crossover(self, parent1, parent2):
|
||||
child_genes = []
|
||||
for i in range(len(parent1.genes)):
|
||||
# Perform crossover by randomly selecting genes from parents
|
||||
if random.random() < self.crossover_rate:
|
||||
child_genes.append(parent1.genes[i])
|
||||
else:
|
||||
child_genes.append(parent2.genes[i])
|
||||
|
||||
child = Individual(child_genes)
|
||||
return child
|
||||
|
||||
def mutation(self):
|
||||
# Perform mutation on the offspring
|
||||
for individual in self.population:
|
||||
if random.random() < mutation_rate:
|
||||
self.perform_mutation(individual)
|
||||
|
||||
def perform_mutation(self, individual):
|
||||
# Perform mutation operation on the individual
|
||||
index1 = random.randint(0, num_of_trees - 1)
|
||||
index2 = random.randint(0, num_of_trees - 1)
|
||||
individual.genes[index1], individual.genes[index2] = individual.genes[index2], individual.genes[index1]
|
||||
|
||||
def run(self):
|
||||
self.initialize_population()
|
||||
for _ in range(self.generations):
|
||||
self.evaluate_fitness()
|
||||
self.selection()
|
||||
self.crossover()
|
||||
self.mutation()
|
||||
self.evaluate_fitness()
|
||||
|
||||
best_individual = max(self.population, key=lambda x: x.fitness)
|
||||
max_dist=best_individual.fitness
|
||||
print(max_dist)
|
||||
return best_individual
|
||||
|
||||
|
||||
def Manhattan_dis(start, end):
|
||||
start_x, start_y = start
|
||||
end_x, end_y = end
|
||||
return abs(start_x - end_x) + abs(start_y - end_y)
|
||||
|
||||
|
||||
def Make_path(start, end, previos):
|
||||
path = [end]
|
||||
while start not in path:
|
||||
path.append(previos[path[-1]])
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
|
||||
def A_star(field, start, end):
|
||||
open = []
|
||||
previous = {}
|
||||
closed = set()
|
||||
checked = set()
|
||||
now = (0, start)
|
||||
h.heappush(open, (0, start))
|
||||
while len(open) > 0:
|
||||
now = h.heappop(open)
|
||||
if now[1] in closed:
|
||||
continue
|
||||
if now[1][0:2] == end:
|
||||
path = Make_path(start, now[1], previous)
|
||||
return path
|
||||
closed.add(now[1])
|
||||
checked.add(now[1][0:2])
|
||||
for x in Neighbors(field, now[1]):
|
||||
if x not in closed and x not in checked:
|
||||
previous[x] = now[1]
|
||||
if now[1][0:2] != x[0:2]:
|
||||
added_cost = field[x[0], x[1]] + Manhattan_dis(x[0:2], end)
|
||||
else:
|
||||
added_cost = 0
|
||||
h.heappush(open, (now[0] + added_cost, x))
|
||||
checked.add(x[0:2])
|
144
src/main.py
144
src/main.py
@ -3,10 +3,56 @@ import random
|
||||
#import Flower
|
||||
import Beehive
|
||||
import Frames
|
||||
from GeneticAlgorithm import GA
|
||||
from Field import Field, Neighbors
|
||||
from queue import Queue
|
||||
import heapq as h
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def Manhattan_dis(start, end):
|
||||
start_x, start_y = start
|
||||
end_x, end_y = end
|
||||
return abs(start_x - end_x) + abs(start_y - end_y)
|
||||
|
||||
|
||||
def Make_path(start, end, previos):
|
||||
path = [end]
|
||||
while start not in path:
|
||||
path.append(previos[path[-1]])
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
|
||||
def A_star(field, start, end):
|
||||
open = []
|
||||
previous = {}
|
||||
closed = set()
|
||||
checked = set()
|
||||
now = (0, start)
|
||||
h.heappush(open, (0, start))
|
||||
while len(open) > 0:
|
||||
now = h.heappop(open)
|
||||
if now[1] in closed:
|
||||
continue
|
||||
if now[1][0:2] == end:
|
||||
path = Make_path(start, now[1], previous)
|
||||
return path
|
||||
closed.add(now[1])
|
||||
checked.add(now[1][0:2])
|
||||
for x in Neighbors(field, now[1]):
|
||||
if x not in closed and x not in checked:
|
||||
previous[x] = now[1]
|
||||
if now[1][0:2] != x[0:2]:
|
||||
added_cost = field[x[0], x[1]] + Manhattan_dis(x[0:2], end)
|
||||
else:
|
||||
added_cost = 0
|
||||
h.heappush(open, (now[0] + added_cost, x))
|
||||
checked.add(x)
|
||||
|
||||
|
||||
white = (255, 255, 255)
|
||||
|
||||
#setting caption and icon
|
||||
@ -42,13 +88,13 @@ tiles_types = {
|
||||
SHORT: pygame.image.load('spritesNtiles/shortGrass64.png'),
|
||||
TALL: pygame.image.load('spritesNtiles/tallGrass64.png'),
|
||||
TREE: pygame.image.load('spritesNtiles/dirtTree64.png'),
|
||||
FLOWER: pygame.image.load('spritesNtiles/input.png')
|
||||
FLOWER: pygame.image.load('spritesNtiles/flower64.png')
|
||||
}
|
||||
|
||||
|
||||
|
||||
tilemapSizeX = 25
|
||||
tilemapSizeY = 15
|
||||
tilemapSizeX = 12
|
||||
tilemapSizeY = 12
|
||||
tileSize = 64
|
||||
|
||||
tilemap_types = []
|
||||
@ -63,17 +109,12 @@ for x in range(tilemapSizeX):
|
||||
#example tilemap values
|
||||
tilemap_values = []
|
||||
|
||||
SHORT_VALUE = 5
|
||||
SHORT_VALUE = 1
|
||||
TALL_VALUE = 100
|
||||
TREE_VALUE = 50
|
||||
TREE_VALUE = 200
|
||||
FLOWER_VALUE = 1
|
||||
|
||||
|
||||
for X in range(0, len(tilemap_types)):
|
||||
tilemap_values.append([])
|
||||
for Y in range(0, len(tilemap_types[X])):
|
||||
if tilemap_types[X][Y] == SHORT: value = SHORT_VALUE
|
||||
elif tilemap_types[X][Y] == TALL: value = TALL_VALUE
|
||||
elif tilemap_types[X][Y] == TREE: value = TREE_VALUE
|
||||
tilemap_values[X].append(value)
|
||||
|
||||
###
|
||||
|
||||
@ -90,52 +131,43 @@ dis = pygame.display.set_mode((disX, disY))
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
#position of the bee and pos changings
|
||||
bee_x = 2
|
||||
bee_y = 1
|
||||
bee_dir = 'west'
|
||||
|
||||
|
||||
# Define parameters
|
||||
flower_positions = [(flower_x, flower_y) for flower_x in range(tilemapSizeX) for flower_y in range(tilemapSizeY) if tilemap_types[flower_x][flower_y] == FLOWER]
|
||||
generations = 10
|
||||
# Create an instance of the GeneticAlgorithm class
|
||||
ga = GA(10, generations,flower_positions, tilemap_types)
|
||||
|
||||
# Run the genetic algorithm
|
||||
best_individual = ga.run()
|
||||
print(best_individual)
|
||||
|
||||
# Retrieve the best tree arrangement from the best individual
|
||||
tree_arrangement = best_individual
|
||||
|
||||
# Render the tilemap with the optimized tree positions
|
||||
for x, y in tree_arrangement:
|
||||
tilemap_types[x][y] = TREE
|
||||
print(x,y)
|
||||
|
||||
for X in range(0, len(tilemap_types)):
|
||||
tilemap_values.append([])
|
||||
for Y in range(0, len(tilemap_types[X])):
|
||||
if tilemap_types[X][Y] == SHORT: value = SHORT_VALUE
|
||||
elif tilemap_types[X][Y] == TALL: value = TALL_VALUE
|
||||
elif tilemap_types[X][Y] == TREE: value = TREE_VALUE
|
||||
elif tilemap_types[X][Y] == FLOWER: value = FLOWER_VALUE
|
||||
tilemap_values[X].append(value)
|
||||
field = Field(tilemap_types, tilemap_values)
|
||||
|
||||
|
||||
def Manhattan_dis(start, end):
|
||||
start_x, start_y = start
|
||||
end_x, end_y = end
|
||||
return abs(start_x - end_x) + abs(start_y - end_y)
|
||||
|
||||
def Make_path(start, end, previos):
|
||||
path = [end]
|
||||
while start not in path:
|
||||
path.append(previos[path[-1]])
|
||||
path.reverse()
|
||||
return path
|
||||
|
||||
def A_star(field, start, end):
|
||||
open = []
|
||||
previous = {}
|
||||
closed = set()
|
||||
checked = set()
|
||||
now = (0, start)
|
||||
h.heappush(open, (0, start))
|
||||
while len(open) > 0:
|
||||
now = h.heappop(open)
|
||||
if now[1] in closed:
|
||||
continue
|
||||
if now[1][0:2] == end:
|
||||
|
||||
path = Make_path(start, now[1], previous)
|
||||
return path
|
||||
closed.add(now[1])
|
||||
checked.add(now[1][0:2])
|
||||
for x in Neighbors(field, now[1]):
|
||||
if x not in closed and x not in checked:
|
||||
previous[x] = now[1]
|
||||
if now[1][0:2] != x[0:2]:
|
||||
added_cost = field[x[0], x[1]] + Manhattan_dis(x[0:2], end)
|
||||
else : added_cost = 0
|
||||
h.heappush(open, (now[0] + added_cost, x))
|
||||
checked.add(x)
|
||||
|
||||
|
||||
bee_dir = 'west'
|
||||
while True:
|
||||
bee_x = random.randint(0, tilemapSizeX-2)
|
||||
bee_y = random.randint(0, tilemapSizeY-2)
|
||||
if(field.get_type([bee_x, bee_y]) != TREE):
|
||||
break
|
||||
|
||||
|
||||
while True:
|
||||
@ -154,6 +186,7 @@ for x in path_A_star:
|
||||
if x[0:2] not in check_path_A:
|
||||
check_path_A.append(x[0:2])
|
||||
print(check_path_A)
|
||||
print(len(check_path_A))
|
||||
path = path_A_star
|
||||
|
||||
|
||||
@ -198,6 +231,3 @@ while True:
|
||||
if(step == -1 and current_node == 0):
|
||||
step *= -1
|
||||
current_node += step
|
||||
|
||||
|
||||
## setitem, bfs
|
Loading…
Reference in New Issue
Block a user