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 Flower
|
||||||
import Beehive
|
import Beehive
|
||||||
import Frames
|
import Frames
|
||||||
|
from GeneticAlgorithm import GA
|
||||||
from Field import Field, Neighbors
|
from Field import Field, Neighbors
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
import heapq as h
|
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)
|
white = (255, 255, 255)
|
||||||
|
|
||||||
#setting caption and icon
|
#setting caption and icon
|
||||||
@ -42,13 +88,13 @@ tiles_types = {
|
|||||||
SHORT: pygame.image.load('spritesNtiles/shortGrass64.png'),
|
SHORT: pygame.image.load('spritesNtiles/shortGrass64.png'),
|
||||||
TALL: pygame.image.load('spritesNtiles/tallGrass64.png'),
|
TALL: pygame.image.load('spritesNtiles/tallGrass64.png'),
|
||||||
TREE: pygame.image.load('spritesNtiles/dirtTree64.png'),
|
TREE: pygame.image.load('spritesNtiles/dirtTree64.png'),
|
||||||
FLOWER: pygame.image.load('spritesNtiles/input.png')
|
FLOWER: pygame.image.load('spritesNtiles/flower64.png')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tilemapSizeX = 25
|
tilemapSizeX = 12
|
||||||
tilemapSizeY = 15
|
tilemapSizeY = 12
|
||||||
tileSize = 64
|
tileSize = 64
|
||||||
|
|
||||||
tilemap_types = []
|
tilemap_types = []
|
||||||
@ -63,17 +109,12 @@ for x in range(tilemapSizeX):
|
|||||||
#example tilemap values
|
#example tilemap values
|
||||||
tilemap_values = []
|
tilemap_values = []
|
||||||
|
|
||||||
SHORT_VALUE = 5
|
SHORT_VALUE = 1
|
||||||
TALL_VALUE = 100
|
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()
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
#position of the bee and pos changings
|
#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)
|
field = Field(tilemap_types, tilemap_values)
|
||||||
|
|
||||||
|
|
||||||
def Manhattan_dis(start, end):
|
bee_dir = 'west'
|
||||||
start_x, start_y = start
|
while True:
|
||||||
end_x, end_y = end
|
bee_x = random.randint(0, tilemapSizeX-2)
|
||||||
return abs(start_x - end_x) + abs(start_y - end_y)
|
bee_y = random.randint(0, tilemapSizeY-2)
|
||||||
|
if(field.get_type([bee_x, bee_y]) != TREE):
|
||||||
def Make_path(start, end, previos):
|
break
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@ -154,6 +186,7 @@ for x in path_A_star:
|
|||||||
if x[0:2] not in check_path_A:
|
if x[0:2] not in check_path_A:
|
||||||
check_path_A.append(x[0:2])
|
check_path_A.append(x[0:2])
|
||||||
print(check_path_A)
|
print(check_path_A)
|
||||||
|
print(len(check_path_A))
|
||||||
path = path_A_star
|
path = path_A_star
|
||||||
|
|
||||||
|
|
||||||
@ -198,6 +231,3 @@ while True:
|
|||||||
if(step == -1 and current_node == 0):
|
if(step == -1 and current_node == 0):
|
||||||
step *= -1
|
step *= -1
|
||||||
current_node += step
|
current_node += step
|
||||||
|
|
||||||
|
|
||||||
## setitem, bfs
|
|
Loading…
Reference in New Issue
Block a user