Projekt wykorzystuje wcześniej opracowany algorytm AStar, który jest opisany w pliku [route-planning](https://git.wmi.amu.edu.pl/s444399/AI/src/master/route-planning.md).
Moduł podprojektu uruchamia się po uruchomieniu programu oraz kliknięciu **g** na klawiaturze. Omawiany moduł genetyczny podprojektu w dalszej części raportu będzie się pojawiał w skrócie jako **mdg**.
### Opis składowych elementów wykorzystanych w **mdg**
* Gen - jest to najmniejszy wykorzystywany obiekt, reprezentujący zajęty regał, kóry ma określony koszt do danego miejsca odbioru
* Chromosom - jest to uporządkowany zbiór Genów, który reprezentuje kolejność odbioru paczek, końcowa długość wynika z ilości paczek na magazynie.
* Selekcja - składowa odpowiedzialna za wybór najlepszych chromosomów z pośród populacji.
* Crossover - składowa odpowiedzialna za generowanie nowej populacji uwzględniając współczynnik mutacji, wielkość dziedziczonego fragmentu oraz otrzymane podczas selekcji chromosomy.
Podane przez urzydkownika przed uruchomieniem programu:
* ileGeneracji - wartość, która definiuje ile generacji ma się wykonać po uruchomieniu modułu **mdg**,
* ileWPopulacji - wartość, która definiuje ile chromosomów ma się znajdować w Populacji
* fragment - wartość z zakresu (0,1), która względnie do długości chromosomu określa fragment, który będzie dziedziczony, przy tworzeniu nowego chromosomu.
* mutacja - wartość z zakresu (0,1), która określa jaka część nowo tworzonego chromosomu, po dziedziczeniu, ma zostać losowo zmieniona.
* unbox - wartość określająca do jakiego miejsca odbioru ma się kierować wózek
<br/>
0 - losowe miejsce odbioru <br/>
1 - miejsce odbioru tylko po lewej stronie mapy <br/>
2 - miejsce odbioru tylko po prawej stronie mapy <br/>
3 - miejsce odbioru wybierane korzystniej na podstawie kosztu
<br/><br/>
Po uruchomieniu programu:
* generowanie losowo rozmieszczonych paczek na regałach - za przycisku **r** na klawiaturze.
### Integracja
*W pliku program.py* <br/>
Uruchomienie **mdg**:
if event.key == pygame.K_g:
start(self.data,self.wheel)
Po zakończeniu algorytmu, uruchaminy modul który rozwiezie paczki do miejsca odbioru:
* Funkcja *generateGeny* generuje oraz oblicza wartości unboxów dla danego regału oraz zwraca je jako listę genów
* Funkcja *genRandomChromosome* losowo miesza wygenerowane geny oraz dla podanej wartości **unbox** (podanej przy uruchomieniu programu) zapisuje w genach wartości odpowiadające koodrynatom unboxa oraz z jakiego unboxa wózek przyjedzie. W przypadku pierwszego genu, do którego wózek będzie jechać z określonego miejsca ta wartość pozostaje *None*. Funkcja zwraca spójny chromosom.
#### Generowanie Losowej populacji
*W pliku genetyczne.py*
def genRandomPopulation(data, ileWPopulacji):
populacja = []
for i in range(ileWPopulacji):
populacja.append(genRandomChromosome(data))
return populacja
Odpowiednio:
* Dla podanej wartości *ileWPopulacji* funkcja generuje losową populację wykorzystując metodę losowego chromosomu, wykonując tyle iteracji ile wynosi wartość.
#### Selekcyjny wybór najlepszych chromosomów z pośród populacji na podstawie funkcji fitness
* Zmienna *koszt* jest sumą całkowitą kosztów przejechania trasy.
* Pętla *for* iteruje się tyle razy ile jest genów w chromosomie.
* W pierwszej iteracji koszt jest liczony dla pierwszego genu w chromosomie wywołując AStar, z pozycji początkowej wózka do miejsca regału.
* Dla reszty iteracji jest sprawdzane do którego unboxa będzie jechać wózek, i taka wartość kosztu jest dodawana co całkowitej sumy oraz koszt przejechania od unboxa poprzedniego genu do regału (zmienna *unboxPoprzedniegoGenu*)
def dwieNajlepsze(populacja, data):
tmpPopulacja = populacja[:]
chromFitness = []
for chrom in populacja:
chromFitness.append(fitness(chrom,data))
bestValue = min(chromFitness)
bestChromIndex = chromFitness.index(bestValue)
pierwsza = tmpPopulacja[bestChromIndex]
if (data.best == None):
data.best = (pierwsza[:],bestValue)
elif(data.best[1] > bestValue):
data.best = (pierwsza[:],bestValue)
data.doWykresu.append(bestValue)
tmpPopulacja.pop(bestChromIndex)
chromFitness.pop(bestChromIndex)
bestValue = min(chromFitness)
bestChromIndex = chromFitness.index(bestValue)
druga = tmpPopulacja[bestChromIndex]
tmpPopulacja.pop(bestChromIndex)
chromFitness.pop(bestChromIndex)
return (pierwsza, druga)
Funkcja selekcji dla której odpowiednio:
* W pierwszej pętli *for* tworzy się lista *chromFitness* przetrzymująca wartości kosztów dla danego chromosomu. Wartości w *chromFitness* odpowiadają chromosomom na tych samych indeksach w liście populacja.
* Zmienna *bestValue* reprezentuje najlepszy koszt z danej populacji
* Zmienna *pierwsza* reprezentuje chromosom o najkorzystniejszym koszcie.
* Zmienna *druga* reprezentuje chromosom o drugim co do wartości najkorzystniejszym koszcie.
* W zmiennej *best* klasy obiektu *data* zapisywana jest krotka odpowiednio (chromosom,koszt) najlepszego chromosomu.
* Funkcja zwraca krotkę z dwoma najlepszymi chromosomami w populacji.
* *pierwszy*, *drugi* - wybrane najkorzystniejsze chromosomy, z których ma powstać nowy chromosom
* *fragmentLiczba* - jest to liczba reprezentująca jaki fragment z **pierwszego** chromosomu zostanie bezpośrednio skopiowany do nowego chromosomu, ten fragment jest wybierany losowo spośród chromosomu natomiast jego długość jest określona procentowo i zależy od podanej wartości (oraz ilości genów w chromosomoie)
* *wspMutacji* - jest to liczba reprezentująca jak wiele par w chromosomie zostanie zamienionych miejscami.
* Zmienne pomocnicze:
* *iterator*, *pomIterator* - w pierwszych dwóch instrukcjach warunkowych jest pilnowane aby iterując się nie przekroczyły dopuszczalnej wartości (odpowiadają one indeksom w kolejce). *Iterato* jest indeksem w nowym, tworzonym chromosomie. *pomIterator* jest indeksem który przechodzi przez **drugi** podany chromosom.
* lista *usedKordy* - do niej są dodawane koordynaty genów, które zostały skopiowane z **pierwszego** chromosomu, aby geny o tych samych koordynatach z **drugiego** chromosomu nie zostały zapisane w nowym chromosomie.
* Następuje skopiowanie fagmentu z **pierwszego** chromosomu, w pierwszej pętli *for* wykonuje się przepisanie wartości do powstającego chromosomu. W drugiej pętli *for* następuje przepisanie pozostałych wartości z **drugiego** chromosomu do powstającego chromosomu.
* Po przepisaniu wartości według wspMutacji jest dokonywana zamiana genów w nowym chromosomie.
* Ostatnia pętla **for** łączy geny ze sobą (zapisując unbox poprzedniego genu)