diff --git a/route-planning.md b/route-planning.md new file mode 100644 index 0000000..ba0acc5 --- /dev/null +++ b/route-planning.md @@ -0,0 +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) +``` +