2021-06-13 16:28:40 +02:00
|
|
|
import astar
|
|
|
|
import cart
|
|
|
|
import definitions
|
|
|
|
import graph
|
|
|
|
import map
|
|
|
|
import os
|
|
|
|
import pickle
|
|
|
|
import plant
|
|
|
|
import pygame
|
|
|
|
import random
|
|
|
|
import station
|
|
|
|
import treelearn
|
2021-06-18 12:16:19 +02:00
|
|
|
|
|
|
|
|
2021-06-13 16:28:40 +02:00
|
|
|
def create_genetic_algorithm():
|
2021-06-18 12:16:19 +02:00
|
|
|
if os.path.exists(
|
|
|
|
"resources/genetic_algorithm/optimalastar.pkl"): # jeżeli algorytm genetyczny utworzył plik wcześcniej to odczytaj
|
2021-06-18 12:07:34 +02:00
|
|
|
astar_costs = pickle.load(open(os.path.join('resources/genetic_algorithm', "optimalastar.pkl"), "rb"))
|
2021-06-18 12:16:19 +02:00
|
|
|
# kolejność alfabetyczna
|
2021-06-13 16:28:40 +02:00
|
|
|
definitions.BEETROOTS_ADULT_COST = astar_costs[0]
|
|
|
|
definitions.BEETROOTS_GROW_COST = astar_costs[1]
|
|
|
|
definitions.CARROTS_ADULT_COST = astar_costs[2]
|
|
|
|
definitions.CARROTS_GROW_COST = astar_costs[3]
|
|
|
|
definitions.DIRT_COST = astar_costs[4]
|
|
|
|
definitions.FARMLAND_DRY_COST = astar_costs[5]
|
|
|
|
definitions.FARMLAND_WET_COST = astar_costs[6]
|
|
|
|
definitions.FLOWER_DANDELION_COST = astar_costs[7]
|
|
|
|
definitions.POTATOES_ADULT_COST = astar_costs[8]
|
|
|
|
definitions.POTATOES_GROW_COST = astar_costs[9]
|
|
|
|
definitions.STATION_COST = astar_costs[10]
|
|
|
|
definitions.WHEAT_ADULT_COST = astar_costs[11]
|
|
|
|
definitions.WHEAT_GROW_COST = astar_costs[12]
|
2021-06-18 12:16:19 +02:00
|
|
|
else: # w przeciwnym razie ucz algorytmem genetycznym
|
|
|
|
astar_costs = [definitions.BEETROOTS_ADULT_COST, definitions.BEETROOTS_GROW_COST,
|
|
|
|
definitions.CARROTS_ADULT_COST, definitions.CARROTS_GROW_COST, definitions.DIRT_COST,
|
|
|
|
definitions.FARMLAND_DRY_COST, definitions.FARMLAND_WET_COST, definitions.FLOWER_DANDELION_COST,
|
|
|
|
definitions.POTATOES_ADULT_COST, definitions.POTATOES_GROW_COST, definitions.STATION_COST,
|
|
|
|
definitions.WHEAT_ADULT_COST, definitions.WHEAT_GROW_COST] # kolejność alfabetyczna
|
2021-06-18 12:07:34 +02:00
|
|
|
astar_costs = evolve(astar_costs)
|
|
|
|
pickle.dump(astar_costs, open(os.path.join('resources/genetic_algorithm', "optimalastar.pkl"), "wb"))
|
2021-06-18 12:16:19 +02:00
|
|
|
|
|
|
|
|
2021-06-18 12:07:34 +02:00
|
|
|
def evolve(astar_costs):
|
2021-06-18 12:16:19 +02:00
|
|
|
first_generation = [] # pierwsza generacja
|
|
|
|
overall_solutions = [] # rozwiązania końcowe
|
|
|
|
solutions = [] # rozwiązania danej generacji
|
|
|
|
for individual in range(
|
|
|
|
definitions.GENETIC_ALGORITHM_NUMBER_OF_INDIVIDUALS_ZERO): # liczba osobników pierwszej generacji
|
2021-06-18 12:07:34 +02:00
|
|
|
for _ in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT):
|
|
|
|
first_generation.append(random.uniform(0, 10))
|
2021-06-18 12:16:19 +02:00
|
|
|
solutions.append(first_generation) # generowanie losowych kosztów pól dla pierwszej generacji
|
|
|
|
for gen in range(definitions.GENETIC_ALGORITHM_NUMBER_OF_GENERATIONS): # liczba generacji
|
2021-06-18 12:07:34 +02:00
|
|
|
print(f"=== Generation {gen + 1} ===")
|
2021-06-18 12:16:19 +02:00
|
|
|
ranked_solutions = [] # rozwiązania z wynikiem
|
2021-06-18 12:07:34 +02:00
|
|
|
index = 0
|
2021-06-18 12:16:19 +02:00
|
|
|
for s in solutions: # przypisanie rozwiązaniom wyniku funkcji fitness
|
2021-06-18 12:07:34 +02:00
|
|
|
ranked_solutions.append((fitness(s, index), s))
|
|
|
|
index = index + 1
|
|
|
|
ranked_solutions.sort()
|
|
|
|
print(f"=== Gen {gen + 1} best solution ===")
|
|
|
|
print(ranked_solutions[0])
|
|
|
|
overall_solutions.append(ranked_solutions[0])
|
2021-06-18 12:16:19 +02:00
|
|
|
# TODO warunek stopu
|
|
|
|
best_solutions = ranked_solutions[
|
|
|
|
:definitions.GENETIC_ALGORITHM_NUMBER_OF_BEST_INDIVIDUALS] # najlepsze osobniki w danej generacji
|
2021-06-18 12:07:34 +02:00
|
|
|
elements = []
|
|
|
|
for element in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT):
|
|
|
|
elems = []
|
|
|
|
elements.append(elems)
|
|
|
|
for solution in best_solutions:
|
|
|
|
for element in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT):
|
|
|
|
elements[element].append(solution[1][element])
|
2021-06-18 12:16:19 +02:00
|
|
|
next_generation = [] # nowa ganeracja
|
2021-06-18 12:07:34 +02:00
|
|
|
e = []
|
2021-06-18 12:16:19 +02:00
|
|
|
for individual in range(
|
|
|
|
definitions.GENETIC_ALGORITHM_NUMBER_OF_INDIVIDUALS): # liczba osobników w kolejnej generacji
|
2021-06-18 12:07:34 +02:00
|
|
|
for el in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT):
|
2021-06-18 12:16:19 +02:00
|
|
|
# mutacje
|
2021-06-18 12:07:34 +02:00
|
|
|
e.append(random.choice(elements[el]) * random.uniform(0.99, 1.01))
|
|
|
|
next_generation.append(e)
|
2021-06-18 12:16:19 +02:00
|
|
|
solutions = next_generation # zastąpnienie osobników nową generacją
|
2021-06-18 12:07:34 +02:00
|
|
|
overall_solutions.sort()
|
2021-06-18 12:16:19 +02:00
|
|
|
for _ in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): # przyspianie finalnych kosztów astara
|
2021-06-18 12:07:34 +02:00
|
|
|
astar_costs[_] = overall_solutions[0][1][_]
|
|
|
|
return astar_costs
|
2021-06-18 12:16:19 +02:00
|
|
|
|
|
|
|
|
2021-06-18 12:07:34 +02:00
|
|
|
def fitness(astar_costs, index):
|
|
|
|
ans = harvest(astar_costs, index)
|
2021-06-18 12:16:19 +02:00
|
|
|
if ans == 0: # TODO
|
2021-06-13 16:28:40 +02:00
|
|
|
return 0
|
|
|
|
else:
|
|
|
|
return 1 / ans
|
2021-06-18 12:16:19 +02:00
|
|
|
|
|
|
|
|
2021-06-18 12:07:34 +02:00
|
|
|
def harvest(astar_costs, index):
|
2021-06-18 12:16:19 +02:00
|
|
|
# kolejność alfabetyczna
|
2021-06-13 16:28:40 +02:00
|
|
|
definitions.BEETROOTS_ADULT_COST = astar_costs[0]
|
|
|
|
definitions.BEETROOTS_GROW_COST = astar_costs[1]
|
|
|
|
definitions.CARROTS_ADULT_COST = astar_costs[2]
|
|
|
|
definitions.CARROTS_GROW_COST = astar_costs[3]
|
|
|
|
definitions.DIRT_COST = astar_costs[4]
|
|
|
|
definitions.FARMLAND_DRY_COST = astar_costs[5]
|
|
|
|
definitions.FARMLAND_WET_COST = astar_costs[6]
|
|
|
|
definitions.FLOWER_DANDELION_COST = astar_costs[7]
|
|
|
|
definitions.POTATOES_ADULT_COST = astar_costs[8]
|
|
|
|
definitions.POTATOES_GROW_COST = astar_costs[9]
|
|
|
|
definitions.STATION_COST = astar_costs[10]
|
|
|
|
definitions.WHEAT_ADULT_COST = astar_costs[11]
|
|
|
|
definitions.WHEAT_GROW_COST = astar_costs[12]
|
2021-06-18 12:16:19 +02:00
|
|
|
# tworzenie podstawowych obiektów
|
2021-06-13 16:28:40 +02:00
|
|
|
map1 = map.Map([])
|
|
|
|
map1.create_base_map()
|
2021-06-18 12:16:19 +02:00
|
|
|
move_list = ["rotate_left", "move", "move", "move", "move", "move", "move", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "rotate_left", "rotate_left", "rotate_left", "move", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "rotate_left", "rotate_left", "rotate_left", "move", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "move", "rotate_left", "rotate_left", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "rotate_left", "move", "move", "rotate_left", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "move", "rotate_left", "rotate_left", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "rotate_left", "move", "move", "move", "rotate_left", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "rotate_left", "move", "move", "rotate_left", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "rotate_left", "move",
|
|
|
|
"rotate_left", "rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "rotate_left",
|
|
|
|
"rotate_left", "rotate_left", "move", "rotate_left", "rotate_left", "rotate_left",
|
|
|
|
"move"] # początkowe ruchy
|
|
|
|
amount_of_seeds_dict = {"beetroot": definitions.CART_AMOUNT_OF_SEEDS_EACH_TYPE,
|
|
|
|
"carrot": definitions.CART_AMOUNT_OF_SEEDS_EACH_TYPE,
|
|
|
|
"potato": definitions.CART_AMOUNT_OF_SEEDS_EACH_TYPE,
|
|
|
|
"wheat": definitions.CART_AMOUNT_OF_SEEDS_EACH_TYPE}
|
2021-06-13 16:28:40 +02:00
|
|
|
collected_plants_dict_cart = {"beetroot": 0, "carrot": 0, "potato": 0, "wheat": 0}
|
|
|
|
collected_plants_dict_station = {"beetroot": 0, "carrot": 0, "potato": 0, "wheat": 0}
|
2021-06-18 12:16:19 +02:00
|
|
|
fertilizer_dict = {"beetroot": definitions.CART_FERTILIZER, "carrot": definitions.CART_FERTILIZER,
|
|
|
|
"potato": definitions.CART_FERTILIZER, "wheat": definitions.CART_FERTILIZER}
|
2021-06-13 16:28:40 +02:00
|
|
|
station1 = station.Station(collected_plants_dict_station)
|
2021-06-18 12:16:19 +02:00
|
|
|
cart1 = cart.Cart(amount_of_seeds_dict, collected_plants_dict_cart, definitions.CART_DIRECTION_WEST,
|
|
|
|
fertilizer_dict, definitions.CART_FUEL, definitions.CART_WATER_LEVEL, 0 * definitions.BLOCK_SIZE,
|
|
|
|
0 * definitions.BLOCK_SIZE)
|
2021-06-13 16:28:40 +02:00
|
|
|
cart1_rect = pygame.Rect(cart1.get_x(), cart1.get_y(), definitions.BLOCK_SIZE, definitions.BLOCK_SIZE)
|
2021-06-18 12:16:19 +02:00
|
|
|
tree = treelearn.treelearn() # tworzenie drzewa decyzyjnego
|
|
|
|
decision = [0] # początkowa decyzja o braku powrotu do stacji (0)
|
2021-06-13 16:28:40 +02:00
|
|
|
grow_flower_dandelion = False
|
|
|
|
random_movement = False
|
2021-06-18 12:16:19 +02:00
|
|
|
for run in range(definitions.GENETIC_ALGORITHM_NUMBER_OF_CART_MOVES): # liczba ruchów wózka
|
|
|
|
if not move_list: # jeżeli są jakieś ruchy do wykonania w move_list
|
2021-06-13 16:28:40 +02:00
|
|
|
grow_flower_dandelion = True
|
2021-06-18 12:16:19 +02:00
|
|
|
istate = graph.Istate(cart1.get_direction(), cart1.get_x() / definitions.BLOCK_SIZE,
|
|
|
|
cart1.get_y() / definitions.BLOCK_SIZE) # stan początkowy wózka (jego orientacja oraz jego aktualne miejsce)
|
|
|
|
if plant.Plant.if_any_mature_plant(map1) is True: # jeżeli istnieje jakaś dojrzała roślina
|
2021-06-13 16:28:40 +02:00
|
|
|
random_movement = False
|
2021-06-18 12:16:19 +02:00
|
|
|
if decision == [0]: # jeżeli decyzja jest 0 (brak powrotu do stacji) to uprawiaj pole
|
|
|
|
move_list = (
|
|
|
|
astar.graphsearch([], astar.f, [], plant.Plant.get_closest_mature_plant(istate, map1), istate,
|
|
|
|
map1, graph.succ)) # lista z ruchami, które należy po kolei wykonać, astar
|
|
|
|
else: # jeżeli decyzja jest 1 (powrót do stacji) to wróć do stacji uzupełnić zapasy
|
|
|
|
move_list = (graph.graphsearch([], [], (0, 0), istate,
|
|
|
|
graph.succ)) # lista z ruchami, które należy po kolei wykonać, graphsearch
|
2021-06-13 16:28:40 +02:00
|
|
|
else:
|
|
|
|
random_movement = True
|
2021-06-18 12:16:19 +02:00
|
|
|
elif move_list: # jeżeli move_list nie jest pusta
|
|
|
|
cart1.handle_movement(cart1_rect,
|
|
|
|
move_list.pop(0)) # wykonaj kolejny ruch oraz zdejmij ten ruch z początku listy
|
2021-06-13 16:28:40 +02:00
|
|
|
if random_movement is True:
|
2021-06-18 12:16:19 +02:00
|
|
|
cart1.handle_movement_random(cart1_rect) # wykonuj losowe ruchy
|
2021-06-13 16:28:40 +02:00
|
|
|
if grow_flower_dandelion is True:
|
2021-06-18 12:16:19 +02:00
|
|
|
plant.Plant.grow_flower_dandelion(map1) # losuj urośnięcie kwiatka dandeliona
|
|
|
|
cart1.do_work(cart1_rect, map1, station1) # wykonaj pracę na danym polu
|
|
|
|
decision = treelearn.make_decision(cart1.get_all_amount_of_seeds(), cart1.get_all_collected_plants(),
|
|
|
|
cart1.get_all_fertilizer(), cart1.get_fuel(), tree,
|
|
|
|
cart1.get_water_level()) # podejmij decyzję czy wracać do stacji (0 : NIE, 1 : TAK)
|
|
|
|
plant.Plant.grow_plants(map1) # zwiększ poziom dojrzałości roślin
|
2021-06-18 12:07:34 +02:00
|
|
|
print("individual no.", index + 1, "score:", station1.get_all_collected_plants())
|
2021-06-18 12:16:19 +02:00
|
|
|
return station1.get_all_collected_plants()
|