diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 699e73b..46c7152 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -3,86 +3,19 @@ + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + @@ -323,10 +258,10 @@ - + - + diff --git a/astar.py b/astar.py index b035171..e12cfe6 100644 --- a/astar.py +++ b/astar.py @@ -1,75 +1,107 @@ from operator import itemgetter import cart import copy -class Istate: #stan początkowy wózka (strona, w którą patrzy, miejsce, w którym się on znajduje) + + +class Istate: # stan początkowy wózka (strona, w którą patrzy, miejsce, w którym się on znajduje) def __init__(self, direction, x, y): self.direction = direction self.x = x self.y = y + def get_direction(self): return self.direction + def set_direction(self, direction): self.direction = direction + def get_x(self): return self.x + def set_x(self, x): self.x = x + def get_y(self): return self.y + def set_y(self, y): self.y = y -class Node: #wierzchołek grafu + + +class Node: # wierzchołek grafu def __init__(self, action, direction, parent, x, y): - self.action = action #akcja jaką ma wykonać (obróc się w lewo, obróć się w prawo, ruch do przodu) + self.action = action # akcja jaką ma wykonać (obróc się w lewo, obróć się w prawo, ruch do przodu) self.direction = direction - self.parent = parent #ojciec wierzchołka + self.parent = parent # ojciec wierzchołka self.x = x self.y = y + def get_action(self): return self.action + def set_action(self, action): self.action = action + def get_direction(self): return self.direction + def set_direction(self, direction): self.direction = direction + def get_parent(self): return self.parent + def set_parent(self, parent): self.parent = parent + def get_x(self): return self.x + def set_x(self, x): self.x = x + def get_y(self): return self.y + def set_y(self, y): self.y = y -def cost(map, node): #funkcja kosztu : ile kosztuje przejechanie przez dane pole + + +def cost(map, node): # funkcja kosztu : ile kosztuje przejechanie przez dane pole cost = 0 - while(node.get_parent() != None): + while (node.get_parent() != None): cost = cost + map.get_field_cost(int(node.get_x()), int(node.get_y())) + 1 node = node.get_parent() return cost -def f(goaltest, map, node): #funkcja zwracająca sumę funkcji kosztu oraz heurestyki + + +def f(goaltest, map, node): # funkcja zwracająca sumę funkcji kosztu oraz heurestyki return cost(map, node) + heuristic(goaltest, node) -def goal_test(elem, goaltest): #funkcja sprawdzająca czy położenie wózka równa się położeniu punktu docelowego, jeśli tak zwraca prawdę, w przeciwnym wypadku fałsz + + +def goal_test(elem, + goaltest): # funkcja sprawdzająca czy położenie wózka równa się położeniu punktu docelowego, jeśli tak zwraca prawdę, w przeciwnym wypadku fałsz if elem.get_x() == goaltest[0] and elem.get_y() == goaltest[1]: return True else: return False -def graphsearch(explored, f, fringe, goaltest, istate, map, succ): #przeszukiwanie grafu wszerz - node = Node(None, istate.get_direction(), None, istate.get_x(), istate.get_y()) #wierzchołek początkowy, stworzony ze stanu początkowego wózka - fringe.append((node, 0)) #wierzchołki do odwiedzenia z priorytetem + + +def graphsearch(explored, f, fringe, goaltest, istate, map, succ): # przeszukiwanie grafu wszerz + node = Node(None, istate.get_direction(), None, istate.get_x(), + istate.get_y()) # wierzchołek początkowy, stworzony ze stanu początkowego wózka + fringe.append((node, 0)) # wierzchołki do odwiedzenia z priorytetem while True: if not fringe: return False - elem = fringe.pop(0) #zdejmujemy wierzchołek z kolejki fringe i rozpatrujemy go + elem = fringe.pop(0) # zdejmujemy wierzchołek z kolejki fringe i rozpatrujemy go temp = copy.copy(elem[0]) - if goal_test(elem[0], goaltest) is True: #jeżeli osiągniemy cel w trakcie przeszukiwania grafu wszerz (wjedziemy na pole docelowe) : zwracamy listę ruchów, po których wykonaniu dotrzemy na miejsce + if goal_test(elem[0], + goaltest) is True: # jeżeli osiągniemy cel w trakcie przeszukiwania grafu wszerz (wjedziemy na pole docelowe) : zwracamy listę ruchów, po których wykonaniu dotrzemy na miejsce return print_moves(elem[0]) - explored.append(elem) #dodajemy wierzchołek do listy wierzchołków odwiedzonych - for (action, state) in succ(temp): #iterujemy po wszystkich możliwych akcjach i stanach otrzymanych dla danego wierzchołka grafu + explored.append(elem) # dodajemy wierzchołek do listy wierzchołków odwiedzonych + for (action, state) in succ( + temp): # iterujemy po wszystkich możliwych akcjach i stanach otrzymanych dla danego wierzchołka grafu fringe_tuple = [] fringe_tuple_prio = [] explored_tuple = [] @@ -78,31 +110,40 @@ def graphsearch(explored, f, fringe, goaltest, istate, map, succ): #przeszukiwan fringe_tuple_prio.append(((x.get_direction(), x.get_x(), x.get_y()), y)) for (x, y) in explored: explored_tuple.append((x.get_direction(), x.get_x(), x.get_y())) - x = Node(action, state[0], elem[0], state[1], state[2]) #stworzenie nowego wierzchołka, którego rodzicem jest elem - p = f(goaltest, map, x) #liczy priorytet - if state not in fringe_tuple and state not in explored_tuple: #jeżeli stan nie znajduje się na fringe oraz nie znajduje się w liście wierzchołków odwiedzonych - fringe.append((x, p)) #dodanie wierzchołka na fringe - fringe = sorted(fringe, key=itemgetter(1)) #sortowanie fringe'a według priorytetu + x = Node(action, state[0], elem[0], state[1], + state[2]) # stworzenie nowego wierzchołka, którego rodzicem jest elem + p = f(goaltest, map, x) # liczy priorytet + if state not in fringe_tuple and state not in explored_tuple: # jeżeli stan nie znajduje się na fringe oraz nie znajduje się w liście wierzchołków odwiedzonych + fringe.append((x, p)) # dodanie wierzchołka na fringe + fringe = sorted(fringe, key=itemgetter(1)) # sortowanie fringe'a według priorytetu elif state in fringe_tuple: i = 0 for (state_prio, r) in fringe_tuple_prio: if str(state_prio) == str(state): if r > p: - fringe.insert(i, (x, p)) #zamiana state, który należy do fringe z priorytetem r na state z priorytetem p (niższym) + fringe.insert(i, (x, + p)) # zamiana state, który należy do fringe z priorytetem r na state z priorytetem p (niższym) fringe.pop(i + 1) - fringe = sorted(fringe, key=itemgetter(1)) #sortowanie fringe'a według priorytetu + fringe = sorted(fringe, key=itemgetter(1)) # sortowanie fringe'a według priorytetu break i = i + 1 -def heuristic(goaltest, node): #funkcja heurestyki : oszacowuje koszt osiągnięcia stanu końcowego (droga) + + +def heuristic(goaltest, node): # funkcja heurestyki : oszacowuje koszt osiągnięcia stanu końcowego (droga) return abs(node.get_x() - goaltest[0]) + abs(node.get_y() - goaltest[1]) -def print_moves(elem): #zwraca listę ruchów jakie należy wykonać by dotrzeć do punktu docelowego + + +def print_moves(elem): # zwraca listę ruchów jakie należy wykonać by dotrzeć do punktu docelowego moves_list = [] while (elem.get_parent() != None): moves_list.append(elem.get_action()) elem = elem.get_parent() moves_list.reverse() return moves_list -def succ(elem): #funkcja następnika, przypisuje jakie akcje są możliwe do wykonania na danym polu oraz jaki będzie stan (kierunek, położenie) po wykonaniu tej akcji + + +def succ( + elem): # funkcja następnika, przypisuje jakie akcje są możliwe do wykonania na danym polu oraz jaki będzie stan (kierunek, położenie) po wykonaniu tej akcji actions_list = [] temp = copy.copy(elem.get_direction()) if temp == 1: @@ -128,4 +169,4 @@ def succ(elem): #funkcja następnika, przypisuje jakie akcje są możliwe do wyk actions_list.append(("move", (elem.get_direction(), elem.get_x(), temp_move_south))) elif cart.Cart.is_move_allowed_succ(elem) == "x - 1": actions_list.append(("move", (elem.get_direction(), temp_move_west, elem.get_y()))) - return actions_list \ No newline at end of file + return actions_list diff --git a/cart.py b/cart.py index 4715d9f..5260fd8 100644 --- a/cart.py +++ b/cart.py @@ -1,54 +1,81 @@ import definitions import random + + class Cart: def __init__(self, amount_of_seeds, collected_plants, direction, fertilizer, fuel, water_level, x, y): - self.amount_of_seeds = amount_of_seeds #amount_of_seeds to słownik, przechowuje informacje o posiadanej ilości ziaren dla danej rośliny - self.collected_plants = collected_plants #collected_plants to słownik, przechowuje informacje o zebranych plonach - self.direction = direction #w którą stronę patrzy, zgodnie ze wskazówkami zegara (1 -: godzina 12, 2 : godzina 3, 3 : godzina 6, 4 : godzina 9) - self.fertilizer = fertilizer #fertilizer to słownik, przechowuje informacje o ilości posiadanego nawozu dla konkretnej rośliny - self.fuel = fuel #aktualna ilość paliwa - self.water_level = water_level #aktualna ilość wody do podlewania + self.amount_of_seeds = amount_of_seeds # amount_of_seeds to słownik, przechowuje informacje o posiadanej ilości ziaren dla danej rośliny + self.collected_plants = collected_plants # collected_plants to słownik, przechowuje informacje o zebranych plonach + self.direction = direction # w którą stronę patrzy, zgodnie ze wskazówkami zegara (1 -: godzina 12, 2 : godzina 3, 3 : godzina 6, 4 : godzina 9) + self.fertilizer = fertilizer # fertilizer to słownik, przechowuje informacje o ilości posiadanego nawozu dla konkretnej rośliny + self.fuel = fuel # aktualna ilość paliwa + self.water_level = water_level # aktualna ilość wody do podlewania self.x = x self.y = y - def get_all_amount_of_seeds(self): #zwraca łączną ilość ziaren (suma ziaren dla wszystkich roślin) - return self.amount_of_seeds["beetroot"] + self.amount_of_seeds["carrot"] + self.amount_of_seeds["potato"] + self.amount_of_seeds["wheat"] - def get_amount_of_seeds(self, name): #zwraca łączną ilość ziaren dla podanej rośliny (name) + + def get_all_amount_of_seeds(self): # zwraca łączną ilość ziaren (suma ziaren dla wszystkich roślin) + return self.amount_of_seeds["beetroot"] + self.amount_of_seeds["carrot"] + self.amount_of_seeds["potato"] + \ + self.amount_of_seeds["wheat"] + + def get_amount_of_seeds(self, name): # zwraca łączną ilość ziaren dla podanej rośliny (name) return self.amount_of_seeds[name] - def set_amount_of_seeds(self, name, value): #dla podanej rośliny (name) ustawia łączną ilość ziaren (value) + + def set_amount_of_seeds(self, name, value): # dla podanej rośliny (name) ustawia łączną ilość ziaren (value) self.amount_of_seeds[name] = value - def get_all_collected_plants(self): #zwraca łączną ilość zebranych plonów (suma plonów wszystkich roślin) - return self.collected_plants["beetroot"] + self.collected_plants["carrot"] + self.collected_plants["potato"] + self.collected_plants["wheat"] - def get_collected_plants(self, name): #zwraca łączną ilość zebranych plonów dla podanej rośliny (name) + + def get_all_collected_plants(self): # zwraca łączną ilość zebranych plonów (suma plonów wszystkich roślin) + return self.collected_plants["beetroot"] + self.collected_plants["carrot"] + self.collected_plants["potato"] + \ + self.collected_plants["wheat"] + + def get_collected_plants(self, name): # zwraca łączną ilość zebranych plonów dla podanej rośliny (name) return self.collected_plants[name] - def set_collected_plants(self, name, value): #dla podanej rośliny (name) ustawia łączną ilość zebranych plonów (value) + + def set_collected_plants(self, name, + value): # dla podanej rośliny (name) ustawia łączną ilość zebranych plonów (value) self.collected_plants[name] = value + def get_direction(self): return self.direction + def set_direction(self, direction): self.direction = direction - def get_all_fertilizer(self): #zwraca łączną ilość posiadanego nawozu (suma nawozu dla wszystkich roślin) - return self.fertilizer["beetroot"] + self.fertilizer["carrot"] + self.fertilizer["potato"] + self.fertilizer["wheat"] - def get_fertilizer(self, name): #zwraca łączną ilość posiadanego nawozu dla podanej rośliny (name) + + def get_all_fertilizer(self): # zwraca łączną ilość posiadanego nawozu (suma nawozu dla wszystkich roślin) + return self.fertilizer["beetroot"] + self.fertilizer["carrot"] + self.fertilizer["potato"] + self.fertilizer[ + "wheat"] + + def get_fertilizer(self, name): # zwraca łączną ilość posiadanego nawozu dla podanej rośliny (name) return self.fertilizer[name] - def set_fertilizer(self, name, value): #dla podanej rośliny (name) ustawia ilość posiadanego nawozu (value) + + def set_fertilizer(self, name, value): # dla podanej rośliny (name) ustawia ilość posiadanego nawozu (value) self.fertilizer[name] = value + def get_fuel(self): return self.fuel + def set_fuel(self, fuel): self.fuel = fuel + def get_water_level(self): return self.water_level + def set_water_level(self, water_level): self.water_level = water_level + def get_x(self): return self.x + def set_x(self, x): self.x = x + def get_y(self): return self.y + def set_y(self, y): self.y = y - def do_work(self, cart_rect, map1, station1): #jaką pracę wózek ma wykonać na danym polu, na którym aktualnie przebywa (zmienia stan logiczny danego pola) + + def do_work(self, cart_rect, map1, + station1): # jaką pracę wózek ma wykonać na danym polu, na którym aktualnie przebywa (zmienia stan logiczny danego pola) loop = True if self.get_all_amount_of_seeds() == 0: loop = False @@ -90,19 +117,23 @@ class Cart: field.get_plant().set_name("wheat") field.get_plant().set_state(1) loop = False - elif field.get_plant().get_name() == "beetroot" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.BEETROOTS_MAXIMUM_STATE - definitions.BEETROOTS_GROW_TIME and self.get_fertilizer("beetroot") > 0 and field.get_soil().get_is_fertilized() is False: + elif field.get_plant().get_name() == "beetroot" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.BEETROOTS_MAXIMUM_STATE - definitions.BEETROOTS_GROW_TIME and self.get_fertilizer( + "beetroot") > 0 and field.get_soil().get_is_fertilized() is False: self.set_fertilizer("beetroot", (self.get_fertilizer("beetroot") - 1)) field.get_soil().set_is_fertilized(True) field.get_plant().set_state(field.get_plant().get_state() + definitions.BEETROOTS_GROW_TIME) - elif field.get_plant().get_name() == "carrot" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.CARROTS_MAXIMUM_STATE - definitions.CARROTS_GROW_TIME and self.get_fertilizer("carrot") > 0 and field.get_soil().get_is_fertilized() is False: + elif field.get_plant().get_name() == "carrot" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.CARROTS_MAXIMUM_STATE - definitions.CARROTS_GROW_TIME and self.get_fertilizer( + "carrot") > 0 and field.get_soil().get_is_fertilized() is False: self.set_fertilizer("carrot", (self.get_fertilizer("carrot") - 1)) field.get_soil().set_is_fertilized(True) field.get_plant().set_state(field.get_plant().get_state() + definitions.CARROTS_GROW_TIME) - elif field.get_plant().get_name() == "potato" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.POTATOES_MAXIMUM_STATE - definitions.POTATOES_GROW_TIME and self.get_fertilizer("potato") > 0 and field.get_soil().get_is_fertilized() is False: + elif field.get_plant().get_name() == "potato" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.POTATOES_MAXIMUM_STATE - definitions.POTATOES_GROW_TIME and self.get_fertilizer( + "potato") > 0 and field.get_soil().get_is_fertilized() is False: self.set_fertilizer("potato", (self.get_fertilizer("potato") - 1)) field.get_soil().set_is_fertilized(True) field.get_plant().set_state(field.get_plant().get_state() + definitions.POTATOES_GROW_TIME) - elif field.get_plant().get_name() == "wheat" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.WHEAT_MAXIMUM_STATE - definitions.WHEAT_GROW_TIME and self.get_fertilizer("wheat") > 0 and field.get_soil().get_is_fertilized() is False: + elif field.get_plant().get_name() == "wheat" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.WHEAT_MAXIMUM_STATE - definitions.WHEAT_GROW_TIME and self.get_fertilizer( + "wheat") > 0 and field.get_soil().get_is_fertilized() is False: self.set_fertilizer("wheat", (self.get_fertilizer("wheat") - 1)) field.get_soil().set_is_fertilized(True) field.get_plant().set_state(field.get_plant().get_state() + definitions.WHEAT_GROW_TIME) @@ -134,7 +165,8 @@ class Cart: field.get_soil().set_water_level(False) field.get_soil().set_state(False) self.set_collected_plants("wheat", self.get_collected_plants("wheat") + 1) - def handle_movement(self, cart_rect, move): #odpowiada za poruszanie się wózka po mapie + + def handle_movement(self, cart_rect, move): # odpowiada za poruszanie się wózka po mapie if self.get_fuel() > 0: if move == "move": self.move() @@ -145,7 +177,8 @@ class Cart: self.set_fuel(self.get_fuel() - 1) cart_rect.x = self.get_x() cart_rect.y = self.get_y() - def handle_movement_random(self, cart_rect): #odpowiada za losowe poruszanie się wózka po mapie + + def handle_movement_random(self, cart_rect): # odpowiada za losowe poruszanie się wózka po mapie loop = True while loop and self.get_fuel() > 0: random1 = random.randint(1, 3) @@ -161,7 +194,9 @@ class Cart: self.rotate_right() loop = False self.set_fuel(self.get_fuel() - 1) - def is_move_allowed(self, cart_rect): #sprawdza czy dany ruch, który chce wykonać wózek jest możliwy, zwraca prawdę lub fałsz + + def is_move_allowed(self, + cart_rect): # sprawdza czy dany ruch, który chce wykonać wózek jest możliwy, zwraca prawdę lub fałsz if self.direction == definitions.CART_DIRECTION_EAST and cart_rect.x + definitions.BLOCK_SIZE < definitions.WIDTH_MAP: return True elif self.direction == definitions.CART_DIRECTION_NORTH and cart_rect.y - definitions.BLOCK_SIZE >= 0: @@ -172,8 +207,10 @@ class Cart: return True else: return False + @staticmethod - def is_move_allowed_succ(node): #sprawdza czy dany ruch, który chce wykonać wózek jest możliwy, zwraca pozycje po wykonaniu ruchu, wersja node + def is_move_allowed_succ( + node): # sprawdza czy dany ruch, który chce wykonać wózek jest możliwy, zwraca pozycje po wykonaniu ruchu, wersja node if node.get_direction() == definitions.CART_DIRECTION_EAST and node.get_x() * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE < definitions.WIDTH_MAP: return "x + 1" elif node.get_direction() == definitions.CART_DIRECTION_NORTH and node.get_y() * definitions.BLOCK_SIZE - definitions.BLOCK_SIZE >= 0: @@ -184,6 +221,7 @@ class Cart: return "x - 1" else: return False + def move(self): if self.direction == definitions.CART_DIRECTION_EAST: self.x = self.x + definitions.BLOCK_SIZE @@ -193,24 +231,32 @@ class Cart: self.y = self.y + definitions.BLOCK_SIZE elif self.direction == definitions.CART_DIRECTION_WEST: self.x = self.x - definitions.BLOCK_SIZE + def rotate_left(self): if self.direction == 1: self.direction = 4 else: self.direction = self.direction - 1 + def rotate_right(self): if self.direction == 4: self.direction = 1 else: self.direction = self.direction + 1 - def station_restore(self, station1): #aktualizuje stan stacji pod względem oddanych plonów oraz uzupełnia zapasy wózka - station1.set_collected_plants("beetroot", station1.get_collected_plants("beetroot") + self.get_collected_plants("beetroot")) + + def station_restore(self, + station1): # aktualizuje stan stacji pod względem oddanych plonów oraz uzupełnia zapasy wózka + station1.set_collected_plants("beetroot", + station1.get_collected_plants("beetroot") + self.get_collected_plants("beetroot")) self.set_collected_plants("beetroot", 0) - station1.set_collected_plants("carrot", station1.get_collected_plants("carrot") + self.get_collected_plants("carrot")) + station1.set_collected_plants("carrot", + station1.get_collected_plants("carrot") + self.get_collected_plants("carrot")) self.set_collected_plants("carrot", 0) - station1.set_collected_plants("potato", station1.get_collected_plants("potato") + self.get_collected_plants("potato")) + station1.set_collected_plants("potato", + station1.get_collected_plants("potato") + self.get_collected_plants("potato")) self.set_collected_plants("potato", 0) - station1.set_collected_plants("wheat", station1.get_collected_plants("wheat") + self.get_collected_plants("wheat")) + station1.set_collected_plants("wheat", + station1.get_collected_plants("wheat") + self.get_collected_plants("wheat")) self.set_collected_plants("wheat", 0) self.set_amount_of_seeds("beetroot", definitions.CART_AMOUNT_OF_SEEDS_EACH_TYPE) self.set_amount_of_seeds("carrot", definitions.CART_AMOUNT_OF_SEEDS_EACH_TYPE) @@ -221,4 +267,4 @@ class Cart: self.set_fertilizer("potato", definitions.CART_FERTILIZER) self.set_fertilizer("wheat", definitions.CART_FERTILIZER) self.set_fuel(definitions.CART_FUEL) - self.set_water_level(definitions.CART_WATER_LEVEL) \ No newline at end of file + self.set_water_level(definitions.CART_WATER_LEVEL) diff --git a/definitions.py b/definitions.py index 541f6da..85d1892 100644 --- a/definitions.py +++ b/definitions.py @@ -1,6 +1,7 @@ -#definicje +# definicje import os import pygame + pygame.init() BLOCK_SIZE = 60 BEETROOT = pygame.image.load(os.path.join('resources/images', 'beetroot.png')) @@ -119,4 +120,4 @@ WHEAT_STAGE_6 = pygame.image.load(os.path.join('resources/images', 'wheat_stage_ WHEAT_STAGE_6 = pygame.transform.scale(WHEAT_STAGE_6, (BLOCK_SIZE, BLOCK_SIZE)) WHEAT_STAGE_7 = pygame.image.load(os.path.join('resources/images', 'wheat_stage_7.png')) WHEAT_STAGE_7 = pygame.transform.scale(WHEAT_STAGE_7, (BLOCK_SIZE, BLOCK_SIZE)) -WINDOW = pygame.display.set_mode((WIDTH, HEIGHT)) \ No newline at end of file +WINDOW = pygame.display.set_mode((WIDTH, HEIGHT)) diff --git a/field.py b/field.py index 24d0447..babd454 100644 --- a/field.py +++ b/field.py @@ -1,17 +1,23 @@ class Field: - def __init__(self, plant, rect, soil): #składa się z rośliny oraz gleby, plus koordynaty danego pola + def __init__(self, plant, rect, soil): # składa się z rośliny oraz gleby, plus koordynaty danego pola self.plant = plant self.rect = rect self.soil = soil + def get_plant(self): return self.plant + def set_plant(self, plant): self.plant = plant + def set_rect(self, rect): self.rect = rect + def get_rect(self): return self.rect + def get_soil(self): return self.soil + def set_soil(self, soil): - self.soil = soil \ No newline at end of file + self.soil = soil diff --git a/geneticalgorithm.py b/geneticalgorithm.py index aaf36dd..65eb207 100644 --- a/geneticalgorithm.py +++ b/geneticalgorithm.py @@ -10,10 +10,13 @@ import pygame import random import station import treelearn + + def create_genetic_algorithm(): - if os.path.exists("resources/genetic_algorithm/optimalastar.pkl"): #jeżeli algorytm genetyczny utworzył plik wcześcniej to odczytaj + if os.path.exists( + "resources/genetic_algorithm/optimalastar.pkl"): # jeżeli algorytm genetyczny utworzył plik wcześcniej to odczytaj astar_costs = pickle.load(open(os.path.join('resources/genetic_algorithm', "optimalastar.pkl"), "rb")) - #kolejność alfabetyczna + # kolejność alfabetyczna definitions.BEETROOTS_ADULT_COST = astar_costs[0] definitions.BEETROOTS_GROW_COST = astar_costs[1] definitions.CARROTS_ADULT_COST = astar_costs[2] @@ -27,31 +30,39 @@ def create_genetic_algorithm(): definitions.STATION_COST = astar_costs[10] definitions.WHEAT_ADULT_COST = astar_costs[11] definitions.WHEAT_GROW_COST = astar_costs[12] - 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 + 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 astar_costs = evolve(astar_costs) pickle.dump(astar_costs, open(os.path.join('resources/genetic_algorithm', "optimalastar.pkl"), "wb")) + + def evolve(astar_costs): - 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 + 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 for _ in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): first_generation.append(random.uniform(0, 10)) - 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 + 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 print(f"=== Generation {gen + 1} ===") - ranked_solutions = [] #rozwiązania z wynikiem + ranked_solutions = [] # rozwiązania z wynikiem index = 0 - for s in solutions: #przypisanie rozwiązaniom wyniku funkcji fitness + for s in solutions: # przypisanie rozwiązaniom wyniku funkcji fitness 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]) - #TODO warunek stopu - best_solutions = ranked_solutions[:definitions.GENETIC_ALGORITHM_NUMBER_OF_BEST_INDIVIDUALS] #najlepsze osobniki w danej generacji + # TODO warunek stopu + best_solutions = ranked_solutions[ + :definitions.GENETIC_ALGORITHM_NUMBER_OF_BEST_INDIVIDUALS] # najlepsze osobniki w danej generacji elements = [] for element in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): elems = [] @@ -59,26 +70,31 @@ def evolve(astar_costs): for solution in best_solutions: for element in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): elements[element].append(solution[1][element]) - next_generation = [] #nowa ganeracja + next_generation = [] # nowa ganeracja e = [] - for individual in range(definitions.GENETIC_ALGORITHM_NUMBER_OF_INDIVIDUALS): #liczba osobników w kolejnej generacji + for individual in range( + definitions.GENETIC_ALGORITHM_NUMBER_OF_INDIVIDUALS): # liczba osobników w kolejnej generacji for el in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): - #mutacje + # mutacje e.append(random.choice(elements[el]) * random.uniform(0.99, 1.01)) next_generation.append(e) - solutions = next_generation #zastąpnienie osobników nową generacją + solutions = next_generation # zastąpnienie osobników nową generacją overall_solutions.sort() - for _ in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): #przyspianie finalnych kosztów astara + for _ in range(definitions.GENETIC_ALGORITHM_COSTS_AMOUNT): # przyspianie finalnych kosztów astara astar_costs[_] = overall_solutions[0][1][_] return astar_costs + + def fitness(astar_costs, index): ans = harvest(astar_costs, index) - if ans == 0: #TODO + if ans == 0: # TODO return 0 else: return 1 / ans + + def harvest(astar_costs, index): - #kolejność alfabetyczna + # kolejność alfabetyczna definitions.BEETROOTS_ADULT_COST = astar_costs[0] definitions.BEETROOTS_GROW_COST = astar_costs[1] definitions.CARROTS_ADULT_COST = astar_costs[2] @@ -92,41 +108,69 @@ def harvest(astar_costs, index): definitions.STATION_COST = astar_costs[10] definitions.WHEAT_ADULT_COST = astar_costs[11] definitions.WHEAT_GROW_COST = astar_costs[12] - #tworzenie podstawowych obiektów + # tworzenie podstawowych obiektów map1 = map.Map([]) map1.create_base_map() - 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} + 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} collected_plants_dict_cart = {"beetroot": 0, "carrot": 0, "potato": 0, "wheat": 0} collected_plants_dict_station = {"beetroot": 0, "carrot": 0, "potato": 0, "wheat": 0} - fertilizer_dict = {"beetroot": definitions.CART_FERTILIZER, "carrot": definitions.CART_FERTILIZER, "potato": definitions.CART_FERTILIZER, "wheat": definitions.CART_FERTILIZER} + fertilizer_dict = {"beetroot": definitions.CART_FERTILIZER, "carrot": definitions.CART_FERTILIZER, + "potato": definitions.CART_FERTILIZER, "wheat": definitions.CART_FERTILIZER} station1 = station.Station(collected_plants_dict_station) - 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) + 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) cart1_rect = pygame.Rect(cart1.get_x(), cart1.get_y(), definitions.BLOCK_SIZE, definitions.BLOCK_SIZE) - tree = treelearn.treelearn() #tworzenie drzewa decyzyjnego - decision = [0] #początkowa decyzja o braku powrotu do stacji (0) + tree = treelearn.treelearn() # tworzenie drzewa decyzyjnego + decision = [0] # początkowa decyzja o braku powrotu do stacji (0) grow_flower_dandelion = False random_movement = False - 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 + 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 grow_flower_dandelion = True - 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 + 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 random_movement = False - 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 + 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 else: random_movement = True - 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 + 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 if random_movement is True: - cart1.handle_movement_random(cart1_rect) #wykonuj losowe ruchy + cart1.handle_movement_random(cart1_rect) # wykonuj losowe ruchy if grow_flower_dandelion is True: - 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 + 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 print("individual no.", index + 1, "score:", station1.get_all_collected_plants()) - return station1.get_all_collected_plants() \ No newline at end of file + return station1.get_all_collected_plants() diff --git a/graph.py b/graph.py index a0b82cd..b3f1323 100644 --- a/graph.py +++ b/graph.py @@ -1,83 +1,117 @@ import cart import copy -class Istate: #stan początkowy wózka (strona, w którą patrzy, miejsce, w którym się on znajduje) + + +class Istate: # stan początkowy wózka (strona, w którą patrzy, miejsce, w którym się on znajduje) def __init__(self, direction, x, y): self.direction = direction self.x = x self.y = y + def get_direction(self): return self.direction + def set_direction(self, direction): self.direction = direction + def get_x(self): return self.x + def set_x(self, x): self.x = x + def get_y(self): return self.y + def set_y(self, y): self.y = y -class Node: #wierzchołek grafu + + +class Node: # wierzchołek grafu def __init__(self, action, direction, parent, x, y): - self.action = action #akcja jaką ma wykonać (obróc się w lewo, obróć się w prawo, ruch do przodu) + self.action = action # akcja jaką ma wykonać (obróc się w lewo, obróć się w prawo, ruch do przodu) self.direction = direction - self.parent = parent #ojciec wierzchołka + self.parent = parent # ojciec wierzchołka self.x = x self.y = y + def get_action(self): return self.action + def set_action(self, action): self.action = action + def get_direction(self): return self.direction + def set_direction(self, direction): self.direction = direction + def get_parent(self): return self.parent + def set_parent(self, parent): self.parent = parent + def get_x(self): return self.x + def set_x(self, x): self.x = x + def get_y(self): return self.y + def set_y(self, y): self.y = y -def goal_test(goaltest, elem): #funkcja sprawdzająca czy położenie wózka równa się położeniu punktu docelowego, jeśli tak zwraca prawdę, w przeciwnym wypadku fałsz + + +def goal_test(goaltest, + elem): # funkcja sprawdzająca czy położenie wózka równa się położeniu punktu docelowego, jeśli tak zwraca prawdę, w przeciwnym wypadku fałsz if elem.get_x() == goaltest[0] and elem.get_y() == goaltest[1]: return True else: return False -def graphsearch(explored, fringe, goaltest, istate, succ): #przeszukiwanie grafu wszerz - node = Node(None, istate.get_direction(), None, istate.get_x(), istate.get_y()) #wierzchołek początkowy, stworzony ze stanu początkowego wózka - fringe.append(node) #wierzchołki do odwiedzenia + + +def graphsearch(explored, fringe, goaltest, istate, succ): # przeszukiwanie grafu wszerz + node = Node(None, istate.get_direction(), None, istate.get_x(), + istate.get_y()) # wierzchołek początkowy, stworzony ze stanu początkowego wózka + fringe.append(node) # wierzchołki do odwiedzenia while True: if not fringe: return False - elem = fringe.pop(0) #zdejmujemy wierzchołek z kolejki fringe i rozpatrujemy go + elem = fringe.pop(0) # zdejmujemy wierzchołek z kolejki fringe i rozpatrujemy go temp = copy.copy(elem) - if goal_test(goaltest, elem) is True: #jeżeli osiągniemy cel w trakcie przeszukiwania grafu wszerz (wjedziemy na pole docelowe) : zwracamy listę ruchów, po których wykonaniu dotrzemy na miejsce + if goal_test(goaltest, + elem) is True: # jeżeli osiągniemy cel w trakcie przeszukiwania grafu wszerz (wjedziemy na pole docelowe) : zwracamy listę ruchów, po których wykonaniu dotrzemy na miejsce return print_moves(elem) - explored.append(elem) #dodajemy wierzchołek do listy wierzchołków odwiedzonych - for (action, state) in succ(temp): #iterujemy po wszystkich możliwych akcjach i stanach otrzymanych dla danego wierzchołka grafu + explored.append(elem) # dodajemy wierzchołek do listy wierzchołków odwiedzonych + for (action, state) in succ( + temp): # iterujemy po wszystkich możliwych akcjach i stanach otrzymanych dla danego wierzchołka grafu fringe_tuple = [] explored_tuple = [] for x in fringe: fringe_tuple.append((x.get_direction(), x.get_x(), x.get_y())) for x in explored: explored_tuple.append((x.get_direction(), x.get_x(), x.get_y())) - if state not in fringe_tuple and state not in explored_tuple: #jeżeli stan nie znajduje się na fringe oraz nie znajduje się w liście wierzchołków odwiedzonych - x = Node(action, state[0], elem, state[1], state[2]) #stworzenie nowego wierzchołka, którego rodzicem jest elem - fringe.append(x) #dodanie wierzchołka na fringe -def print_moves(elem): #zwraca listę ruchów jakie należy wykonać by dotrzeć do punktu docelowego + if state not in fringe_tuple and state not in explored_tuple: # jeżeli stan nie znajduje się na fringe oraz nie znajduje się w liście wierzchołków odwiedzonych + x = Node(action, state[0], elem, state[1], + state[2]) # stworzenie nowego wierzchołka, którego rodzicem jest elem + fringe.append(x) # dodanie wierzchołka na fringe + + +def print_moves(elem): # zwraca listę ruchów jakie należy wykonać by dotrzeć do punktu docelowego moves_list = [] while (elem.get_parent() != None): moves_list.append(elem.get_action()) elem = elem.get_parent() moves_list.reverse() return moves_list -def succ(elem): #funkcja następnika, przypisuje jakie akcje są możliwe do wykonania na danym polu oraz jaki będzie stan (kierunek, położenie) po wykonaniu tej akcji + + +def succ( + elem): # funkcja następnika, przypisuje jakie akcje są możliwe do wykonania na danym polu oraz jaki będzie stan (kierunek, położenie) po wykonaniu tej akcji actions_list = [] temp = copy.copy(elem.get_direction()) if temp == 1: @@ -103,4 +137,4 @@ def succ(elem): #funkcja następnika, przypisuje jakie akcje są możliwe do wyk actions_list.append(("move", (elem.get_direction(), elem.get_x(), temp_move_south))) elif cart.Cart.is_move_allowed_succ(elem) == "x - 1": actions_list.append(("move", (elem.get_direction(), temp_move_west, elem.get_y()))) - return actions_list \ No newline at end of file + return actions_list diff --git a/map.py b/map.py index 344a3ae..6a22286 100644 --- a/map.py +++ b/map.py @@ -3,18 +3,24 @@ import field import plant import pygame import soil + + class Map: def __init__(self, fields): - self.fields = fields #przechowuje wszystkie pola (Field) + self.fields = fields # przechowuje wszystkie pola (Field) + def get_fields(self): return self.fields + def set_fields(self, fields): self.fields = fields - def create_base_map(self): #wypełnia mapę polami z bazowymi logicznymi wartościami + + def create_base_map(self): # wypełnia mapę polami z bazowymi logicznymi wartościami for i in range(definitions.WIDTH_AMOUNT): temp_map_field = [] for j in range(definitions.HEIGHT_AMOUNT): - temp_rect = pygame.Rect(i * definitions.BLOCK_SIZE, j * definitions.BLOCK_SIZE, definitions.BLOCK_SIZE, definitions.BLOCK_SIZE) + temp_rect = pygame.Rect(i * definitions.BLOCK_SIZE, j * definitions.BLOCK_SIZE, definitions.BLOCK_SIZE, + definitions.BLOCK_SIZE) if i == 0 and j == 0: temp_plant = plant.Plant("station", -1) else: @@ -23,7 +29,8 @@ class Map: temp_field = field.Field(temp_plant, temp_rect, temp_soil) temp_map_field.append(temp_field) self.fields.append(temp_map_field) - def draw_window(self, cart, cart_rect, station): #rysuje mapę + + def draw_window(self, cart, cart_rect, station): # rysuje mapę self.fill_map(station) if cart.get_direction() == definitions.CART_DIRECTION_EAST: definitions.WINDOW.blit(definitions.CART_DIRECTION_EAST_TEXTURE, (cart_rect.x, cart_rect.y)) @@ -34,7 +41,8 @@ class Map: elif cart.get_direction() == definitions.CART_DIRECTION_WEST: definitions.WINDOW.blit(definitions.CART_DIRECTION_WEST_TEXTURE, (cart_rect.x, cart_rect.y)) pygame.display.update() - def fill_map(self, station): #wypełnia mapę teksturami na podstawie logicznego stanu pól + + def fill_map(self, station): # wypełnia mapę teksturami na podstawie logicznego stanu pól for i in range(definitions.WIDTH_AMOUNT): for j in range(definitions.HEIGHT_AMOUNT): field = self.fields[i][j] @@ -103,40 +111,53 @@ class Map: definitions.WINDOW.blit(block, (rect.x, rect.y)) for i in range(definitions.WIDTH_AMOUNT): block = definitions.SPONGE_WET - definitions.WINDOW.blit(block, (i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) + definitions.WINDOW.blit(block, + (i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) if i == 1: block = definitions.BEETROOT - definitions.WINDOW.blit(block, (i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) + definitions.WINDOW.blit(block, ( + i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) elif i == 2: - text = definitions.FONT.render(str(station.get_collected_plants("beetroot")), True, definitions.FONT_COLOR) + text = definitions.FONT.render(str(station.get_collected_plants("beetroot")), True, + definitions.FONT_COLOR) text_rect = text.get_rect() - text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) + text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, + definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) definitions.WINDOW.blit(text, text_rect) elif i == 3: block = definitions.CARROT - definitions.WINDOW.blit(block, (i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) + definitions.WINDOW.blit(block, ( + i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) elif i == 4: - text = definitions.FONT.render(str(station.get_collected_plants("carrot")), True, definitions.FONT_COLOR) + text = definitions.FONT.render(str(station.get_collected_plants("carrot")), True, + definitions.FONT_COLOR) text_rect = text.get_rect() - text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) + text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, + definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) definitions.WINDOW.blit(text, text_rect) elif i == 5: block = definitions.POTATO - definitions.WINDOW.blit(block, (i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) + definitions.WINDOW.blit(block, ( + i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) elif i == 6: - text = definitions.FONT.render(str(station.get_collected_plants("potato")), True, definitions.FONT_COLOR) + text = definitions.FONT.render(str(station.get_collected_plants("potato")), True, + definitions.FONT_COLOR) text_rect = text.get_rect() - text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) + text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, + definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) definitions.WINDOW.blit(text, text_rect) elif i == 7: block = definitions.WHEAT - definitions.WINDOW.blit(block, (i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) + definitions.WINDOW.blit(block, ( + i * definitions.BLOCK_SIZE, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE)) elif i == 8: text = definitions.FONT.render(str(station.get_collected_plants("wheat")), True, definitions.FONT_COLOR) text_rect = text.get_rect() - text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) + text_rect.center = (i * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2, + definitions.HEIGHT_AMOUNT * definitions.BLOCK_SIZE + definitions.BLOCK_SIZE / 2) definitions.WINDOW.blit(text, text_rect) - def get_field_cost(self, x, y): #zwraca koszt danego pola + + def get_field_cost(self, x, y): # zwraca koszt danego pola field = self.fields[x][y] if field.get_plant().get_name() == "station" and field.get_plant().get_state() == -1: return definitions.STATION_COST @@ -163,4 +184,4 @@ class Map: elif field.get_soil().get_state() is True and field.get_soil().get_water_level() is False: return definitions.FARMLAND_DRY_COST elif field.get_soil().get_state() is True and field.get_soil().get_water_level() is True: - return definitions.FARMLAND_WET_COST \ No newline at end of file + return definitions.FARMLAND_WET_COST diff --git a/neuralnetwork.py b/neuralnetwork.py index 466c915..9195317 100644 --- a/neuralnetwork.py +++ b/neuralnetwork.py @@ -11,7 +11,12 @@ import pathlib import torch import torch.nn as nn import torchvision -transformer1 = transforms.Compose([transforms.Resize((definitions.IMAGE_SIZE_NEURAL_NETWORK, definitions.IMAGE_SIZE_NEURAL_NETWORK)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) + +transformer1 = transforms.Compose( + [transforms.Resize((definitions.IMAGE_SIZE_NEURAL_NETWORK, definitions.IMAGE_SIZE_NEURAL_NETWORK)), + transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) + + class ConvNet(nn.Module): def __init__(self, num_classes=6): super(ConvNet, self).__init__() @@ -24,7 +29,9 @@ class ConvNet(nn.Module): self.conv3 = nn.Conv2d(in_channels=20, out_channels=32, kernel_size=3, stride=1, padding=1) self.bn3 = nn.BatchNorm2d(num_features=32) self.relu3 = nn.ReLU() - self.fc = nn.Linear(in_features=int(definitions.IMAGE_SIZE_NEURAL_NETWORK / 2) * int(definitions.IMAGE_SIZE_NEURAL_NETWORK / 2) * 32, out_features=num_classes) + self.fc = nn.Linear(in_features=int(definitions.IMAGE_SIZE_NEURAL_NETWORK / 2) * int( + definitions.IMAGE_SIZE_NEURAL_NETWORK / 2) * 32, out_features=num_classes) + def forward(self, input): output = self.conv1(input) output = self.bn1(output) @@ -35,30 +42,38 @@ class ConvNet(nn.Module): output = self.conv3(output) output = self.bn3(output) output = self.relu3(output) - output = output.view(-1, 32 * int(definitions.IMAGE_SIZE_NEURAL_NETWORK / 2) * int(definitions.IMAGE_SIZE_NEURAL_NETWORK / 2)) + output = output.view(-1, 32 * int(definitions.IMAGE_SIZE_NEURAL_NETWORK / 2) * int( + definitions.IMAGE_SIZE_NEURAL_NETWORK / 2)) output = self.fc(output) return output -def create_neural_network(): #tworzenie sieci neuronowej - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') #użyj cuda jeśli możliwe - transformer = transforms.Compose([transforms.Resize((definitions.IMAGE_SIZE_NEURAL_NETWORK, definitions.IMAGE_SIZE_NEURAL_NETWORK)), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) - train_path = os.path.join('resources/neural_network/train/') #ścieżka do obrazków do treningu - test_path = os.path.join('resources/neural_network/test/') #ścieżka do obrazków do testu - train_loader = DataLoader(torchvision.datasets.ImageFolder(train_path, transform=transformer), batch_size=64, shuffle=True) - test_loader = DataLoader(torchvision.datasets.ImageFolder(test_path, transform=transformer), batch_size=32, shuffle=True) + + +def create_neural_network(): # tworzenie sieci neuronowej + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # użyj cuda jeśli możliwe + transformer = transforms.Compose( + [transforms.Resize((definitions.IMAGE_SIZE_NEURAL_NETWORK, definitions.IMAGE_SIZE_NEURAL_NETWORK)), + transforms.RandomHorizontalFlip(), transforms.ToTensor(), + transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) + train_path = os.path.join('resources/neural_network/train/') # ścieżka do obrazków do treningu + test_path = os.path.join('resources/neural_network/test/') # ścieżka do obrazków do testu + train_loader = DataLoader(torchvision.datasets.ImageFolder(train_path, transform=transformer), batch_size=64, + shuffle=True) + test_loader = DataLoader(torchvision.datasets.ImageFolder(test_path, transform=transformer), batch_size=32, + shuffle=True) root = pathlib.Path(train_path) classes = sorted([j.name.split('/')[-1] for j in root.iterdir()]) - if os.path.exists("resources/neural_network/checkpoint.model"): #jeżeli istnieje model to wczytaj + if os.path.exists("resources/neural_network/checkpoint.model"): # jeżeli istnieje model to wczytaj checkpoint = torch.load(os.path.join('resources/neural_network', 'checkpoint.model')) model = ConvNet(num_classes=6) model.load_state_dict(checkpoint) model.eval() - else: #w przeciwnym razie utwórz nowy model + else: # w przeciwnym razie utwórz nowy model model = ConvNet(num_classes=6).to(device) optimizer = Adam(model.parameters(), lr=0.001, weight_decay=0.0001) loss_function = nn.CrossEntropyLoss() num_epochs = 10 - train_count = len(glob.glob(train_path + '/**/*.png')) #liczba obrazków treningowych - test_count = len(glob.glob(test_path + '/**/*.png')) #liczba obrazków testowych + train_count = len(glob.glob(train_path + '/**/*.png')) # liczba obrazków treningowych + test_count = len(glob.glob(test_path + '/**/*.png')) # liczba obrazków testowych best_accuracy = 0.0 for epoch in range(num_epochs): model.train() @@ -88,7 +103,8 @@ def create_neural_network(): #tworzenie sieci neuronowej _, prediction = torch.max(outputs.data, 1) test_accuracy += int(torch.sum(prediction == labels.data)) test_accuracy = test_accuracy / test_count - print('Epoch: ' + str(epoch + 1) + ' Train Loss: ' + str(train_loss) + ' Train Accuracy: ' + str(train_accuracy) + ' Test Accuracy: ' + str(test_accuracy)) + print('Epoch: ' + str(epoch + 1) + ' Train Loss: ' + str(train_loss) + ' Train Accuracy: ' + str( + train_accuracy) + ' Test Accuracy: ' + str(test_accuracy)) if test_accuracy > best_accuracy: torch.save(model.state_dict(), 'resources/neural_network/checkpoint.model') best_accuracy = test_accuracy @@ -97,19 +113,22 @@ def create_neural_network(): #tworzenie sieci neuronowej model.load_state_dict(checkpoint) model.eval() return classes, model -def predfield(classes, istate, model): #zwraca najbliższe miejsce pola z wyrośniętą rośliną na podstawie wykrywania obrazu - pred_path = os.path.join('resources/neural_network/tiles/') #ścieżka do obrazków do sprawdzenia + + +def predfield(classes, istate, + model): # zwraca najbliższe miejsce pola z wyrośniętą rośliną na podstawie wykrywania obrazu + pred_path = os.path.join('resources/neural_network/tiles/') # ścieżka do obrazków do sprawdzenia pred_dict = {} images_path = glob.glob(pred_path + '/*.png') - x = None #x'owa pola - y = None #y'kowa pola + x = None # x'owa pola + y = None # y'kowa pola x_position = 15 y_position = 12 min = None - for i in images_path: #dodajemy pocięte obrazki do listy i ustawiamy im przewidywaną metkę + for i in images_path: # dodajemy pocięte obrazki do listy i ustawiamy im przewidywaną metkę pred_dict[i[i.rfind('/') + 1:]] = prediction1(classes, i, model, transformer1) for img_name, field in pred_dict.items(): - if field != "random": #jeżeli metka nie jest 'random' to przypisz do x'a i y'a miejsce wyrośniętej rośliny + if field != "random": # jeżeli metka nie jest 'random' to przypisz do x'a i y'a miejsce wyrośniętej rośliny if x is None and y is None: x = img_name[x_position] y = img_name[y_position] @@ -141,11 +160,13 @@ def predfield(classes, istate, model): #zwraca najbliższe miejsce pola z wyroś min = len((graph.graphsearch([], [], (temp_x, temp_y), istate, graph.succ))) x = temp_x y = temp_y - if x == None and y == None: #jeżeli nie ma wyrośniętej rośliny to zwróć fałsz + if x == None and y == None: # jeżeli nie ma wyrośniętej rośliny to zwróć fałsz return False else: return x, y -def prediction1(classes, img_path, model, transformer): #zwraca predykcję dla danego obrazka + + +def prediction1(classes, img_path, model, transformer): # zwraca predykcję dla danego obrazka image = Image.open(img_path).convert('RGB') image_tensor = transformer(image).float() image_tensor = image_tensor.unsqueeze_(0) @@ -155,4 +176,4 @@ def prediction1(classes, img_path, model, transformer): #zwraca predykcję dla d output = model(input) index = output.data.numpy().argmax() pred = classes[index] - return pred \ No newline at end of file + return pred diff --git a/plant.py b/plant.py index 4810b92..8fa2c81 100644 --- a/plant.py +++ b/plant.py @@ -1,22 +1,30 @@ import definitions import graph import random + + class Plant: def __init__(self, name, state): - self.name = name #nazwa rośliny np. "wheat" - self.state = state #etap rozwoju rośliny + self.name = name # nazwa rośliny np. "wheat" + self.state = state # etap rozwoju rośliny + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_state(self): return self.state + def set_state(self, state): self.state = state + @staticmethod - def get_closest_mature_plant(istate, map): #pobiera miejsce najbliższej dojrzałej rośliny od miejsca, w którym znajduje się wózek - x = None #x'owa pola - y = None #y'kowa pola + def get_closest_mature_plant(istate, + map): # pobiera miejsce najbliższej dojrzałej rośliny od miejsca, w którym znajduje się wózek + x = None # x'owa pola + y = None # y'kowa pola min = None for i in range(definitions.WIDTH_AMOUNT): for j in range(definitions.HEIGHT_AMOUNT): @@ -62,8 +70,9 @@ class Plant: y = j min = len((graph.graphsearch([], [], (x, y), istate, graph.succ))) return x, y + @staticmethod - def grow_flower_dandelion(map): #metoda statyczna, losująca czy na danym polu ma urosnąć kwiat dandelion + def grow_flower_dandelion(map): # metoda statyczna, losująca czy na danym polu ma urosnąć kwiat dandelion for i in range(definitions.WIDTH_AMOUNT): for j in range(definitions.HEIGHT_AMOUNT): field = map.get_fields()[i][j] @@ -72,8 +81,10 @@ class Plant: if random1 <= definitions.FLOWER_DANDELION_GROW_PROBABILITY: field.get_plant().set_name("flower_dandelion") field.get_plant().set_state(definitions.FLOWER_DANDELION_MAXIMUM_STATE) + @staticmethod - def grow_plants(map): #metoda statyczna, która zwiększa pole state (etap rozwoju rośliny) dla danej rośliny na danym polu o 1 + def grow_plants( + map): # metoda statyczna, która zwiększa pole state (etap rozwoju rośliny) dla danej rośliny na danym polu o 1 for i in range(definitions.WIDTH_AMOUNT): for j in range(definitions.HEIGHT_AMOUNT): field = map.get_fields()[i][j] @@ -85,8 +96,10 @@ class Plant: field.get_plant().set_state(field.get_plant().get_state() + 1) elif field.get_plant().get_name() == "wheat" and field.get_plant().get_state() > 0 and field.get_plant().get_state() < definitions.WHEAT_MAXIMUM_STATE: field.get_plant().set_state(field.get_plant().get_state() + 1) + @staticmethod - def if_any_mature_plant(map): #sprawdza czy na polu występuje choć jedna dojrzała roślina, jeśli tak zwraca prawdę, w przeciwnym razie zwraca fałsz + def if_any_mature_plant( + map): # sprawdza czy na polu występuje choć jedna dojrzała roślina, jeśli tak zwraca prawdę, w przeciwnym razie zwraca fałsz for i in range(definitions.WIDTH_AMOUNT): for j in range(definitions.HEIGHT_AMOUNT): field = map.get_fields()[i][j] @@ -98,4 +111,4 @@ class Plant: return True elif field.get_plant().get_name() == "wheat" and field.get_plant().get_state() == definitions.WHEAT_MAXIMUM_STATE: return True - return False \ No newline at end of file + return False diff --git a/py.py b/py.py index a84627e..eca9ea9 100644 --- a/py.py +++ b/py.py @@ -11,64 +11,100 @@ import plant import pygame import station import treelearn + + def main(): - #inicjowanie pygame'a + # inicjowanie pygame'a pygame.init() pygame.display.set_caption("Smart Cart") - #tworzenie podstawowych obiektów + # tworzenie podstawowych obiektów map1 = map.Map([]) map1.create_base_map() - 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} + 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} collected_plants_dict_cart = {"beetroot": 0, "carrot": 0, "potato": 0, "wheat": 0} collected_plants_dict_station = {"beetroot": 0, "carrot": 0, "potato": 0, "wheat": 0} - fertilizer_dict = {"beetroot": definitions.CART_FERTILIZER, "carrot": definitions.CART_FERTILIZER, "potato": definitions.CART_FERTILIZER, "wheat": definitions.CART_FERTILIZER} + fertilizer_dict = {"beetroot": definitions.CART_FERTILIZER, "carrot": definitions.CART_FERTILIZER, + "potato": definitions.CART_FERTILIZER, "wheat": definitions.CART_FERTILIZER} station1 = station.Station(collected_plants_dict_station) - 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) + 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) cart1_rect = pygame.Rect(cart1.get_x(), cart1.get_y(), definitions.BLOCK_SIZE, definitions.BLOCK_SIZE) clock = pygame.time.Clock() - tree = treelearn.treelearn() #tworzenie drzewa decyzyjnego - decision = [0] #początkowa decyzja o braku powrotu do stacji (0) - geneticalgorithm.create_genetic_algorithm() #stworzenie algorytmu genetycznego - classes, model = neuralnetwork.create_neural_network() #uczenie sieci neuronowej + tree = treelearn.treelearn() # tworzenie drzewa decyzyjnego + decision = [0] # początkowa decyzja o braku powrotu do stacji (0) + geneticalgorithm.create_genetic_algorithm() # stworzenie algorytmu genetycznego + classes, model = neuralnetwork.create_neural_network() # uczenie sieci neuronowej grow_flower_dandelion = False random_movement = False run = True - while run: #pętla główna programu + while run: # pętla główna programu clock.tick(definitions.FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False map1.draw_window(cart1, cart1_rect, station1) - if not move_list: #jeżeli są jakieś ruchy do wykonania w move_list + if not move_list: # jeżeli są jakieś ruchy do wykonania w move_list grow_flower_dandelion = True - pygame.image.save(pygame.display.get_surface(), os.path.join('resources/neural_network/tiles/', 'screen.jpg')) #zrzut obecnego ekranu - tiles = image_slicer.slice(os.path.join('resources/neural_network/tiles/', 'screen.jpg'), row=definitions.HEIGHT_AMOUNT + 1, col=definitions.WIDTH_AMOUNT, save=False) #pocięcie ekranu na sto części - image_slicer.save_tiles(tiles, directory=os.path.join('resources/neural_network/tiles/'), prefix='tile', format='png') #zapisanie części do folderu tiles + pygame.image.save(pygame.display.get_surface(), + os.path.join('resources/neural_network/tiles/', 'screen.jpg')) # zrzut obecnego ekranu + tiles = image_slicer.slice(os.path.join('resources/neural_network/tiles/', 'screen.jpg'), + row=definitions.HEIGHT_AMOUNT + 1, col=definitions.WIDTH_AMOUNT, + save=False) # pocięcie ekranu na sto części + image_slicer.save_tiles(tiles, directory=os.path.join('resources/neural_network/tiles/'), prefix='tile', + format='png') # zapisanie części do folderu tiles os.remove('resources/neural_network/tiles/screen.jpg') for char in range(0, definitions.WIDTH_AMOUNT): if str(char) == "0": os.remove('resources/neural_network/tiles/tile_11_10.png') else: os.remove('resources/neural_network/tiles/tile_11_0' + str(char) + '.png') - 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 neuralnetwork.predfield(classes, istate, model) is not False: #jeżeli istnieje jakaś dojrzała roślina + 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 neuralnetwork.predfield(classes, istate, model) is not False: # jeżeli istnieje jakaś dojrzała roślina random_movement = False - if decision == [0]: #jeżeli decyzja jest 0 (brak powrotu do stacji) to uprawiaj pole - move_list = (astar.graphsearch([], astar.f, [], neuralnetwork.predfield(classes, istate, model), 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 + if decision == [0]: # jeżeli decyzja jest 0 (brak powrotu do stacji) to uprawiaj pole + move_list = ( + astar.graphsearch([], astar.f, [], neuralnetwork.predfield(classes, istate, model), 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 else: random_movement = True - 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 + 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 if random_movement is True: - cart1.handle_movement_random(cart1_rect) #wykonuj losowe ruchy - 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) + cart1.handle_movement_random(cart1_rect) # wykonuj losowe ruchy + 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) if grow_flower_dandelion is True: - plant.Plant.grow_flower_dandelion(map1) #losuj urośnięcie kwiatka dandeliona - plant.Plant.grow_plants(map1) #zwiększ poziom dojrzałości roślin + plant.Plant.grow_flower_dandelion(map1) # losuj urośnięcie kwiatka dandeliona + plant.Plant.grow_plants(map1) # zwiększ poziom dojrzałości roślin pygame.quit() + + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/soil.py b/soil.py index 863bb4a..0fcee30 100644 --- a/soil.py +++ b/soil.py @@ -1,17 +1,23 @@ class Soil: def __init__(self, is_fertilized, state, water_level): - self.is_fertilized = is_fertilized #nienawieziona lub nawieziona - self.state = state #niezaorana lub zaorana - self.water_level = water_level #niepodlana lub podlana + self.is_fertilized = is_fertilized # nienawieziona lub nawieziona + self.state = state # niezaorana lub zaorana + self.water_level = water_level # niepodlana lub podlana + def get_is_fertilized(self): return self.is_fertilized + def set_is_fertilized(self, is_fertilized): self.is_fertilized = is_fertilized + def get_state(self): return self.state + def set_state(self, state): self.state = state + def get_water_level(self): return self.water_level + def set_water_level(self, water_level): - self.water_level = water_level \ No newline at end of file + self.water_level = water_level diff --git a/station.py b/station.py index 4bb9c90..03443be 100644 --- a/station.py +++ b/station.py @@ -1,9 +1,14 @@ class Station: def __init__(self, collected_plants): - self.collected_plants = collected_plants #collected_plants to słownik, przechowuje informacje o oddanych plonach - def get_all_collected_plants(self): #zwraca łączną ilość zebranych plonów (suma plonów wszystkich roślin) - return self.collected_plants["beetroot"] + self.collected_plants["carrot"] + self.collected_plants["potato"] + self.collected_plants["wheat"] - def get_collected_plants(self, name): #zwraca łączną ilość oddanych plonów dla podanej rośliny (name) + self.collected_plants = collected_plants # collected_plants to słownik, przechowuje informacje o oddanych plonach + + def get_all_collected_plants(self): # zwraca łączną ilość zebranych plonów (suma plonów wszystkich roślin) + return self.collected_plants["beetroot"] + self.collected_plants["carrot"] + self.collected_plants["potato"] + \ + self.collected_plants["wheat"] + + def get_collected_plants(self, name): # zwraca łączną ilość oddanych plonów dla podanej rośliny (name) return self.collected_plants[name] - def set_collected_plants(self, name, value): #dla podanej rośliny (name) ustawia łączną ilość oddanych plonów (value) - self.collected_plants[name] = value \ No newline at end of file + + def set_collected_plants(self, name, + value): # dla podanej rośliny (name) ustawia łączną ilość oddanych plonów (value) + self.collected_plants[name] = value diff --git a/treelearn.py b/treelearn.py index 829eb8a..5111c71 100644 --- a/treelearn.py +++ b/treelearn.py @@ -6,24 +6,31 @@ import pickle import pydotplus from sklearn import tree from sklearn.tree import DecisionTreeClassifier -def make_decision(amount_of_seeds, collected_plants, fertilizer, fuel, tree, water_level): #zwraca decyzję o powrocie do stacji (0 : NIE, 1 : TAK) - decision = tree.predict([[amount_of_seeds, collected_plants, fertilizer, fuel, water_level]]) #podejmij decyzję na podstawie aktualnych parametrów wózka o powrocie do stacji lub nie + + +def make_decision(amount_of_seeds, collected_plants, fertilizer, fuel, tree, + water_level): # zwraca decyzję o powrocie do stacji (0 : NIE, 1 : TAK) + decision = tree.predict([[amount_of_seeds, collected_plants, fertilizer, fuel, + water_level]]) # podejmij decyzję na podstawie aktualnych parametrów wózka o powrocie do stacji lub nie return decision -def treelearn(): #zwraca utworzone drzewo decyzyjne - if os.path.exists("resources/decision_tree/tree.pkl"): #jeżeli drzewo jest zapisane w pliku to odczytaj + + +def treelearn(): # zwraca utworzone drzewo decyzyjne + if os.path.exists("resources/decision_tree/tree.pkl"): # jeżeli drzewo jest zapisane w pliku to odczytaj dtree = pickle.load(open(os.path.join('resources/decision_tree', "tree.pkl"), "rb")) - else: #w przeciwnym razie utwórz drzewo od początku i zapisz do pliku - df = pandas.read_csv(os.path.join('resources/decision_tree', 'data.csv')) #czytanie danych do nauki drzewa z pliku .csv + else: # w przeciwnym razie utwórz drzewo od początku i zapisz do pliku + df = pandas.read_csv( + os.path.join('resources/decision_tree', 'data.csv')) # czytanie danych do nauki drzewa z pliku .csv features = ['amount of seeds', 'collected plants', 'fertilizer', 'fuel', 'water level'] - x = df[features] #wczytanie atrybutów, z których ma się uczyć drzewo - y = df['back to station'] #podjęte decyzje - dtree = DecisionTreeClassifier() #klasyfikuje drzewo - dtree = dtree.fit(x, y) #uczy drzewo + x = df[features] # wczytanie atrybutów, z których ma się uczyć drzewo + y = df['back to station'] # podjęte decyzje + dtree = DecisionTreeClassifier() # klasyfikuje drzewo + dtree = dtree.fit(x, y) # uczy drzewo pickle.dump(dtree, open(os.path.join('resources/decision_tree', "tree.pkl"), "wb")) data = tree.export_graphviz(dtree, out_file=None, feature_names=features) graph = pydotplus.graph_from_dot_data(data) graph.write_png(os.path.join('resources/decision_tree', 'mytree.png')) img = pltimg.imread(os.path.join('resources/decision_tree', 'mytree.png')) imgplot = plt.imshow(img) - plt.show() #wyświetl drzewo decyzyjne - return dtree \ No newline at end of file + plt.show() # wyświetl drzewo decyzyjne + return dtree