From ce9956ee1707bc2b740cb4152978cf87fc58dd90 Mon Sep 17 00:00:00 2001 From: Aleksandra Jonas Date: Tue, 28 Apr 2020 21:13:38 +0000 Subject: [PATCH] Zaktualizuj 'route-planning.md' --- route-planning.md | 318 +++++++++++++++++++++++----------------------- 1 file changed, 159 insertions(+), 159 deletions(-) diff --git a/route-planning.md b/route-planning.md index ba0acc5..0fae6c6 100644 --- a/route-planning.md +++ b/route-planning.md @@ -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) +``` +