Genetic algorithm

This commit is contained in:
Art-cyber520 2021-05-24 16:43:07 +02:00
parent 56c8fbfc07
commit 24ef21c8e9
27 changed files with 350 additions and 88 deletions

View File

@ -1,5 +1,17 @@
class Track: class Track:
def __init__(self, road, distance): def __init__(self, priority, road):
self.priority = priority
self.road = road self.road = road
self.distance = distance
def __eq__(self, other):
try:
return self.priority == other.priority
except AttributeError:
return NotImplemented
def __lt__(self, other):
try:
return self.priority < other.priority
except AttributeError:
return NotImplemented

View File

@ -1,5 +1,10 @@
import queue import queue
from itertools import permutations, islice, combinations from itertools import permutations, islice
from math import sqrt
import random
from resources.Globals import NUMBER_OF_INDIVIDUALS_FOR_DUEL, NUMBER_OF_POINTS_PERMUTATION, PERCENT_OF_MUTATION, \
PERCENT_OF_OUTGOING_INDIVIDUALS
class Travel: class Travel:
@ -9,12 +14,190 @@ class Travel:
def genetic_algorithm(travel_map): def genetic_algorithm(travel_map):
population = queue.PriorityQueue() population = []
road_map = list(travel_map.keys()) road_map = list(travel_map.keys())
points_permutation = list(map(list, islice(permutations(road_map), 10))) points_permutation = list(map(list, islice(permutations(road_map), NUMBER_OF_POINTS_PERMUTATION)))
# for i in range(0, len(points_permutation)): # Generate the first population
# distance = for i in range(0, len(points_permutation)):
# subject = Track() road = points_permutation[i]
# print(points_permutation) priority = adaptation_function(points_permutation[i], travel_map)
# print(len(points_permutation))
population.append((priority, road))
while len(population) < 10000:
parent1, parent2 = tournament_selection(population)
child = edge_recombination_crossover(parent1[1], parent2[1])
child_priority = adaptation_function(child, travel_map)
population.append((child_priority, child))
mutation_function(population, travel_map)
population.sort(key=lambda x: x[0], reverse=True)
return population[0]
def adaptation_function(list_points, travel_map):
index_of_point = 0
distance = 0
while True:
if index_of_point < (-len(list_points)):
return round((1 / distance) * 1000000)
if index_of_point == (len(list_points) - 1):
x1 = travel_map.get(list_points[index_of_point])[0]
y1 = travel_map.get(list_points[index_of_point])[1]
x2 = travel_map.get(list_points[-len(list_points)])[0]
y2 = travel_map.get(list_points[-len(list_points)])[1]
index_of_point = -len(list_points) - 1
else:
x1 = travel_map.get(list_points[index_of_point])[0]
y1 = travel_map.get(list_points[index_of_point])[1]
x2 = travel_map.get(list_points[index_of_point + 1])[0]
y2 = travel_map.get(list_points[index_of_point + 1])[1]
index_of_point += 1
distance += sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
def tournament_selection(population):
individuals_for_duel1 = []
individuals_for_duel2 = []
population_length = len(population)
while True:
if len(individuals_for_duel1) == NUMBER_OF_INDIVIDUALS_FOR_DUEL and len(individuals_for_duel2) == NUMBER_OF_INDIVIDUALS_FOR_DUEL:
break
if len(individuals_for_duel1) != NUMBER_OF_INDIVIDUALS_FOR_DUEL:
index1 = random.randint(0, population_length - 1)
candidate_for_duel1 = population[index1]
if candidate_for_duel1 not in individuals_for_duel1:
individuals_for_duel1.append(candidate_for_duel1)
if len(individuals_for_duel2) != NUMBER_OF_INDIVIDUALS_FOR_DUEL:
index2 = random.randint(0, population_length - 1)
candidate_for_duel2 = population[index2]
if candidate_for_duel2 not in individuals_for_duel1 and candidate_for_duel2 not in individuals_for_duel2:
individuals_for_duel2.append(candidate_for_duel2)
winner_of_duel1 = max(individuals_for_duel1, key=lambda x: x[0])
winner_of_duel2 = max(individuals_for_duel2, key=lambda x: x[0])
return winner_of_duel1, winner_of_duel2
def edge_recombination_crossover(parent1, parent2):
dict_of_neighbors = generate_dict_of_neighbors(parent1, parent2)
gen_index = random.randint(0, len(parent1) - 1)
gen = parent1[gen_index]
child = []
while True:
child.append(gen)
if len(child) == len(parent1):
return child
for key in dict_of_neighbors.keys():
if gen in dict_of_neighbors[key]:
dict_of_neighbors[key].remove(gen)
if not dict_of_neighbors[gen]:
while True:
# new_gen = random.randint(parent1[0], parent1[-1])
new_gen_index = random.randint(0, len(parent1) - 1)
new_gen = parent1[new_gen_index]
if new_gen not in child:
break
else:
new_gen = dict_of_neighbors[gen][0]
best_neighbor = len(dict_of_neighbors[new_gen])
for neighbor in dict_of_neighbors[gen][1:]:
possible_best_neighbor = len(dict_of_neighbors[neighbor])
if possible_best_neighbor <= best_neighbor:
best_neighbor = possible_best_neighbor
new_gen = neighbor
gen = new_gen
def generate_dict_of_neighbors(parent1, parent2):
dict_of_neighbors = {}
for i in range(0, len(parent1)):
list_of_neighbors = []
element = parent1[i]
if i == 0:
left_neighbor1 = parent1[-1]
right_neighbor1 = parent1[i + 1]
elif i == (len(parent1) - 1):
left_neighbor1 = parent1[i - 1]
right_neighbor1 = parent1[0]
else:
left_neighbor1 = parent1[i - 1]
right_neighbor1 = parent1[i + 1]
list_of_neighbors.extend([left_neighbor1, right_neighbor1])
index = parent2.index(element)
if index == 0:
left_neighbor2 = parent2[-1]
right_neighbor2 = parent2[index + 1]
elif index == (len(parent2) - 1):
left_neighbor2 = parent2[index - 1]
right_neighbor2 = parent2[0]
else:
left_neighbor2 = parent2[index - 1]
right_neighbor2 = parent2[index + 1]
if left_neighbor2 not in list_of_neighbors:
list_of_neighbors.append(left_neighbor2)
if right_neighbor2 not in list_of_neighbors:
list_of_neighbors.append(right_neighbor2)
dict_of_neighbors[element] = list_of_neighbors
return dict_of_neighbors
def mutation_function(population, travel_map):
mutation_percentage = random.random()
if mutation_percentage <= PERCENT_OF_MUTATION:
count_individual_for_mutation = round(len(population) * mutation_percentage)
mutants = set()
for i in range(0, count_individual_for_mutation):
while True:
individual_for_mutation = random.randint(0, len(population) - 1)
if individual_for_mutation not in mutants:
mutants.add(individual_for_mutation)
candidate_mutant = population[individual_for_mutation]
while True:
chromosome1 = random.randint(0, len(candidate_mutant[1]) - 1)
chromosome2 = random.randint(0, len(candidate_mutant[1]) - 1)
if chromosome1 != chromosome2:
candidate_mutant[1][chromosome1], candidate_mutant[1][chromosome2] = candidate_mutant[1][chromosome2], candidate_mutant[1][chromosome1]
candidate_mutant_priority = adaptation_function(candidate_mutant[1], travel_map)
mutant = (candidate_mutant_priority, candidate_mutant[1])
if mutant not in population:
population[individual_for_mutation] = mutant
break
break

Binary file not shown.

View File

@ -56,14 +56,11 @@ def Fill(bool):
travel.points_coord.append(field.small_field_canvas.coords(field.canvas_small_images[0])) travel.points_coord.append(field.small_field_canvas.coords(field.canvas_small_images[0]))
travel.points_coord.extend(field.mines_coord) travel.points_coord.extend(field.mines_coord)
print(travel.points_coord)
for i in range(0, len(travel.points_coord)): for i in range(0, len(travel.points_coord)):
travel.points_map[i + 1] = travel.points_coord[i] travel.points_map[i + 1] = travel.points_coord[i]
# print(travel.points_map)
# key = list(travel.points_map.keys()) print(travel.points_map)
# print(key)
tr.genetic_algorithm(travel.points_map)
for i in range(0, len(field.canvas_small_images)): for i in range(0, len(field.canvas_small_images)):
@ -202,71 +199,128 @@ def create_action_list(states, index):
create_action_list(states, states.index(state_parent)) create_action_list(states, states.index(state_parent))
def MouseClickEvent(event): def MouseClickEvent(track):
global fringe global fringe
global explored global explored
global action_list global action_list
start_position = field.small_field_canvas.coords(player.image_canvas_id) print("The best individual is: {} {}".format(track[1], track[0]))
end_position = [] for point in range(0, len(track[1]) + 1):
start_position = field.small_field_canvas.coords(player.image_canvas_id)
if point == len(track[1]):
end_position = travel.points_map[1]
else:
end_position = travel.points_map[track[1][point]]
# print("Pierwsza pozycja: {} {}".format(start_position[0], start_position[1])) node = nd.Node()
if len(fringe) == 0:
node.state.coord = start_position
node.state.direction = "east"
else:
states = []
for k in range(0, len(fringe)):
new_state = fringe[k].state.coord
states.append(new_state)
start_node = fringe[-1]
for i in range(0, len(field.canvas_small_images)): node.state.coord = start_node.state.coord
img_coords = field.small_field_canvas.coords(field.canvas_small_images[i]) node.state.direction = start_node.state.direction
if (img_coords[0] <= event.x and event.x <= img_coords[0] + IMAGE_SIZE) and (img_coords[1] <= event.y and event.y <= img_coords[1] + IMAGE_SIZE):
end_position = img_coords
print("Color cost: ", field.cell_expense[i])
# if len(end_position) == 2: fringe.clear()
# print("Koncowa pozycja: {} {}".format(end_position[0], end_position[1])) explored.clear()
action_list.clear()
fringe = nd.graph_search_A(fringe, explored, node.state, end_position)
# fringe = nd.graph_search(fringe, explored, node.state, end_position)
node = nd.Node()
if len(fringe) == 0:
node.state.coord = start_position
node.state.direction = "east"
else:
states = [] states = []
for k in range(0, len(fringe)): goal_all = []
new_state = fringe[k].state.coord for i in range(0, len(fringe)):
new_state = [fringe[i].state.coord, fringe[i].state.direction]
states.append(new_state) states.append(new_state)
start_node = fringe[-1] if end_position[0] == fringe[i].state.coord[0] and end_position[1] == fringe[i].state.coord[1]:
goal_all.append(fringe[i])
node.state.coord = start_node.state.coord elem_min = goal_all[0]
node.state.direction = start_node.state.direction for i in range(1, len(goal_all)):
if elem_min.priority > goal_all[i].priority:
fringe.clear() elem_min = goal_all[i]
explored.clear() index = fringe.index(elem_min)
action_list.clear() fringe = fringe[:index + 1]
fringe = nd.graph_search_A(fringe, explored, node.state, end_position)
# fringe = nd.graph_search(fringe, explored, node.state, end_position)
states = [] create_action_list(states, -1)
goal_all = []
for i in range(0, len(fringe)):
new_state = [fringe[i].state.coord, fringe[i].state.direction]
states.append(new_state)
if end_position[0] == fringe[i].state.coord[0] and end_position[1] == fringe[i].state.coord[1]:
goal_all.append(fringe[i])
elem_min = goal_all[0] # for i in range(0, len(fringe)):
for i in range(1, len(goal_all)): # print('Node{} = State: {} {}, Parent: {} {} {}, Action: {}'.format(i + 1, fringe[i].state.coord, fringe[i].state.direction, fringe[i].parent[0], fringe[i].parent[1], fringe[i].parent[2], fringe[i].action))
if elem_min.priority > goal_all[i].priority:
elem_min = goal_all[i]
index = fringe.index(elem_min)
fringe = fringe[:index + 1]
create_action_list(states, -1) # print(action_list)
# Start moving
AutoMove()
DrawFlag()
time.sleep(SLEEP_AFTER_CHECK_MINE)
# start_position = field.small_field_canvas.coords(player.image_canvas_id)
# end_position = []
#
# # print("Pierwsza pozycja: {} {}".format(start_position[0], start_position[1]))
#
# for i in range(0, len(field.canvas_small_images)):
# img_coords = field.small_field_canvas.coords(field.canvas_small_images[i])
# if (img_coords[0] <= event.x and event.x <= img_coords[0] + IMAGE_SIZE) and (img_coords[1] <= event.y and event.y <= img_coords[1] + IMAGE_SIZE):
# end_position = img_coords
# print("Color cost: ", field.cell_expense[i])
#
# # if len(end_position) == 2:
# # print("Koncowa pozycja: {} {}".format(end_position[0], end_position[1]))
#
# node = nd.Node()
# if len(fringe) == 0:
# node.state.coord = start_position
# node.state.direction = "east"
# else:
# states = []
# for k in range(0, len(fringe)):
# new_state = fringe[k].state.coord
# states.append(new_state)
# start_node = fringe[-1]
#
# node.state.coord = start_node.state.coord
# node.state.direction = start_node.state.direction
#
# fringe.clear()
# explored.clear()
# action_list.clear()
# fringe = nd.graph_search_A(fringe, explored, node.state, end_position)
# # fringe = nd.graph_search(fringe, explored, node.state, end_position)
#
# states = []
# goal_all = []
# for i in range(0, len(fringe)): # for i in range(0, len(fringe)):
# print('Node{} = State: {} {}, Parent: {} {} {}, Action: {}'.format(i + 1, fringe[i].state.coord, fringe[i].state.direction, fringe[i].parent[0], fringe[i].parent[1], fringe[i].parent[2], fringe[i].action)) # new_state = [fringe[i].state.coord, fringe[i].state.direction]
# states.append(new_state)
print(action_list) # if end_position[0] == fringe[i].state.coord[0] and end_position[1] == fringe[i].state.coord[1]:
# goal_all.append(fringe[i])
#
# elem_min = goal_all[0]
# Start moving # for i in range(1, len(goal_all)):
AutoMove() # if elem_min.priority > goal_all[i].priority:
# elem_min = goal_all[i]
# index = fringe.index(elem_min)
# fringe = fringe[:index + 1]
#
# create_action_list(states, -1)
#
# # for i in range(0, len(fringe)):
# # print('Node{} = State: {} {}, Parent: {} {} {}, Action: {}'.format(i + 1, fringe[i].state.coord, fringe[i].state.direction, fringe[i].parent[0], fringe[i].parent[1], fringe[i].parent[2], fringe[i].action))
#
# print(action_list)
#
#
#
# # Start moving
# AutoMove()
def PutMines(mines_array): def PutMines(mines_array):
@ -341,19 +395,19 @@ def DrawFlag():
field.small_field_canvas.create_image(player.current_x, player.current_y, anchor=NW, image=field.flag_img) field.small_field_canvas.create_image(player.current_x, player.current_y, anchor=NW, image=field.flag_img)
def IsItMine(): # def IsItMine():
visited = 0 # 0 - not mine; 1 - on this mine for the first time; 2 - already been on this mine # visited = 0 # 0 - not mine; 1 - on this mine for the first time; 2 - already been on this mine
#
# Checks if the player is on the mine # # Checks if the player is on the mine
for i in field.mines_coord: # for i in field.mines_coord:
if i[0] == player.current_x and i[1] == player.current_y: # if i[0] == player.current_x and i[1] == player.current_y:
visited = 1 # visited = 1
# Checks if the player has already been on this mine # # Checks if the player has already been on this mine
for y in field.visited_mines: # for y in field.visited_mines:
if y[0] == player.current_x and y[1] == player.current_y: # if y[0] == player.current_x and y[1] == player.current_y:
visited = 2 # visited = 2
if visited == 1: # if visited == 1:
DrawFlag() # DrawFlag()
def AutoMove(): def AutoMove():
@ -363,7 +417,7 @@ def AutoMove():
# Move once # Move once
Action(action) Action(action)
# Check if player on mine and if yes, draw flag # Check if player on mine and if yes, draw flag
IsItMine() # IsItMine()
# Update main window # Update main window
field.win.update() field.win.update()
@ -376,13 +430,13 @@ def DrawRectangle():
color = None color = None
# Chose color for rectangle # Chose color for rectangle
for i in range(len(field.cell_expense)): for i in range(len(field.cell_expense)):
if field.cell_expense[i] == 10: if field.cell_expense[i] == standard_cell_cost:
color = "None" color = "None"
elif field.cell_expense[i] == 20: elif field.cell_expense[i] == sand_cell_cost:
color = "yellow" color = "yellow"
elif field.cell_expense[i] == 40: elif field.cell_expense[i] == water_cell_cost:
color = "dodger blue" color = "dodger blue"
elif field.cell_expense[i] == 5: elif field.cell_expense[i] == swamp_cell_cost:
color = "green4" color = "green4"
if color != "None": if color != "None":
field.small_field_canvas.create_rectangle(x, y, x + IMAGE_SIZE + 2, y + IMAGE_SIZE + 2, width=2, outline=color) field.small_field_canvas.create_rectangle(x, y, x + IMAGE_SIZE + 2, y + IMAGE_SIZE + 2, width=2, outline=color)
@ -415,8 +469,15 @@ def CostingOfCells():
def click_button(): def click_button():
btn.destroy() btn.destroy()
label = Label(field.win, text='Prepod lox\nPrepod lox\nPrepod lox\nPrepod lox\nPrepod lox\nPrepod lox\n', fg='black') label = Label(field.win, text="Wait... AI conquers the world!", fg='black')
label.place(x=50, y=570) label.place(x=50, y=570)
field.win.update()
track = tr.genetic_algorithm(travel.points_map)
track[1].remove(1)
label.config(text=track[1])
field.win.update()
MouseClickEvent(track)
def main(): def main():
@ -433,7 +494,7 @@ def main():
foreground="#ccc", # цвет текста foreground="#ccc", # цвет текста
padx="20", # отступ от границ до содержимого по горизонтали padx="20", # отступ от границ до содержимого по горизонтали
pady="8", # отступ от границ до содержимого по вертикали pady="8", # отступ от границ до содержимого по вертикали
font="16", # высота шрифта font="24", # высота шрифта
command=click_button command=click_button
) )
@ -478,7 +539,7 @@ def main():
# Rectangle() # Rectangle()
# Binding keyboard press to function # Binding keyboard press to function
# field.win.bind("<Key>", Action) # field.win.bind("<Key>", Action)
field.small_field_canvas.bind("<Button-1>", MouseClickEvent) # field.small_field_canvas.bind("<Button-1>", MouseClickEvent)
# Starting mainloop for window # Starting mainloop for window
field.win.mainloop() field.win.mainloop()

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -9,11 +9,11 @@ WINDOW_Y = 950
# Size of small image # Size of small image
IMAGE_SIZE = 50 IMAGE_SIZE = 50
MIN_AMOUNT_OF_MINES = 0 MIN_AMOUNT_OF_MINES = 6
MAX_AMOUNT_OF_MINES = 11 MAX_AMOUNT_OF_MINES = 11
AMOUNT_OF_MINES = random.randint(MIN_AMOUNT_OF_MINES, MAX_AMOUNT_OF_MINES) AMOUNT_OF_MINES = random.randint(MIN_AMOUNT_OF_MINES, MAX_AMOUNT_OF_MINES)
DELAY_TIME = 0.5 DELAY_TIME = 0.2
STEP = IMAGE_SIZE + 5 STEP = IMAGE_SIZE + 5
@ -26,7 +26,13 @@ amount_of_water_cells = 10
water_cell_cost = 40 water_cell_cost = 40
amount_of_swamp_cells = 10 amount_of_swamp_cells = 10
swamp_cell_cost = 5 swamp_cell_cost = 80
x_start = 5 x_start = 5
y_start = 5 y_start = 5
NUMBER_OF_INDIVIDUALS_FOR_DUEL = 4
NUMBER_OF_POINTS_PERMUTATION = 10
PERCENT_OF_MUTATION = 0.01
PERCENT_OF_OUTGOING_INDIVIDUALS = 0.03
SLEEP_AFTER_CHECK_MINE = 1