Compare commits
53 Commits
master
...
VowpalWabb
Author | SHA1 | Date | |
---|---|---|---|
|
7ee29820a6 | ||
|
8ca6b13fb3 | ||
6d21be1665 | |||
bfa30af3b2 | |||
bc655dded2 | |||
b55707b543 | |||
1ee731eec5 | |||
d67ed545dc | |||
794f80c1a7 | |||
3824702e4d | |||
|
118a8a1b1d | ||
|
8d6501708e | ||
83d95f008b | |||
|
b1a25ecc77 | ||
a8a0f97f3a | |||
|
00563e34f2 | ||
923251016a | |||
|
2e9d079d87 | ||
22550b92ec | |||
|
320c702482 | ||
|
3ba1f27d63 | ||
cf6172b5b2 | |||
78c4b6f01c | |||
dc14001bc5 | |||
89d0c03949 | |||
98b232a982 | |||
|
f48a725712 | ||
|
49c5c2aef4 | ||
|
737f59671d | ||
a49f41d681 | |||
|
09ff70271a | ||
|
ab69d0d986 | ||
d9e0bf434b | |||
f509230f60 | |||
0b2b255a20 | |||
813cf2accb | |||
28d2faaaed | |||
0c87e6de66 | |||
cf3bf3d4f5 | |||
|
d9fc9e1384 | ||
|
7d80f5c05f | ||
|
28c6dd4744 | ||
|
35fe3314f2 | ||
|
d9d65c249f | ||
d95378c72e | |||
913dba936f | |||
c969355d70 | |||
42d124cc6e | |||
|
94064f5d03 | ||
|
635292d9f5 | ||
|
15f88b9e20 | ||
|
abb6dbb5dd | ||
22e4a12eff |
@ -1,5 +1,6 @@
|
||||
import pygame
|
||||
from DataModels.Cell import Cell
|
||||
from VowpalWabbit.vowpal_utils import MAP_CONTENT
|
||||
|
||||
class Dump( Cell ):
|
||||
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])
|
||||
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"
|
||||
|
@ -2,26 +2,29 @@ from DataModels.Cell import Cell
|
||||
from DataModels.Road import Road
|
||||
from DataModels.House import House
|
||||
from DataModels.Dump import Dump
|
||||
from config import GRID_WIDTH, GRID_HEIGHT, DELAY
|
||||
from utilities import movement, check_moves, save_moveset
|
||||
from config import GRID_WIDTH, GRID_HEIGHT, DELAY, CLOSE_ON_END
|
||||
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.BestFS import BestFS
|
||||
from Traversal.BFS import BFS
|
||||
import pygame
|
||||
import pygame, sys
|
||||
|
||||
class GC(Cell):
|
||||
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)
|
||||
self.moves = []
|
||||
self.old_time = pygame.time.get_ticks()
|
||||
self.vowpal_house_visited = 0
|
||||
unvisit_dump(map_objects)
|
||||
|
||||
def move(self, direction, environment):
|
||||
self.x, self.y = movement(environment, self.x, self.y)[0][direction]
|
||||
self.update_rect(self.x, self.y)
|
||||
self.moves_made = self.moves_made + 1 #moves counter
|
||||
|
||||
print(check_moves(environment, self.x, self.y,direction))
|
||||
|
||||
def collect(self, enviromnent):
|
||||
x, y = [self.x, self.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
|
||||
|
||||
def find_houses(self,enviromnent, house_count,dump_count, mode):
|
||||
self.algorithm_run = True
|
||||
|
||||
x = self.x
|
||||
y = self.y
|
||||
result = []
|
||||
element_list=[]
|
||||
house_count_after_search=house_count
|
||||
for home in range(house_count):
|
||||
last_x = x
|
||||
last_y = y
|
||||
avalible_moves = check_moves(enviromnent, x,y)
|
||||
if mode == "DFS":
|
||||
house,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],House)
|
||||
elif mode == "BFS":
|
||||
house,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],House)
|
||||
result = result[1::]
|
||||
self.moves.extend(result)
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
element_list.append(house)
|
||||
|
||||
house.Visit()
|
||||
unvisit_dump(enviromnent)
|
||||
for dump in range(dump_count):
|
||||
last_x = x
|
||||
last_y = y
|
||||
avalible_moves = check_moves(enviromnent, x,y)
|
||||
if mode == "DFS":
|
||||
dump,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],Dump)
|
||||
elif mode == "BFS":
|
||||
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)
|
||||
dump.Visit()
|
||||
for x in element_list:
|
||||
x.unvisited = True
|
||||
x.Visit()
|
||||
self.moves.reverse()
|
||||
save_moveset(self.moves)
|
||||
|
||||
|
||||
def find_houses_BestFS(self, environment):
|
||||
self.algorithm_run = True
|
||||
|
||||
x = self.x
|
||||
y = self.y
|
||||
result = [[x,y]]
|
||||
|
||||
houses_list = []
|
||||
dump_list = []
|
||||
a = 0
|
||||
for row in environment:
|
||||
b = 0
|
||||
for col in row:
|
||||
if (type(col) is House):
|
||||
for col in row:
|
||||
if (type(col) is House):
|
||||
houses_list.append([col,[a,b]])
|
||||
if (type(col) is Dump):
|
||||
dump_list.append([col,[a,b]])
|
||||
if (type(col) is Dump):
|
||||
dump_list.append([col,[a,b]])
|
||||
b += 1
|
||||
a += 1
|
||||
|
||||
|
||||
x, y = self.x, self.y
|
||||
|
||||
for i in range(len(houses_list)):
|
||||
last_x = x
|
||||
last_y = y
|
||||
available_movement = check_moves(environment, x, y)
|
||||
output = BestFS(environment, available_movement, [[x,y]], houses_list)
|
||||
if(output != None):
|
||||
[x,y],result,houses_list = output[0], output[1], output[2]
|
||||
self.moves.extend(result[1:])
|
||||
[x,y],result,houses_list,house = output[0], output[1], output[2], output[3]
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
house.Visit()
|
||||
unvisit_dump(environment)
|
||||
for i in range(len(dump_list)):
|
||||
last_x = x
|
||||
last_y = y
|
||||
available_movement = check_moves(environment, x, y)
|
||||
output = BestFS(environment, available_movement, [[x,y]], dump_list)
|
||||
if(output != None):
|
||||
[x,y],result,dump_list = output[0], output[1], output[2]
|
||||
self.moves.extend(result[1:])
|
||||
[x,y],result,dump_list,dump = output[0], output[1], output[2], output[3]
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
dump.Visit()
|
||||
self.moves.reverse()
|
||||
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):
|
||||
now = pygame.time.get_ticks()
|
||||
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
|
||||
|
||||
self.old_time = pygame.time.get_ticks()
|
||||
if self.moves[-1] == "pick_garbage":
|
||||
self.collect(environment)
|
||||
self.moves.pop()
|
||||
return
|
||||
self.x, self.y = self.moves.pop()
|
||||
self.moves_made = self.moves_made + 1 #moves counter
|
||||
self.update_rect(self.x,self.y)
|
||||
self.move(self.moves[-1],environment)
|
||||
self.moves.pop()
|
||||
|
@ -1,5 +1,5 @@
|
||||
from DataModels.Cell import Cell
|
||||
|
||||
from VowpalWabbit.vowpal_utils import MAP_CONTENT
|
||||
|
||||
class House(Cell):
|
||||
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])
|
||||
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"
|
||||
|
@ -141,13 +141,13 @@ def GenerateMap():
|
||||
GC_position = random.choice(roads)
|
||||
|
||||
#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.write(str(width)+" "+str(height)+"\n")
|
||||
map_file.write(str(GC_position[0])+" "+str(GC_position[1])+"\n")
|
||||
for row in grid:
|
||||
map_file.write(" ".join(row)+"\n")
|
||||
map_file.close()
|
||||
print(name)
|
||||
#print(name)
|
||||
|
||||
return(name)
|
104
Raports/SI_Raport_VowpalWabbit.md
Normal file
104
Raports/SI_Raport_VowpalWabbit.md
Normal 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.
|
@ -1,89 +0,0 @@
|
||||
---
|
||||
|
||||
# SVM raport
|
||||
|
||||
##### Konrad Pierzyński
|
||||
|
||||
###### Śmieciarz
|
||||
|
||||
12.06.2019
|
||||
|
||||
---
|
||||
|
||||
**SVM** - **S**upport-**V**ector **M**achine - zestaw metod uczenia stosowanych głównie do klasyfikacji, której nauka ma na celu wyznaczenie płaszczyzn rozdzielających dane wejściowe na klasy.
|
||||
|
||||
![5d00b5469956838867](https://i.loli.net/2019/06/12/5d00b5469956838867.png)
|
||||
|
||||
---
|
||||
|
||||
### Przygotowanie danych
|
||||
|
||||
Dane uczące zostały wygenerowane w następujący sposób:
|
||||
|
||||
+ Program generuje losową mapę o określonych wymiarach
|
||||
|
||||
+ Uruchamiany jest jeden z algorytmów (*BestFirstSearch*), który generuje listę ruchów.
|
||||
|
||||
+ Do zestawu uczącego dopisywana jest para składająca się na ruch i otoczenie gracza.
|
||||
|
||||
- Ruch odpowiada kierunkom: góra, prawo, dół, lewo i akcji zebrania/oddania śmieci - odpowienio liczbowo 1, 2, 3, 4, 99
|
||||
|
||||
- Otocznie to tablica dwuwymiarowa 7x7, gdzie element środkowy to pozycja gracza. Tablica ta następnie spłaszczana jest do tablicy jednowymiarowej
|
||||
|
||||
- Każdy 'domek', na którym została wykonana już akcja zebrania i jest opróżniony, widoczny jest na mapie tak samo jak element otoczenia, z którym gracz nie może wejść w żadną interakcję (stanąć, zebrać)
|
||||
|
||||
- Jeśli siatka 7x7 wykracza swoim zakresem za mapę, siatka uzupełniana jest przez trawę, czyli obiekt, z którym gracz nie wchodzi w interakcję
|
||||
|
||||
+ Po przejściu całej mapy algorytmem i zebraniu danych proces jest powtarzany tak długo, by zgromadzić około tysiąc rozwiązanych map
|
||||
|
||||
Pojedynczy zestaw danych jest zapisywany jako json postaci:
|
||||
|
||||
```json
|
||||
{
|
||||
"maps": [
|
||||
[Int, Int, ...],
|
||||
[Int, Int, ...],
|
||||
...
|
||||
],
|
||||
"moves":
|
||||
[
|
||||
Int, Int, ...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
I dopisywany do głównej struktury:
|
||||
|
||||
```json
|
||||
{
|
||||
"moveset": [
|
||||
Zestaw, Zestaw, ...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Uczenie
|
||||
|
||||
Do przeprowadzenia procesu uczenia dane uczące zostały podzielone na dwie listy:
|
||||
|
||||
- Pierwsza lista X zawiera wszystkie mapy częściowe (otoczenia)
|
||||
|
||||
```X = [ [Int, Int, ...], [Int, Int, ...], ... ]```
|
||||
|
||||
- Druga lista y zawiera odpowiadające mapom ruchy (1,2,3,4,99), które wykonał algorytm (*BestFirstSearch*) na danych otoczeniach.
|
||||
|
||||
```y = [ Int, Int, ... ]```
|
||||
|
||||
Wyżej wymienione dwie listy zostały podane jako argument metodzie ```fit(X,y)```, która odpowiada za uczenie się SVM. Natomiast utworzenie samego obiektu polega na zaimportowaniu biblioteki *scikit-learn*:
|
||||
```from sklearn import svm```
|
||||
a następnie już same utworzenia obiektu svm:
|
||||
```clf = svm.SVC(gamma='scale')```
|
||||
Wyuczony obiekt jest zapisywany do pliku, dzięki modułowi ```pickle```, aby nie przeprowadzać procesu uczenia za każdym uruchomieniem programu.
|
||||
|
||||
---
|
||||
|
||||
### Wykonywanie ruchów
|
||||
|
||||
Do przewidywania ruchów wystarczy użyć metody ```predict([ [otoczenie] ])``` , które przyjmuje mapę częściową, a jej wynik jest akcją, którą powinien wykonać gracz. Wynik metody przekazywany jest graczowi, który wykonuje ruch.
|
@ -1,92 +0,0 @@
|
||||
# Sztuczna Inteligencja 2019 - Raport Indywidualny
|
||||
|
||||
**Czas trwania opisywanych prac:** 09.05.2019 - 11.06.2019
|
||||
|
||||
**Autor:** Michał Starski
|
||||
|
||||
**Wybrany temat:** Inteligentna śmieciarka
|
||||
|
||||
**Link do repozytorium projektu:** https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi
|
||||
|
||||
## Wybrany algorytm uczenia - drzewa decyzyjne
|
||||
|
||||
### Przygotowane dane
|
||||
|
||||
Aby zapewnić smieciarce jak najlepszy wynik, do przygotowania danych do uczenia wybrałem algorytm szukania najkrótszej ścieżki, który dawał najlepsze wyniki podczas projektu grupowego - **BestFS**.
|
||||
|
||||
Podczas każdego jednorazowego przebiegu algorytmu BestFS patrzyłem na to jaki krok śmieciarka wykonuje w danej sytuacji, a następnie dane kroki zapisywałem do pliku w formacie json, tworząc próbki do późniejszej nauki.
|
||||
|
||||
Przykładowa próbka w formacie json:
|
||||
|
||||
```json
|
||||
{
|
||||
"moveset": [
|
||||
{
|
||||
"maps": [[1, 1, 3, 4, 2, 2, 2, 2, 1], [2, 1, 1, 3, 1, 4, 1, 1, 1]],
|
||||
"moves": [1, 2]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`moveset` to tablica wszystkich próbek wykorzystywanych do nauki.
|
||||
Każdy element tablicy to obiekt posiadający dwa pola:
|
||||
`maps` - otoczenie śmieciarki w danym kroku,
|
||||
`moves` - ruch śmieciarki przy danym otoczeniu
|
||||
|
||||
W powyższym przykładzie dla czytelności, zostały przedstawione otoczenia 3x3 wokół śmieciarki. W implementacji obszar ten został powiększony do 7x7 w celu poprawienia dokładności algorytmu.
|
||||
|
||||
#### Maps
|
||||
|
||||
Spłaszczona tablicę dwuwymiarową przedstawiająca otoczenie śmieciarki w konkretnym momencie działania algorytmu. Każda z cyfr przedstawia inny obiekt na mapie:
|
||||
|
||||
- 1 - Trawa (Grass)
|
||||
- 2 - Droga (Road)
|
||||
- 3 - Wysypisko (Dump)
|
||||
- 4 - Dom (House)
|
||||
|
||||
Dla powyższego przykładu pierwsza sytuacja (`moveset[0].maps[0]`) przedstawia następujące otoczenie na mapie
|
||||
|
||||
```
|
||||
G G D
|
||||
H R R
|
||||
R R G
|
||||
```
|
||||
|
||||
#### Moves
|
||||
|
||||
Tablica ruchów śmieciarki. i-ty ruch w tablicy odpowiada i-temu otoczeniu. Wyróżnimay 5 różnych ruchów agenta:
|
||||
|
||||
- 1 - Lewo
|
||||
- 2 - Prawo
|
||||
- 3 - Dół
|
||||
- 4 - Góra
|
||||
- 99 - Zbierz śmieci
|
||||
|
||||
Tak więc dla powyższego otoczenia `1` będzie oznaczać, że agent ruszył się w lewo.
|
||||
|
||||
---
|
||||
|
||||
### Implementacja
|
||||
|
||||
Do implementacji uczenia poprzez drzewo decyzyjny wykorzystałem bibliotekę [scikit learn](https://scikit-learn.org) do języka **python**. Podając odpowiednie dane, biblioteka przygotuje nam model zdolny do samodzielnego poruszania się na mapie.
|
||||
|
||||
```python
|
||||
#Trenowanie modelu
|
||||
from sklearn import tree
|
||||
X = [Kolejne otoczenia 7x7 w danym kroku]
|
||||
Y = [Kolejne kroki odpowiednie dla danego otoczenia]
|
||||
clf = tree.DecisionTreeClassifier()
|
||||
clf = clf.fit(X, Y)
|
||||
|
||||
#Samodzielny ruch wytrenowanego modelu
|
||||
clf.predict([Otoczenie agenta])
|
||||
```
|
||||
|
||||
`clf.predict` zwróci nam 1 z 5 ruchów, które ma wykonać agent.
|
||||
|
||||
---
|
||||
|
||||
### Obserwacje
|
||||
|
||||
W idealnym przypadku wytrenowany model powinien odzwierciedlać algorytm BestFS, jako iż to na podstawie jego był trenowany i to jego decyzje starał się naśladować. W rzeczywistości jednak po przygotowaniu ok. 1000 próbek agent radził sobie różnorako. Na jednych mapach poruszał się dość sprawnie, jednak na wielu nie wiedział co ma robić. Przyczyny mogą być różne, jednak w mojej opinii, przygotowanych danych było jednak trochę za mało i gdyby dać o wiele więcej danych do wytrenowania modelu, rezultat byłby o wiele lepszy.
|
@ -33,7 +33,6 @@ def BFS(grid, available_movement, gc_moveset, mode):
|
||||
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
|
||||
cell = grid[location[0]][location[1]]
|
||||
if(type(cell) == mode and cell.unvisited):
|
||||
cell.unvisited = False
|
||||
object_in_area = True
|
||||
break
|
||||
|
||||
|
@ -15,7 +15,7 @@ def CalculateDistance(gc, object_list):
|
||||
return min_distance_goal
|
||||
|
||||
def BestFS(grid, available_movement, gc_moveset, object_list, depth = 0):
|
||||
|
||||
|
||||
x, y = gc_moveset[-1][0], gc_moveset[-1][1]
|
||||
|
||||
#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")
|
||||
cell = grid[min_distance_goal[0][0]][min_distance_goal[0][1]]
|
||||
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 > 15 or len(available_movement) == 0):
|
||||
return
|
||||
return
|
||||
|
||||
#set preffered directions based on the closest object
|
||||
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])
|
||||
result = BestFS(grid, available_movement_next, gc_moveset_next, object_list, depth + 1)
|
||||
if result!= None:
|
||||
return result
|
||||
return result
|
||||
|
@ -5,7 +5,6 @@ from DataModels.Container import Container
|
||||
from config import GRID_WIDTH, GRID_HEIGHT
|
||||
|
||||
def DFS(grid, available_movement, gc_moveset, mode,depth=0):
|
||||
|
||||
possible_goals = []
|
||||
a = gc_moveset[-1][0]
|
||||
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:
|
||||
cell = grid[location[0]][location[1]]
|
||||
if(type(cell) == mode and cell.unvisited):
|
||||
cell.unvisited = False
|
||||
object_in_area = True
|
||||
break
|
||||
|
||||
|
1
VowpalWabbit/VowpalDataCache/constant_input.txt
Normal file
1
VowpalWabbit/VowpalDataCache/constant_input.txt
Normal 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
|
1
VowpalWabbit/VowpalDataCache/constant_output.txt
Normal file
1
VowpalWabbit/VowpalDataCache/constant_output.txt
Normal file
@ -0,0 +1 @@
|
||||
1
|
52208
VowpalWabbit/VowpalInputData/input_dataset061200291k.txt
Normal file
52208
VowpalWabbit/VowpalInputData/input_dataset061200291k.txt
Normal file
File diff suppressed because it is too large
Load Diff
5404
VowpalWabbit/VowpalInputData/input_dataset06121019100.txt
Normal file
5404
VowpalWabbit/VowpalInputData/input_dataset06121019100.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
VowpalWabbit/VowpalModels/100.model
Normal file
BIN
VowpalWabbit/VowpalModels/100.model
Normal file
Binary file not shown.
BIN
VowpalWabbit/VowpalModels/1k.model
Normal file
BIN
VowpalWabbit/VowpalModels/1k.model
Normal file
Binary file not shown.
4
VowpalWabbit/VowpalWrapper/wrapper.py
Normal file
4
VowpalWabbit/VowpalWrapper/wrapper.py
Normal file
@ -0,0 +1,4 @@
|
||||
import subprocess
|
||||
|
||||
def wrap_ex(command):
|
||||
subprocess.check_call(["./VowpalWabbit/VowpalWrapper/wrapper_exec.sh", command])
|
2
VowpalWabbit/VowpalWrapper/wrapper_exec.sh
Executable file
2
VowpalWabbit/VowpalWrapper/wrapper_exec.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
eval "$1"
|
38
VowpalWabbit/generate_dataset.py
Normal file
38
VowpalWabbit/generate_dataset.py
Normal 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)
|
6
VowpalWabbit/vowpal_auto_run.sh
Executable file
6
VowpalWabbit/vowpal_auto_run.sh
Executable 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
|
177
VowpalWabbit/vowpal_utils.py
Normal file
177
VowpalWabbit/vowpal_utils.py
Normal 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
|
29
config.py
29
config.py
@ -1,15 +1,34 @@
|
||||
import sys, random
|
||||
from MapGenerator import GenerateMap
|
||||
import sys, random, MapGenerator
|
||||
|
||||
CELL_SIZE = 64
|
||||
FPS = 60
|
||||
DELAY = 50
|
||||
DELAY = 5
|
||||
|
||||
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:
|
||||
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' )
|
||||
|
||||
|
23
main.py
Normal file → Executable file
23
main.py
Normal file → Executable file
@ -3,16 +3,14 @@
|
||||
import pygame
|
||||
import sys
|
||||
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 DataModels.Grass import Grass
|
||||
from DataModels.House import House
|
||||
from DataModels.Dump import Dump
|
||||
from DataModels.Road import Road
|
||||
from DataModels.GC import GC
|
||||
|
||||
from utilities import unvisit_dump
|
||||
pygame.init()
|
||||
|
||||
pygame_sprites = pygame.sprite.Group()
|
||||
@ -21,6 +19,8 @@ dump_count=0
|
||||
FPS_CLOCK = pygame.time.Clock()
|
||||
GAME_WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0, 32)
|
||||
|
||||
algorithm = ALGORITHM
|
||||
|
||||
map = open(MAP_NAME, 'r')
|
||||
map.readline()
|
||||
map.readline()
|
||||
@ -77,12 +77,21 @@ for line in map_objects:
|
||||
for item in line:
|
||||
pygame_sprites.add(item)
|
||||
|
||||
gc = GC(GC_X, GC_Y, 200)
|
||||
print("GC: " + str(GC_X) + str(GC_Y))
|
||||
gc = GC(GC_X, GC_Y,map_objects, 200)
|
||||
#print("GC: " + str(GC_X) + str(GC_Y))
|
||||
pygame_sprites.add(gc)
|
||||
|
||||
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():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
@ -104,6 +113,8 @@ while True:
|
||||
gc.find_houses_BestFS(map_objects)
|
||||
elif event.key == pygame.K_8:
|
||||
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)
|
||||
pygame_sprites.update()
|
||||
|
23
utilities.py
23
utilities.py
@ -1,7 +1,7 @@
|
||||
from config import GRID_WIDTH, GRID_HEIGHT
|
||||
from DataModels.Road import Road
|
||||
import json, os, platform
|
||||
|
||||
from DataModels.Dump import Dump
|
||||
import platform,os,json
|
||||
def movement(environment, x ,y):
|
||||
movement = {
|
||||
"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:
|
||||
path = '/moveset_data.json'
|
||||
output_file = os.path.normpath(os.getcwd()) + path
|
||||
|
||||
|
||||
results = {}
|
||||
try:
|
||||
f = open(output_file, 'r+')
|
||||
@ -38,16 +38,25 @@ def save_moveset(moveset):
|
||||
open(output_file, 'a').close()
|
||||
finally:
|
||||
f = open(output_file, 'r+')
|
||||
|
||||
|
||||
try:
|
||||
results = json.load(f)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
finally:
|
||||
if "moveset" not in results:
|
||||
results = { "moveset": [] }
|
||||
|
||||
|
||||
results["moveset"].append(moveset)
|
||||
f.seek(0)
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user