Zaktualizuj 'route-planning.md'
This commit is contained in:
parent
ab046705c8
commit
ce9956ee17
@ -1,159 +1,159 @@
|
||||
# *Sztuczna inteligencja - projekt zespołowy - Autonomiczny Traktor*
|
||||
|
||||
#### autorzy: Aleksandra Werda, Natalia Wiśniewska, Kinga Jagodzińska, Aleksandra Jonas
|
||||
***
|
||||
## Planowanie ruchu
|
||||
|
||||
|
||||
- schemat procedury przeszukiwania grafu stanów z uwzględnieniem kosztu
|
||||
- strategia A*
|
||||
|
||||
___
|
||||
|
||||
Drugim zadaniem dotyczącym projektu jest zastosowanie strategii przeszukiwania przestrzeni stanów do problemu planowania ruchu agenta na kracie.
|
||||
___
|
||||
## Heurystyka
|
||||
- założenie — odległość pomiędzy sąsiadującymi polami wynosi 2, tyle samo co koszt wjazdu na puste pole
|
||||
- s — pole, na którym jesteśmy
|
||||
- f — pole końcowe
|
||||
- dla s = f program kończy pracę, bo znajdujemy się już w położeniu końcowym, dlatego pominęłyśmy ten przypadek w definicji heurystyki.
|
||||
```
|
||||
def hscore(self, s, f):
|
||||
if f > s:
|
||||
a_h = (f - s) // 5
|
||||
else:
|
||||
a_h = (s - f) // 5
|
||||
if f % 5 >= s % 5:
|
||||
b_h = f % 5 - s % 5
|
||||
else:
|
||||
b_h = s % 5 - f % 5 + 1
|
||||
return 2 * m.sqrt(a_h * 2 + b_h * 2)
|
||||
```
|
||||
Wpierw obliczamy wysokość trójkąta, jaki tworzą obecne i końcowe pole, w celu wyznaczenia przeciwprostokątnej — odległość między s i f.
|
||||
|
||||
___
|
||||
## Funkcja następnika
|
||||
Tworzymy listę, do której będziemy kolejno generować sąsiadów dla danego x.
|
||||
|
||||
```
|
||||
def neighbours(self):
|
||||
self.neighbours = list(range(25))
|
||||
self.neighbours[0] = [1, 5]
|
||||
self.neighbours[4] = [3, 9]
|
||||
self.neighbours[20] = [15, 21]
|
||||
self.neighbours[24] = [19, 23]
|
||||
for x in range(1, 4):
|
||||
self.neighbours[x] = [x - 1, x + 5, x + 1]
|
||||
for x in range(5, 16, 5):
|
||||
self.neighbours[x] = [x - 5, x + 1, x + 5]
|
||||
for x in range(9, 20, 5):
|
||||
self.neighbours[x] = [x - 5, x - 1, x + 5]
|
||||
for x in range(21, 24):
|
||||
self.neighbours[x] = [x - 1, x - 5, x + 1]
|
||||
for x in [6, 7, 8, 11, 12, 13, 16, 17, 18]:
|
||||
self.neighbours[x] = [x - 5, x - 1, x + 1, x + 5]
|
||||
```
|
||||
___
|
||||
## Główna pętla strategii przeszukiwania
|
||||
Zaczynamy od znalezienia w open_set pola o najniższym f.
|
||||
```
|
||||
while open_set:
|
||||
# Szukanie pola w open_set z najniższym f
|
||||
temp1 = max(self.f_score) + 1
|
||||
x = 0
|
||||
for i in range(len(open_set)):
|
||||
if self.f_score[open_set[i]] <= temp1:
|
||||
x = open_set[i]
|
||||
temp1 = self.f_score[open_set[i]]
|
||||
```
|
||||
Jeżeli to pole odpowiada temu, do którego chcemy dojść — wywołujemy funkcję tworzącą ścieżkę z pola wyjściowego. Póki nie — pomijamy.
|
||||
```
|
||||
if x == koniec:
|
||||
return self.reconstruct_path(self.came_from, koniec)
|
||||
```
|
||||
|
||||
Usuwamy x z open_set i wrzucamy do closed_set, aby upewnić się, że nie będziemy go ponownie sprawdzać.
|
||||
```
|
||||
open_set.remove(x)
|
||||
closed_set.append(x)
|
||||
```
|
||||
|
||||
Następnie sprawdzamy sąsiadów:
|
||||
```
|
||||
for y in self.neighbours[x]:
|
||||
```
|
||||
To tutaj chcieliśmy mieć pewność, że nie trafimy ponownie na x.
|
||||
```
|
||||
if y in closed_set:
|
||||
continue
|
||||
```
|
||||
Chcemy również sprawdzić, czy jeżeli y jest już w open_set, to nie istnieje krótsze przejście np. z pola startowego przez inne pole na y, niż bezpośrednio na pole y.
|
||||
```
|
||||
tentative_g_score = self.g_score[x] + self.game.fields[y][3]
|
||||
if y not in open_set:
|
||||
open_set.append(y)
|
||||
tentative_is_better = True
|
||||
elif tentative_g_score < self.g_score[y]:
|
||||
tentative_is_better = True
|
||||
```
|
||||
Wyliczamy g i f — przewidywany dystans od startu do celu, dla y.
|
||||
```
|
||||
if tentative_is_better == True:
|
||||
self.came_from[y] = x
|
||||
self.g_score[y] = tentative_g_score
|
||||
self.f_score[y] = self.g_score[y] + self.hscore(y, koniec)
|
||||
```
|
||||
___
|
||||
## Tworzenie ścieżki
|
||||
Przechodzimy po tablicy poprzedników, aż dojdziemy do początku — pola, które nie ma poprzednika.
|
||||
```
|
||||
def reconstruct_path(self, came_from, current):
|
||||
total_path = [current]
|
||||
while came_from[current] != 0:
|
||||
current = came_from[current]
|
||||
total_path.insert(0, current)
|
||||
return total_path
|
||||
```
|
||||
|
||||
___
|
||||
## Koszt podróży na pola uprawne
|
||||
|
||||
|
||||
Zmiany w projekcie zaszły również w pliku run.py, gdzie generujemy losowo pola — każdy kolor odpowiada innej uprawie i etapie jej wzrostu.
|
||||
|
||||
|
||||
Mamy tutaj tablicę tablic. Każda z nich zawiera kolejno informacje o: rodzaju upraw, glebie, nawodnieniu pola oraz koszcie podróży na pole z daną uprawą.
|
||||
|
||||
```
|
||||
def randomize_field(self):
|
||||
for x in range(25):
|
||||
temp = []
|
||||
# nasiona
|
||||
temp.append(random.choice(["żyto", "jęczmień", "owies", "marchew", "rzodkiew", "pietruszka", "puste"]))
|
||||
# gleba
|
||||
temp.append(random.choice([True, False]))
|
||||
# woda
|
||||
temp.append(random.choice([True, False]))
|
||||
# # growth rate
|
||||
# temp.append(random)
|
||||
# # cost
|
||||
if temp[0] == "żyto":
|
||||
temp.append(10)
|
||||
elif temp[0] == "jęczmień":
|
||||
temp.append(12)
|
||||
elif temp[0] == "owies":
|
||||
temp.append(8)
|
||||
elif temp[0] == "marchew":
|
||||
temp.append(14)
|
||||
elif temp[0] == "rzodkiew":
|
||||
temp.append(7)
|
||||
elif temp[0] == "pietruszka":
|
||||
temp.append(6)
|
||||
elif temp[0] == "puste":
|
||||
temp.append(2)
|
||||
else:
|
||||
temp.append(0)
|
||||
|
||||
self.fields.append(temp)
|
||||
```
|
||||
|
||||
# *Sztuczna inteligencja - projekt zespołowy - Autonomiczny Traktor*
|
||||
|
||||
#### autorzy: Aleksandra Werda, Natalia Wiśniewska, Kinga Jagodzińska, Aleksandra Jonas
|
||||
***
|
||||
## Planowanie ruchu
|
||||
|
||||
|
||||
- schemat procedury przeszukiwania grafu stanów z uwzględnieniem kosztu
|
||||
- strategia A*
|
||||
|
||||
___
|
||||
|
||||
Drugim zadaniem dotyczącym projektu jest zastosowanie strategii przeszukiwania przestrzeni stanów do problemu planowania ruchu agenta na kracie.
|
||||
|
||||
## Heurystyka
|
||||
- założenie — odległość pomiędzy sąsiadującymi polami wynosi 2, tyle samo co koszt wjazdu na puste pole
|
||||
- s — pole, na którym jesteśmy
|
||||
- f — pole końcowe
|
||||
- dla s = f program kończy pracę, bo znajdujemy się już w położeniu końcowym, dlatego pominęłyśmy ten przypadek w definicji heurystyki.
|
||||
```
|
||||
def hscore(self, s, f):
|
||||
if f > s:
|
||||
a_h = (f - s) // 5
|
||||
else:
|
||||
a_h = (s - f) // 5
|
||||
if f % 5 >= s % 5:
|
||||
b_h = f % 5 - s % 5
|
||||
else:
|
||||
b_h = s % 5 - f % 5 + 1
|
||||
return 2 * m.sqrt(a_h * 2 + b_h * 2)
|
||||
```
|
||||
Wpierw obliczamy wysokość trójkąta, jaki tworzą obecne i końcowe pole, w celu wyznaczenia przeciwprostokątnej — odległość między s i f.
|
||||
|
||||
|
||||
## Funkcja następnika
|
||||
Tworzymy listę, do której będziemy kolejno generować sąsiadów dla danego x.
|
||||
|
||||
```
|
||||
def neighbours(self):
|
||||
self.neighbours = list(range(25))
|
||||
self.neighbours[0] = [1, 5]
|
||||
self.neighbours[4] = [3, 9]
|
||||
self.neighbours[20] = [15, 21]
|
||||
self.neighbours[24] = [19, 23]
|
||||
for x in range(1, 4):
|
||||
self.neighbours[x] = [x - 1, x + 5, x + 1]
|
||||
for x in range(5, 16, 5):
|
||||
self.neighbours[x] = [x - 5, x + 1, x + 5]
|
||||
for x in range(9, 20, 5):
|
||||
self.neighbours[x] = [x - 5, x - 1, x + 5]
|
||||
for x in range(21, 24):
|
||||
self.neighbours[x] = [x - 1, x - 5, x + 1]
|
||||
for x in [6, 7, 8, 11, 12, 13, 16, 17, 18]:
|
||||
self.neighbours[x] = [x - 5, x - 1, x + 1, x + 5]
|
||||
```
|
||||
|
||||
## Główna pętla strategii przeszukiwania
|
||||
Zaczynamy od znalezienia w open_set pola o najniższym f.
|
||||
```
|
||||
while open_set:
|
||||
# Szukanie pola w open_set z najniższym f
|
||||
temp1 = max(self.f_score) + 1
|
||||
x = 0
|
||||
for i in range(len(open_set)):
|
||||
if self.f_score[open_set[i]] <= temp1:
|
||||
x = open_set[i]
|
||||
temp1 = self.f_score[open_set[i]]
|
||||
```
|
||||
Jeżeli to pole odpowiada temu, do którego chcemy dojść — wywołujemy funkcję tworzącą ścieżkę z pola wyjściowego. Póki nie — pomijamy.
|
||||
```
|
||||
if x == koniec:
|
||||
return self.reconstruct_path(self.came_from, koniec)
|
||||
```
|
||||
|
||||
Usuwamy x z open_set i wrzucamy do closed_set, aby upewnić się, że nie będziemy go ponownie sprawdzać.
|
||||
```
|
||||
open_set.remove(x)
|
||||
closed_set.append(x)
|
||||
```
|
||||
|
||||
Następnie sprawdzamy sąsiadów:
|
||||
```
|
||||
for y in self.neighbours[x]:
|
||||
```
|
||||
To tutaj chcieliśmy mieć pewność, że nie trafimy ponownie na x.
|
||||
```
|
||||
if y in closed_set:
|
||||
continue
|
||||
```
|
||||
Chcemy również sprawdzić, czy jeżeli y jest już w open_set, to nie istnieje krótsze przejście np. z pola startowego przez inne pole na y, niż bezpośrednio na pole y.
|
||||
```
|
||||
tentative_g_score = self.g_score[x] + self.game.fields[y][3]
|
||||
if y not in open_set:
|
||||
open_set.append(y)
|
||||
tentative_is_better = True
|
||||
elif tentative_g_score < self.g_score[y]:
|
||||
tentative_is_better = True
|
||||
```
|
||||
Wyliczamy g i f — przewidywany dystans od startu do celu, dla y.
|
||||
```
|
||||
if tentative_is_better == True:
|
||||
self.came_from[y] = x
|
||||
self.g_score[y] = tentative_g_score
|
||||
self.f_score[y] = self.g_score[y] + self.hscore(y, koniec)
|
||||
```
|
||||
|
||||
## Tworzenie ścieżki
|
||||
Przechodzimy po tablicy poprzedników, aż dojdziemy do początku — pola, które nie ma poprzednika.
|
||||
```
|
||||
def reconstruct_path(self, came_from, current):
|
||||
total_path = [current]
|
||||
while came_from[current] != 0:
|
||||
current = came_from[current]
|
||||
total_path.insert(0, current)
|
||||
return total_path
|
||||
```
|
||||
|
||||
|
||||
## Koszt podróży na pola uprawne
|
||||
|
||||
|
||||
Zmiany w projekcie zaszły również w pliku run.py, gdzie generujemy losowo pola — każdy kolor odpowiada innej uprawie i etapie jej wzrostu.
|
||||
|
||||
|
||||
Mamy tutaj tablicę tablic. Każda z nich zawiera kolejno informacje o: rodzaju upraw, glebie, nawodnieniu pola oraz koszcie podróży na pole z daną uprawą.
|
||||
|
||||
```
|
||||
def randomize_field(self):
|
||||
for x in range(25):
|
||||
temp = []
|
||||
# nasiona
|
||||
temp.append(random.choice(["żyto", "jęczmień", "owies", "marchew", "rzodkiew", "pietruszka", "puste"]))
|
||||
# gleba
|
||||
temp.append(random.choice([True, False]))
|
||||
# woda
|
||||
temp.append(random.choice([True, False]))
|
||||
# # growth rate
|
||||
# temp.append(random)
|
||||
# # cost
|
||||
if temp[0] == "żyto":
|
||||
temp.append(10)
|
||||
elif temp[0] == "jęczmień":
|
||||
temp.append(12)
|
||||
elif temp[0] == "owies":
|
||||
temp.append(8)
|
||||
elif temp[0] == "marchew":
|
||||
temp.append(14)
|
||||
elif temp[0] == "rzodkiew":
|
||||
temp.append(7)
|
||||
elif temp[0] == "pietruszka":
|
||||
temp.append(6)
|
||||
elif temp[0] == "puste":
|
||||
temp.append(2)
|
||||
else:
|
||||
temp.append(0)
|
||||
|
||||
self.fields.append(temp)
|
||||
```
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user