Compare commits

...

53 Commits

Author SHA1 Message Date
Magdalena Wilczynska
7ee29820a6 Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-06-12 10:33:41 +02:00
Magdalena Wilczynska
8ca6b13fb3 Added new model 2019-06-12 10:33:18 +02:00
6d21be1665 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:27:44 +00:00
bfa30af3b2 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:26:10 +00:00
bc655dded2 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:21:13 +00:00
b55707b543 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:20:06 +00:00
1ee731eec5 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:19:54 +00:00
d67ed545dc Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:19:19 +00:00
794f80c1a7 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:13:20 +00:00
3824702e4d Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-12 08:11:55 +00:00
Magdalena Wilczynska
118a8a1b1d Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-06-12 09:47:56 +02:00
Magdalena Wilczynska
8d6501708e Created new model 2019-06-12 09:47:44 +02:00
83d95f008b Zaktualizuj 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-11 21:52:30 +00:00
Magdalena Wilczynska
b1a25ecc77 Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-06-11 22:49:19 +02:00
a8a0f97f3a Zaktualizuj 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-11 20:35:50 +00:00
Magdalena Wilczynska
00563e34f2 Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-06-11 22:17:25 +02:00
923251016a Zaktualizuj 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-11 19:56:56 +00:00
Magdalena Wilczynska
2e9d079d87 Merged with new code 2019-06-11 21:12:52 +02:00
22550b92ec cos robi 2019-06-11 21:10:41 +02:00
Magdalena Wilczynska
320c702482 No conflict here but here we go again 2019-06-11 20:39:16 +02:00
Magdalena Wilczynska
3ba1f27d63 No conflict here but here we go 2019-06-11 20:38:27 +02:00
cf6172b5b2 zmieniono oznaczenia 2019-06-11 20:23:19 +02:00
78c4b6f01c Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-06-11 19:41:01 +02:00
dc14001bc5 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-11 17:40:29 +00:00
89d0c03949 Update 'Raports/SI_Raport_VowpalWabbit.md' 2019-06-11 17:39:15 +00:00
98b232a982 Jeszcze nie dziala 2019-06-11 19:36:51 +02:00
Magdalena Wilczynska
f48a725712 Added report in raw 2019-06-11 19:36:03 +02:00
Magdalena Wilczynska
49c5c2aef4 Set new args for dataset 2019-06-09 12:19:16 +02:00
Magdalena Wilczynska
737f59671d Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-06-09 12:11:03 +02:00
a49f41d681 poprawiono parser i generate input 2019-06-09 11:33:19 +02:00
Magdalena Wilczynska
09ff70271a Merged with new changes 2019-06-09 08:29:13 +02:00
Magdalena Wilczynska
ab69d0d986 New model and data input 2019-06-09 08:25:18 +02:00
d9e0bf434b dodano nowy data set, ulepszono importance 2019-06-09 07:10:16 +02:00
f509230f60 input poprawka v100 2019-06-09 00:45:24 +02:00
0b2b255a20 input poprawka v99 2019-06-09 00:36:21 +02:00
813cf2accb poprawiono wspolrzedne 2019-06-09 00:15:21 +02:00
28d2faaaed zmieniono importane, pushije zanim zepsuje 2019-06-09 00:08:10 +02:00
0c87e6de66 Usunieto zbedne mapy 2019-06-05 21:49:43 +02:00
cf3bf3d4f5 Dodano visited, mapowanie ruchow, zmiana datasetu 2019-06-05 21:48:44 +02:00
Magdalena Wilczynska
d9fc9e1384 Named fields around GC 2019-06-05 19:08:08 +02:00
Magdalena Wilczynska
7d80f5c05f Created learning script, cleaned up 2019-06-05 18:21:27 +02:00
Magdalena Wilczynska
28c6dd4744 Simplified input data 2019-06-05 17:41:58 +02:00
Magdalena Wilczynska
35fe3314f2 Cleaning up 2019-06-05 17:35:39 +02:00
Magdalena Wilczynska
d9d65c249f Added a s ton of stuff - gc-vw communication, custom bash exec 2019-06-05 10:28:55 +02:00
d95378c72e Fixed index error 2019-06-01 21:52:34 +02:00
913dba936f Added parsing data into a file 2019-06-01 21:46:02 +02:00
c969355d70 Merge branch 'VowpalWabbit' of https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi into VowpalWabbit 2019-05-30 21:37:03 +02:00
42d124cc6e Dodano parser 2019-05-30 21:32:56 +02:00
Magdalena Wilczyńska
94064f5d03 Fixed autoshut 2019-05-30 20:23:56 +02:00
Magdalena Wilczyńska
635292d9f5 Added startup flags 2019-05-30 19:37:26 +02:00
Magdalena Wilczyńska
15f88b9e20 Merged master to branch 2019-05-30 19:04:23 +02:00
Magdalena Wilczyńska
abb6dbb5dd Added auto flag to start 2019-05-30 18:37:26 +02:00
22e4a12eff Initialize 2019-05-30 18:09:57 +02:00
22 changed files with 58093 additions and 54 deletions

View File

@ -1,5 +1,6 @@
import pygame import pygame
from DataModels.Cell import Cell from DataModels.Cell import Cell
from VowpalWabbit.vowpal_utils import MAP_CONTENT
class Dump( Cell ): class Dump( Cell ):
def __init__( self, x, y, max_rubbish, dump_type, yellow = 0, green = 0, blue = 0 ): def __init__( self, x, y, max_rubbish, dump_type, yellow = 0, green = 0, blue = 0 ):
@ -12,3 +13,10 @@ class Dump( Cell ):
self.container.yellow, self.container.green, self.container.blue = collector.container.empty(dump_type, self.container.yellow, self.container.green, self.container.blue = collector.container.empty(dump_type,
[self.container.yellow, self.container.green, self.container.blue]) [self.container.yellow, self.container.green, self.container.blue])
self.update_image() self.update_image()
def Visit(self):
self.unvisited = not self.unvisited
if self.unvisited:
MAP_CONTENT[self.y][self.x] = self.dump_type[5]
else:
MAP_CONTENT[self.y][self.x] = "V"

View File

@ -2,26 +2,29 @@ from DataModels.Cell import Cell
from DataModels.Road import Road from DataModels.Road import Road
from DataModels.House import House from DataModels.House import House
from DataModels.Dump import Dump from DataModels.Dump import Dump
from config import GRID_WIDTH, GRID_HEIGHT, DELAY from config import GRID_WIDTH, GRID_HEIGHT, DELAY, CLOSE_ON_END
from utilities import movement, check_moves, save_moveset from utilities import movement, check_moves, save_moveset, unvisit_dump
from VowpalWabbit.vowpal_utils import parse_list, get_predicted_move
from Traversal.DFS import DFS from Traversal.DFS import DFS
from Traversal.BestFS import BestFS from Traversal.BestFS import BestFS
from Traversal.BFS import BFS from Traversal.BFS import BFS
import pygame import pygame, sys
class GC(Cell): class GC(Cell):
moves_made = 0 moves_made = 0
def __init__(self, x, y, max_rubbish, yellow=0, green=0, blue=0): algorithm_run = False
def __init__(self, x, y, map_objects, max_rubbish, yellow=0, green=0, blue=0):
Cell.__init__(self, x, y, max_rubbish, yellow, green, blue) Cell.__init__(self, x, y, max_rubbish, yellow, green, blue)
self.moves = [] self.moves = []
self.old_time = pygame.time.get_ticks() self.old_time = pygame.time.get_ticks()
self.vowpal_house_visited = 0
unvisit_dump(map_objects)
def move(self, direction, environment): def move(self, direction, environment):
self.x, self.y = movement(environment, self.x, self.y)[0][direction] self.x, self.y = movement(environment, self.x, self.y)[0][direction]
self.update_rect(self.x, self.y) self.update_rect(self.x, self.y)
self.moves_made = self.moves_made + 1 #moves counter self.moves_made = self.moves_made + 1 #moves counter
print(check_moves(environment, self.x, self.y,direction))
def collect(self, enviromnent): def collect(self, enviromnent):
x, y = [self.x, self.y] x, y = [self.x, self.y]
coordinates = [(x, y - 1), (x, y + 1), (x - 1, y), (x + 1, y)] coordinates = [(x, y - 1), (x, y + 1), (x - 1, y), (x + 1, y)]
@ -41,80 +44,120 @@ class GC(Cell):
return self.moves_made return self.moves_made
def find_houses(self,enviromnent, house_count,dump_count, mode): def find_houses(self,enviromnent, house_count,dump_count, mode):
self.algorithm_run = True
x = self.x x = self.x
y = self.y y = self.y
result = [] result = []
element_list=[] element_list=[]
house_count_after_search=house_count house_count_after_search=house_count
for home in range(house_count): for home in range(house_count):
last_x = x
last_y = y
avalible_moves = check_moves(enviromnent, x,y) avalible_moves = check_moves(enviromnent, x,y)
if mode == "DFS": if mode == "DFS":
house,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],House) house,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],House)
elif mode == "BFS": elif mode == "BFS":
house,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],House) house,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],House)
result = result[1::] self.moves.extend(parse_list(result[1:], last_x,last_y))
self.moves.extend(result)
element_list.append(house) element_list.append(house)
house.Visit()
unvisit_dump(enviromnent)
for dump in range(dump_count): for dump in range(dump_count):
last_x = x
last_y = y
avalible_moves = check_moves(enviromnent, x,y) avalible_moves = check_moves(enviromnent, x,y)
if mode == "DFS": if mode == "DFS":
dump,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],Dump) dump,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],Dump)
elif mode == "BFS": elif mode == "BFS":
dump,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],Dump) dump,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],Dump)
self.moves.extend(result) self.moves.extend(parse_list(result[1:], last_x,last_y))
element_list.append(dump) element_list.append(dump)
dump.Visit()
for x in element_list: for x in element_list:
x.unvisited = True x.Visit()
self.moves.reverse() self.moves.reverse()
save_moveset(self.moves) save_moveset(self.moves)
def find_houses_BestFS(self, environment): def find_houses_BestFS(self, environment):
self.algorithm_run = True
x = self.x x = self.x
y = self.y y = self.y
result = [[x,y]] result = [[x,y]]
houses_list = [] houses_list = []
dump_list = [] dump_list = []
a = 0 a = 0
for row in environment: for row in environment:
b = 0 b = 0
for col in row: for col in row:
if (type(col) is House): if (type(col) is House):
houses_list.append([col,[a,b]]) houses_list.append([col,[a,b]])
if (type(col) is Dump): if (type(col) is Dump):
dump_list.append([col,[a,b]]) dump_list.append([col,[a,b]])
b += 1 b += 1
a += 1 a += 1
x, y = self.x, self.y x, y = self.x, self.y
for i in range(len(houses_list)): for i in range(len(houses_list)):
last_x = x
last_y = y
available_movement = check_moves(environment, x, y) available_movement = check_moves(environment, x, y)
output = BestFS(environment, available_movement, [[x,y]], houses_list) output = BestFS(environment, available_movement, [[x,y]], houses_list)
if(output != None): if(output != None):
[x,y],result,houses_list = output[0], output[1], output[2] [x,y],result,houses_list,house = output[0], output[1], output[2], output[3]
self.moves.extend(result[1:]) self.moves.extend(parse_list(result[1:], last_x,last_y))
house.Visit()
unvisit_dump(environment)
for i in range(len(dump_list)): for i in range(len(dump_list)):
last_x = x
last_y = y
available_movement = check_moves(environment, x, y) available_movement = check_moves(environment, x, y)
output = BestFS(environment, available_movement, [[x,y]], dump_list) output = BestFS(environment, available_movement, [[x,y]], dump_list)
if(output != None): if(output != None):
[x,y],result,dump_list = output[0], output[1], output[2] [x,y],result,dump_list,dump = output[0], output[1], output[2], output[3]
self.moves.extend(result[1:]) self.moves.extend(parse_list(result[1:], last_x,last_y))
dump.Visit()
self.moves.reverse() self.moves.reverse()
save_moveset(self.moves) save_moveset(self.moves)
def run_vw(self, grid, house_count):
print("VOWPAL WABBIT")
x, y = self.x, self.y
possible_goals=[]
action, position = get_predicted_move([x, y])
self.moves.append(action)
if(action != "pick_garbage"):
x,y = position
else:
possible_goals.append([x+1,y])
possible_goals.append([x-1,y])
possible_goals.append([x,y+1])
possible_goals.append([x,y-1])
for location in possible_goals:
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
cell = grid[location[0]][location[1]]
if(type(cell)==Dump and cell.unvisited) or ((type(cell) == House) and cell.unvisited):
cell.Visit()
print(cell.x, cell.y)
self.vowpal_house_visited = self.vowpal_house_visited +1
if self.vowpal_house_visited == house_count:
unvisit_dump(grid)
#self.moves.reverse()
print(self.moves)
def make_actions_from_list(self,environment): def make_actions_from_list(self,environment):
now = pygame.time.get_ticks() now = pygame.time.get_ticks()
if len(self.moves)==0 or now - self.old_time <= DELAY: if len(self.moves)==0 or now - self.old_time <= DELAY:
if(len(self.moves)==0 and CLOSE_ON_END=="true" and self.algorithm_run):
print("DONE")
sys.exit()
return return
self.old_time = pygame.time.get_ticks() self.old_time = pygame.time.get_ticks()
if self.moves[-1] == "pick_garbage": if self.moves[-1] == "pick_garbage":
self.collect(environment) self.collect(environment)
self.moves.pop() self.moves.pop()
return return
self.x, self.y = self.moves.pop() self.move(self.moves[-1],environment)
self.moves_made = self.moves_made + 1 #moves counter self.moves.pop()
self.update_rect(self.x,self.y)

View File

@ -1,5 +1,5 @@
from DataModels.Cell import Cell from DataModels.Cell import Cell
from VowpalWabbit.vowpal_utils import MAP_CONTENT
class House(Cell): class House(Cell):
def __init__(self, x, y, max_rubbish, yellow=0, green=0, blue=0): def __init__(self, x, y, max_rubbish, yellow=0, green=0, blue=0):
@ -10,3 +10,10 @@ class House(Cell):
self.container.yellow, self.container.green, self.container.blue = collector.container.add( self.container.yellow, self.container.green, self.container.blue = collector.container.add(
[self.container.yellow, self.container.green, self.container.blue]) [self.container.yellow, self.container.green, self.container.blue])
self.update_image() self.update_image()
def Visit(self):
self.unvisited = not self.unvisited
if self.unvisited:
MAP_CONTENT[self.y][self.x] = "H"
else:
MAP_CONTENT[self.y][self.x] = "V"

View File

@ -141,13 +141,13 @@ def GenerateMap():
GC_position = random.choice(roads) GC_position = random.choice(roads)
#Save map to file #Save map to file
name = ".\\Resources\\Maps\\map"+str(datetime.datetime.now().strftime("%Y%m%d%H%M%S"))+"_auto.txt" name = "./Resources/Maps/map"+str(datetime.datetime.now().strftime("%Y%m%d%H%M%S%f"))+"_auto.txt"
map_file = open(name, "w+") map_file = open(name, "w+")
map_file.write(str(width)+" "+str(height)+"\n") map_file.write(str(width)+" "+str(height)+"\n")
map_file.write(str(GC_position[0])+" "+str(GC_position[1])+"\n") map_file.write(str(GC_position[0])+" "+str(GC_position[1])+"\n")
for row in grid: for row in grid:
map_file.write(" ".join(row)+"\n") map_file.write(" ".join(row)+"\n")
map_file.close() map_file.close()
print(name) #print(name)
return(name) return(name)

View File

@ -0,0 +1,104 @@
# Sztuczna inteligencja 2019 - Vowpal Wabbit
**Czas trwania opisywanych prac:** 22.05.2019 - 13.06.2019
**Osoby odpowiedzialne za implementajcę:** Anna Nowak, Magdalena Wilczyńska
**Implementowana technika:** Vowpal Wabbit
**Link do repozytorium projektu:** https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi
## Techniki uczenia - Vowpal Wabbit
#### Implementacja
Cała implementacja dla VW znajduje się na osobnym branchu /VowpalWabbit
##### Środowisko i łączenie z Python3
W związku z informacjami o błędach w implementacji wrappera VowpalWabbit dla Python3, został zaimplementowany własny wrapper umożliwiający komunikację między aplikacją a VW. Dodana została możliwość wywoływania skryptów shellowych (w języku bash) bezpośrednio ze środowiska Python3, dzięki czemu mogłyśmy uzyskać płynną komunikację.
Aby móc dostarczać poprawne dane wejściowe zarówno w trakcie procesu uczenia się jak i podczas szukania rozwiązania problemu, musiałyśmy dodać kilka modyfikacji do istniejących algorytmów. Domki oraz wysypiska dostają teraz dodatkowe oznaczenie jeśli zostały już odwiedzone.
Dodatkowo, podczas szukania rozwiązania istniejącymi algorytmami planowania ruchu, oprócz listy koordynatów agenta zwracamy listę komend, które wykonuje.
##### Komunikacja agent - VW
Dodałyśmy wiele funkcji obsługujących łącznośc między agentem oraz samą aplikacją a VW:
1. Parsery - mapują komendy oraz obiekty na liczby.
2. Generatory danych wejściowych:
- Generator danych do uczenia się - konwertuje listy ruchów, koordynatów i otoczenia na wiersze w formacie VW, po czym zapisuje je do pliku.
- Generator danych rzeczywistych - konwertuje listę obiektów w otoczeniu agenta o promieniu R = 1 na wiersz w formacie VW i zapisuje ją do pliku przeznaczonego do tymczasowego przechowywania danych.
3. Funkcja odczytująca obiekty w otoczeniu agenta o promieniu R = 1. Funkcja ta oblicza współrzędne lewego górnego rogu pola widzenia agenta w celu poprawnego zapisania obiektów w otoczeniu. Funkcja pomija współrzędne agenta oraz współrzędne będące poza siatką mapy.
4. Funkcja odczytująca wynik przewidywań VW. Funkcja ta odczytuje liczbę rzeczywistą zwrócona przez VW i mapuje ją do jednej z możliwych do wykonania przez agenta komend. Przewidywanie VW otrzymujemy przy użyciu komendy
vw -i ./VowpalWabbit/VowpalModels/100k_input.model -t ./VowpalWabbit/VowpalDataCahce/constant_input.txt -p ./vowpalWabbit/VowpalDataCahce/constant_output.txt
##### Format danych
Przedstawione poniżej tabele pokazują mapowania użyte podczas procesu generwania danych.
**Mapowanie obiektów na mapie**
| Obiekt | Cyfra |
| --- | --- |
| E: empty | 0 |
| R: road | 1 |
| H: house | 2 |
| V: visited house | 0 |
| Y: yellow dump | 2 |
| B: blue dump | 2 |
| G: green dump | 2 |
**Mapowanie komend**
| Komenda | Cyfra | Waga przykładu |
| --- | --- | --- |
| pick_garbage | 1 | 5.0 |
| right | 2 | 1.0 |
| left | 3 | 1.0 |
| up | 4 | 1.0 |
| down | 5 | 1.0 |
Jeżeli w polu widzenia agenta znajduje się nieodwiedzony domek, a nie ma on aktualnie do niego dostępu, to następny ruch jest wykonywany z wagą 3.0.
Wyjściowa linijka dla VW:
> akcja waga | F00:a F01:b F10:c F20:d F21:e
Gdzie *Fxy: a* to zmapowany na cyfrę obiekt a będący na koordynatach (x,y) w stosunku do prawego górnego rogu pola widzenia agenta.
Przykładowa linijka danych:
> 1 5.0 | F00:0.0 F01:1.0 F02:0.0 F10:2.0 F12:0.0 F20:0.0 F21:1.0 F22:1.0
##### Proces uczenia
Aby usprawnić proces zbierania danych dodałyśmy parametry wymagane przy starcie aplikacji. Dla projektu VowpalWabbit, zamiast
python3 ./main.py ./Resources/Maps/map_name.txt
od teraz wymagane są 2 do 3 argumentów:
- plik mapy (ścieżka do mapy lub "auto" dla losowo generowanych map)
- informacja, czy aplikacja ma się zamknąc po zakończeniu wykonywania jednego z wcześniej zaimplementowanych algorytmów (true / false)
- algorytm, który automatycznie uruchamia się po starcie aplikacji (bfs / dfs / bestfs / brak wartości jeżeli nie chcemy nic automatycznie włączać)
Przykładowe wywołanie komendy:
python3 ./main.py auto false dfs
W celu maksymalnego zautomatyzowania procesu uczenia się, stworzyłyśmy skrypt, które wszystkie potrzebne rzeczy robi za nas. Wymaga podania liczby uruchomień aplikacji, informacji, czy ma wyczyścić poprzednie dane, nazwę wyjściowego modelu oraz informację, czy po zakończeniu zbierania danych powinien od razu zacząć sie uczyć. Po uruchomieniu aplikacji wymaganą liczbę razy, skrypt zbiera dane z powstałych plików i tworzy z nich jeden plik .txt, który następnie przekazuje do VW za pomocą komendy
vw --oaa 5 data_set.txt -f data_model.model
Poniżej znajdują się parametry, dla których stworzyłyśmy dwa prezentowane modele:
| Nazwa | Liczba wykonań programu | Typ mapy | Przykładowy algorytm | Pole widzenia |
| --- | --- | --- | --- | --- |
| 1k.model | 1000 | auto | BestFS | 2 |
| 100.model | 100 | auto | BestFS | 1 |
W wyniku procesu zbierania danych, otrzymałyśmy dane w liczbie około 50 000 linii oraz 5 000 linii.
#### Obserwacje
Pomimo dostosowania danych wejściowych i ich parametrów agent nie zawsze podejmuje racjonalne ruchy. Za każdym razem gdy trafia na skrzyżowanie nie potrafi dostosować ruchu do sytuacji. Udało nam się jednak nauczyć agenta kierowania się w stronę nieodwiedzonego domku, jeżeli ma taki w polu widzenia.
Podczas obserwacji obu modeli doszłyśmy do wniosku, że agent o zwiększonym polu widzenia(model 1k.model) sprawuje się gorzej niż model o ograniczonym polu widzenia (mimo większej ilości danych).
---
Ze względu na to, że agent nie potrafi wyznaczyć odpowiedniego rozwiązania zadanego mu problemu ograniczyłyśmy przewidywanie do jednego ruchu.

View File

@ -33,7 +33,6 @@ def BFS(grid, available_movement, gc_moveset, mode):
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0: if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
cell = grid[location[0]][location[1]] cell = grid[location[0]][location[1]]
if(type(cell) == mode and cell.unvisited): if(type(cell) == mode and cell.unvisited):
cell.unvisited = False
object_in_area = True object_in_area = True
break break

View File

@ -15,7 +15,7 @@ def CalculateDistance(gc, object_list):
return min_distance_goal return min_distance_goal
def BestFS(grid, available_movement, gc_moveset, object_list, depth = 0): def BestFS(grid, available_movement, gc_moveset, object_list, depth = 0):
x, y = gc_moveset[-1][0], gc_moveset[-1][1] x, y = gc_moveset[-1][0], gc_moveset[-1][1]
#calculate distance to the nearest object #calculate distance to the nearest object
@ -25,11 +25,11 @@ def BestFS(grid, available_movement, gc_moveset, object_list, depth = 0):
gc_moveset.append("pick_garbage") gc_moveset.append("pick_garbage")
cell = grid[min_distance_goal[0][0]][min_distance_goal[0][1]] cell = grid[min_distance_goal[0][0]][min_distance_goal[0][1]]
object_list.remove([cell,min_distance_goal[0]]) object_list.remove([cell,min_distance_goal[0]])
return([x, y], gc_moveset, object_list) return([x, y], gc_moveset, object_list, cell)
#if depth exceeded, return #if depth exceeded, return
if(depth > 15 or len(available_movement) == 0): if(depth > 15 or len(available_movement) == 0):
return return
#set preffered directions based on the closest object #set preffered directions based on the closest object
preffered_directions = [] preffered_directions = []
@ -65,4 +65,4 @@ def BestFS(grid, available_movement, gc_moveset, object_list, depth = 0):
gc_moveset_next.append([x_next,y_next]) gc_moveset_next.append([x_next,y_next])
result = BestFS(grid, available_movement_next, gc_moveset_next, object_list, depth + 1) result = BestFS(grid, available_movement_next, gc_moveset_next, object_list, depth + 1)
if result!= None: if result!= None:
return result return result

View File

@ -5,7 +5,6 @@ from DataModels.Container import Container
from config import GRID_WIDTH, GRID_HEIGHT from config import GRID_WIDTH, GRID_HEIGHT
def DFS(grid, available_movement, gc_moveset, mode,depth=0): def DFS(grid, available_movement, gc_moveset, mode,depth=0):
possible_goals = [] possible_goals = []
a = gc_moveset[-1][0] a = gc_moveset[-1][0]
b = gc_moveset[-1][1] b = gc_moveset[-1][1]
@ -18,7 +17,6 @@ def DFS(grid, available_movement, gc_moveset, mode,depth=0):
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0: if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
cell = grid[location[0]][location[1]] cell = grid[location[0]][location[1]]
if(type(cell) == mode and cell.unvisited): if(type(cell) == mode and cell.unvisited):
cell.unvisited = False
object_in_area = True object_in_area = True
break break

View File

@ -0,0 +1 @@
1.0 | F00:0.0 F01:0.1 F02:0.0 F10:0.1 F12:0.0 F20:0.0 F21:0.1 F22:0.0

View File

@ -0,0 +1 @@
1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
import subprocess
def wrap_ex(command):
subprocess.check_call(["./VowpalWabbit/VowpalWrapper/wrapper_exec.sh", command])

View File

@ -0,0 +1,2 @@
#!/bin/bash
eval "$1"

View File

@ -0,0 +1,38 @@
import glob, datetime, os
from VowpalWrapper.wrapper import wrap_ex
def generate_dataset(run_count, clear, model_name, learn):
print("GENERATING DATASET")
if(clear == True):
print("Clearing stored data... ", end = '')
for dfile in glob.glob('./VowpalWabbit/VowpalInputData/input_map*.txt'):
if(os.path.exists(dfile)):
os.remove(dfile)
print("Done")
print("Collecting data from " + str(run_count) + " runs...")
wrap_ex("./VowpalWabbit/vowpal_auto_run.sh "+str(run_count))
print("Collected data")
filename = "./VowpalWabbit/VowpalInputData/input_dataset" + str(datetime.datetime.now().strftime("%m%d%H%M")) + model_name
print("Creating input file " + filename + ".txt... ", end = '')
input_file = open(filename,"a+")
for pfile in glob.glob('./VowpalWabbit/VowpalInputData/input_map*.txt'):
#print(pfile)
partial_input = open(pfile, "r+")
for line in partial_input:
input_file.write(line)
partial_input.close()
input_file.close()
os.rename(filename, filename + ".txt")
print("Done")
if(learn == True):
print("Learning from " + str(filename) + ".txt")
model_file = "./VowpalWabbit/VowpalModels/" + model_name + ".model"
wrap_ex("vw --oaa 5 " + filename + ".txt -f " + model_file)
print("Learning process complete, model saved to " + model_file)
generate_dataset(100, True, "100", True)

View File

@ -0,0 +1,6 @@
#!/bin/bash
for ((i=1; i<=$1; i++))
do
echo "Run "$i"/"$1
python3 ./main.py auto true bestfs
done

View File

@ -0,0 +1,177 @@
import re, os
from config import MAP_NAME, GRID_WIDTH, GRID_HEIGHT, GC_X, GC_Y
from VowpalWabbit.VowpalWrapper import wrapper
#const
RADIUS = 1
##
COORDINATES_LIST = []
MOVES_LIST = []
with open( MAP_NAME, 'r' ) as map:
MAP_CONTENT = map.readlines()[2:]
MAP_CONTENT = [list(row.strip().replace(" ","")) for row in MAP_CONTENT]
moves_mapping = {
"pick_garbage": 1,
"right": 2,
"left": 3,
"up": 4,
"down": 5
}
predictions_mapping = {
1 : "pick_garbage",
2 : "right",
3 : "left",
4 : "up",
5 : "down"
}
environment_mapping = {
"E":0,
"R":1,
"H":2,
"V":0,
"Y":2,
"B":2,
"G":2
}
def parse_list(whole_result,current_x,current_y):
global COORDINATES_LIST, MOVES_LIST
COORDINATES_LIST = whole_result.copy()
moves = []
primary_x = current_x
primary_y = current_y
#print("x,y",current_x,current_y,"list",whole_result)
parser = {'[0,1]':"down",'[0,-1]':"up",'[1,0]':"right",'[-1,0]':"left"}
for x in range(len(whole_result)):
if whole_result[x]=="pick_garbage":
moves.append(whole_result[x])
else:
x_subtraction = whole_result[x][0] - current_x
y_subtraction = whole_result[x][1] - current_y
current_x = whole_result[x][0]
current_y = whole_result[x][1]
moves.append(parser[f"[{x_subtraction},{y_subtraction}]"])
#print(moves)
MOVES_LIST = moves.copy()
generate_input([primary_x,primary_y])
return moves
def generate_input(current_position):
i = 0 #we'll use it to map coords to moves
input_file_content = []
for position in COORDINATES_LIST:
coords = check_position(current_position, i) #set valid gc position
#vowpal config goes here
importance = 1.0
label = moves_mapping[MOVES_LIST[i]]
area,importance = get_gc_area(coords, RADIUS)
if importance == None:
importance = 1.0
if MOVES_LIST[i] == "pick_garbage":
importance = 5.0
input_line = str(label) + " " + str(importance) + " | "
print ( predictions_mapping[label]+" " +str(importance)+ " |", end = " " )
current_position = position
for a in area:
input_line += a + " "
print( a ,end =" ")
i += 1
print()
input_file_content.append(input_line)
#save to file
tag = re.findall("(map_[0-9]+|map[0-9]+_auto)", MAP_NAME)[0]
filename = "./VowpalWabbit/VowpalInputData/input_" + str(tag) + ".txt"
input_file = open(filename,"a+")
for line in input_file_content:
input_file.write(line+"\n")
input_file.close()
def pass_input(position):
area,importance = get_gc_area(position, RADIUS)
print(get_gc_area(position,1)[0])
if importance==None:
importance = 1.0
input_line = str(importance) + " | "
for a in area:
input_line += a + " "
print(input_line)
#save to file
filename = "./VowpalWabbit/VowpalDataCache/constant_input.txt"
input_file = open(filename,"w+")
input_file.write(input_line)
input_file.close()
return filename
def get_gc_area(position, radius):
area = []
upper_right_coord = [position[0] - radius, position[1] - radius]
importance = None
for x in range(max(0, position[0] - radius), min(position[0] + radius + 1, GRID_WIDTH)): #prevents going abroad
for y in range(max(0, position[1] - radius), min(position[1] + radius + 1, GRID_HEIGHT)):
if([x,y] == position): #we dont need gc data here
continue
if MAP_CONTENT[y][x] == 'H' or MAP_CONTENT[y][x] == 'B' or MAP_CONTENT[y][x] == 'Y' or MAP_CONTENT[y][x] == 'G':
importance = 3.0
area.append("F"+str(x - upper_right_coord[0])+str(y - upper_right_coord[1])+":0."+str(environment_mapping[MAP_CONTENT[y][x]]))
return area,importance
def check_position(position, i):
if(type(position) is list): #if position valid, return it
return position
elif(position == "pick_garbage"): #if invalid, look for recent coords. if not found, return initial coords
for j in range(i-1,-1,-1):
if(type(COORDINATES_LIST[j]) is list):
return COORDINATES_LIST[j]
return [GC_X, GC_Y]
else: #in case sh t happened
print("An error has ocurred while processing GC position.")
def get_predicted_move(position):
input_filename = pass_input(position)
output_filename = "./VowpalWabbit/VowpalDataCache/constant_output.txt"
command = "vw --oaa 5 -i ./VowpalWabbit/VowpalModels/100.model -t "+input_filename+" -p "+output_filename
print(command)
wrapper.wrap_ex(command)
with open( output_filename, 'r' ) as fout:
prediction = float(list(fout.readline().split())[0])
move = make_move_from_prediction(prediction)
print(position, prediction, move)
if(move == "pick_garbage"):
new_position = move
else:
axis = 0
if(move in ["up", "down"]):
axis = 1
direction = 1
if(move in ["up", "left"]):
direction = -1
new_position = position.copy()
new_position[axis] += direction
if(axis == 1 and (new_position[axis] < 0 or new_position[axis] >= GRID_HEIGHT)):
new_position = position.copy()
print("VIOLATED GRID HEIGHT")
if(axis == 0 and (new_position[axis] < 0 or new_position[axis] >= GRID_WIDTH)):
new_position = position.copy()
print("VIOLATED GRID WIDTH")
return move, new_position
def make_move_from_prediction(prediction):
if(prediction > 4.5):
move = predictions_mapping[5]
elif(prediction > 3.5):
move = predictions_mapping[4]
elif(prediction > 2.5):
move = predictions_mapping[3]
elif(prediction > 1.5):
move = predictions_mapping[2]
else:
move = predictions_mapping[1]
return move

View File

@ -1,15 +1,34 @@
import sys, random import sys, random, MapGenerator
from MapGenerator import GenerateMap
CELL_SIZE = 64 CELL_SIZE = 64
FPS = 60 FPS = 60
DELAY = 50 DELAY = 5
try: try:
MAP_NAME = sys.argv[1] map_mode = sys.argv[1]
if(map_mode == "auto"):
MAP_NAME = MapGenerator.GenerateMap()
else:
MAP_NAME = map_mode
except: except:
MAP_NAME = GenerateMap() print("ERROR: Invalid map mode\n Please enter \"auto\" for generated map or provide a path to an existing map.")
sys.exit()
if(len(sys.argv)>2):
CLOSE_ON_END = sys.argv[2]
if(CLOSE_ON_END != "true" and CLOSE_ON_END != "false"):
print("ERROR: Invalid close on end statement\n Please enter \"true\" or \"false\" to specify if app has to shut after finding solution.")
sys.exit()
else:
print("ERROR: Invalid close on end statement\n Please enter \"true\" or \"false\" to specify if app has to shut after finding solution.")
sys.exit()
ALGORITHM = None
if(len(sys.argv)>3):
ALGORITHM = sys.argv[3]
if(ALGORITHM != "bfs" and ALGORITHM != "dfs" and ALGORITHM!= "bestfs"):
print("ERROR: Invalid algorithm statement\n Please enter \"bfs\", \"dfs\" or \"bestfs\" to specify algorithm you want to use.")
sys.exit()
map = open( MAP_NAME, 'r' ) map = open( MAP_NAME, 'r' )

23
main.py Normal file → Executable file
View File

@ -3,16 +3,14 @@
import pygame import pygame
import sys import sys
from random import randint from random import randint
from config import WINDOW_HEIGHT, WINDOW_WIDTH, GRID_HEIGHT, GRID_WIDTH, HOUSE_CAPACITY, FPS, GC_X, GC_Y, MAP_NAME from config import WINDOW_HEIGHT, WINDOW_WIDTH, GRID_HEIGHT, GRID_WIDTH, HOUSE_CAPACITY, FPS, GC_X, GC_Y, MAP_NAME, ALGORITHM
from PIL import Image,ImageDraw from PIL import Image,ImageDraw
from DataModels.Grass import Grass from DataModels.Grass import Grass
from DataModels.House import House from DataModels.House import House
from DataModels.Dump import Dump from DataModels.Dump import Dump
from DataModels.Road import Road from DataModels.Road import Road
from DataModels.GC import GC from DataModels.GC import GC
from utilities import unvisit_dump
pygame.init() pygame.init()
pygame_sprites = pygame.sprite.Group() pygame_sprites = pygame.sprite.Group()
@ -21,6 +19,8 @@ dump_count=0
FPS_CLOCK = pygame.time.Clock() FPS_CLOCK = pygame.time.Clock()
GAME_WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0, 32) GAME_WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0, 32)
algorithm = ALGORITHM
map = open(MAP_NAME, 'r') map = open(MAP_NAME, 'r')
map.readline() map.readline()
map.readline() map.readline()
@ -77,12 +77,21 @@ for line in map_objects:
for item in line: for item in line:
pygame_sprites.add(item) pygame_sprites.add(item)
gc = GC(GC_X, GC_Y, 200) gc = GC(GC_X, GC_Y,map_objects, 200)
print("GC: " + str(GC_X) + str(GC_Y)) #print("GC: " + str(GC_X) + str(GC_Y))
pygame_sprites.add(gc) pygame_sprites.add(gc)
while True: while True:
if(algorithm != None):
if(algorithm == "bfs"):
gc.find_houses(map_objects,house_count,dump_count, "BFS")
elif(algorithm == "dfs"):
gc.find_houses(map_objects,house_count,dump_count, "DFS")
elif (algorithm == "bestfs"):
gc.find_houses_BestFS(map_objects)
algorithm = None
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
pygame.quit() pygame.quit()
@ -104,6 +113,8 @@ while True:
gc.find_houses_BestFS(map_objects) gc.find_houses_BestFS(map_objects)
elif event.key == pygame.K_8: elif event.key == pygame.K_8:
gc.find_houses(map_objects,house_count,dump_count, "BFS") gc.find_houses(map_objects,house_count,dump_count, "BFS")
elif event.key == pygame.K_1:
gc.run_vw(map_objects,house_count)
gc.make_actions_from_list(map_objects) gc.make_actions_from_list(map_objects)
pygame_sprites.update() pygame_sprites.update()

View File

@ -1,7 +1,7 @@
from config import GRID_WIDTH, GRID_HEIGHT from config import GRID_WIDTH, GRID_HEIGHT
from DataModels.Road import Road from DataModels.Road import Road
import json, os, platform from DataModels.Dump import Dump
import platform,os,json
def movement(environment, x ,y): def movement(environment, x ,y):
movement = { movement = {
"right": (x + 1, y) if x + 1 < GRID_WIDTH and type(environment[x + 1][y]) == Road else (x, y), "right": (x + 1, y) if x + 1 < GRID_WIDTH and type(environment[x + 1][y]) == Road else (x, y),
@ -30,7 +30,7 @@ def save_moveset(moveset):
else: else:
path = '/moveset_data.json' path = '/moveset_data.json'
output_file = os.path.normpath(os.getcwd()) + path output_file = os.path.normpath(os.getcwd()) + path
results = {} results = {}
try: try:
f = open(output_file, 'r+') f = open(output_file, 'r+')
@ -38,16 +38,25 @@ def save_moveset(moveset):
open(output_file, 'a').close() open(output_file, 'a').close()
finally: finally:
f = open(output_file, 'r+') f = open(output_file, 'r+')
try: try:
results = json.load(f) results = json.load(f)
except: except:
pass pass
finally: finally:
if "moveset" not in results: if "moveset" not in results:
results = { "moveset": [] } results = { "moveset": [] }
results["moveset"].append(moveset) results["moveset"].append(moveset)
f.seek(0) f.seek(0)
json.dump(results, f, indent=1) json.dump(results, f, indent=1)
f.close() f.close()
def unvisit_dump(enviromnent):
dump = []
for x in enviromnent:
for y in x:
if type(y) == Dump:
dump.append(y)
for x in dump:
x.Visit()