Kurs Framsticks – krok po kroku 

Maciej Komosiński i Szymon Ulatowski

To jest nieoficjalne tłumaczenie wersji oryginalnej: Krzysztof "Filo" Gorgolewski, sierpień 2005, z poprawkami M.K., 2005-2019.
Jeśli znasz angielski, używaj wersji oryginalnej.


O tym dokumencie

Ten kurs wprowadza krok po kroku w środowisko Framsticks. Obejmuje on podstawowe zagadnienia takie jak interfejs programu, symulacja, genetyka i ewolucja. Kurs odnosi sie też do bardziej zaawansowanych funkcji takich jak własne procedury, typy neuronów itp. Może być on używany podczas zajęć z Framsticks jak również jako samouczek. Do przeprowadzenia kursu wymagane jest środowisko Framsticks GUI (dostępne na stronie Framsticks) zainstalowane pod systemem MS Windows (pod Linuksem i macOS użyj wine).

Jeżeli jesteś nauczycielem, poświęć trochę czasu by przerobić po kolei wszystkie ćwiczenia. Zalecamy też uprzednie przejrzenie Podręcznika Framsticks. Możliwe, że zechcesz ominąć niektóre części tego kursu ze względu na twoją dziedzinę - na przykład możesz skupic się tylko na symulacji, genetyce, ewolucji, wzajemnych oddziaływaniach albo pisaniu skryptów. Informatyka, robotyka, biologia, kognitywistyka czy też filozofia wymagają poświęcenia większej uwagi różnym częściom kursu. Dobrym pomysłem jest oszacowanie na wstępie ile czasu zajmie studentom wykonanie poszczególnych zadań. Mógłbyś również wymienić rzeczy, których studenci powinni się nauczyć (albo które powinni przetestować) podczas trwania kursu. Dodatkowo możesz poprosić studentów aby przygotowali na podstawie wybranych ćwiczeń sprawozdania lub ustne prezentacje. Tutaj jest plan przykładowych zajęć ilustrujących optymalizację zachłanną i ewolucyjną, będący fragmentem niniejszego tutorialu.

Jeżeli jesteś studentem czy też po prostu chciałbyć przejść ten kurs żeby nauczyć się Framsticks, polecamy abyś najpierw przejrzał Podręcznik Framsticks. Dopiero potem zacznij kurs. Dobrym pomysłem jest też poproszenie kogoś (np. koleżanki/kolegi) żeby niezależnie i równolegle wykonywał ćwiczenia tak, abyście mogli później razem dyskutować i wymieniać się pomysłami. Jeżeli pewne fragmenty będą zbyt trudne, możesz je opuścić i później przejrzeć kurs jeszcze raz. Jeżeli czegoś nie rozumiesz, zajrzyj do Podręcznika.

Autorzy środowiska i wieloletni użytkownicy prowadzą co roku zajęcia, kursy i warsztaty oparte na tym tutorialu. W zależności od szczegółowości i stopnia zaawansowania do którego dochodzimy, takie kursy trwają od 2×1.5h to 8×1.5h. Krótkie prezentacje 1×1.5h oraz bardzo dokładne, zaawansowane kursy 10×1.5h są również możliwe. Jeśli mieszkasz w okolicach Poznania, mogą zainteresować Cię okresowe spotkania i prezentacje w Laboratorium Sztucznego Życia.

Pełna dokumentacja jest dostępna na oficjalnej stronie Framsticks (to najlepsze miejsce by uzyskać informacje) i jest podsumowana w Podręczniku Framsticks. Ten kurs nie zastępuje dokumentacji.

  1. Podstawy
    1. Poznaj Framsticks
    2. Cel: zobaczyć parę stworzeń, ich zachowań, cech fizycznych, wzajemnych oddziaływań, itp.

      Ustawienia: uzyj Framsticks GUI dla Windows. Ustaw Simulator Parameters/Experiment/Populations/Creatures/Death na "off", włącz OpenGL (jeżeli to będzie możliwe). Ta prezentacja moze być też odegrana przy pomocy "Framsticks Theater" i pokazu "presentation".
      • Załaduj "walking.gen" i włacz symulację
      • Zasymuluj parę ciekawych stworzeń: quadruped, lizard, hopping spider, etc. (prawy klik na genotypie → Simulate → Creatures)
      • Podstawowe czynności w środowisku użytkownika:
        • przeciąganie z lewym przyciskiem: obrót kamery
        • przeciąganie z prawym przyciskiem: przesuwanie kamery
        • podwójny lewy klik: zbliżenie na organizm
        • kółko w górę/w dół: powiększenie
        • control + lewy klik: chwyć stworzenie ("manipulator")
        • shift + prawy klik: wybierz akcję
        • podwojny prawy klik: nakarm (wykonaj pierwszą akcję)
    3. Framsticks GUI
    4. Cel: poznać interfejs użytkownika Framsticks i podstawy symulatora

      • Parametry symulatora: niektóre parametry powinny być zmienione podczas zabawy ze stworzeniami:
        • Experiment/Populations/Creatures/Death – powinno być wyłączone. W przeciwnym wypadku stworzenia mogłby niespodziewanie umierać.
        • Experiment/Parameters/Simulated Creatures – symulator automatycznie stworzy tyle stworzeń. Ustaw na 0 jeżeli nie chcesz, żeby symulator ingerował w twoje stworzenia.
      • Genotype: to opis (plan budowy) stworzenia. Może być zachowany w pliku
        (GUI: menu → File → Load/Save genotypes)
      • Okienko Body&Brain: kliknij na genotypie, żeby zobaczyć strukturę fizyczną i połączenia neuronowe. Kliknij na żyjącym stworku (na liście populacji), żeby zobaczyć działające połączenia neuronowe gdy symulacja jest włączona.
      • Okienko World: zwróć uwagę na kontrolkę listy rozwijanej w prawym górnym rogu. Porównaj jak ustawienia "Every, 25 fps", "Every" oraz "1:100" wpływają na prędkość symulacji ("simulation steps/sec." w prawym górnym rogu głównego paska aplikacji).
      • Creature: stworzenie może być utworzone na podstawie genotypu
        (GUI: prawy klik na genotypie → Simulate → Creatures)
        (GUI: prawy klik na genotypie → Simulate → Kill/Delete)
      • Symulacja mechaniczna: może być MechaStick lub ODE (bryła sztywna). Zobacz ustawienie World/Simulation engine. Wypróbuj oba rodzaje symulacji, pobaw się stworkami używając manipulatora i zwróć uwagę na różnice, m. in. na różnice w wykrywaniu kolizji między ciałami stworków.
    5. Nauka genetyki
    6. Cel: nauczyć się jak zaprojektować proste stworzenie w kodowaniu f1

      • Kliknij New aby stworzyć nowy genotyp
      • Wprowadź genotyp i obejrzyj rezultaty w oknie podglądu
        (Zobacz również specyfikację f1)
        • Wprowadź X – pojawi się pojedyńczy segment liniowy (patyk)
        • Wprowadź kilka wiecej X'ów i przesuń kursor wzdłuż genotypu. Podgląd strukturalny podświetli odpowiadające części ciała. Kliknij na patyk, żeby podświetlić odpawiadającą mu część genotypu.
        • Rozgałęzianie: użyj nawiasów (...) i przecinków, żeby stworzyć drzewiaste organizmy. Przykład: XXX(XX,X). Zobacz jak dodatkowe przecinki wpływają na kierunki rozgałęzień: XXX(,,,XX,X)
        • Nawiasy mogą być zagnieżdżone, spróbuj: XXX(XX,X(X,X)) (przejdź wzdłuż genotypu kursorem, żeby dowiedzieć się który patyk odpowiada któremu X'owi)
        • Obrót płaszczyzny rozgałęzienia: wprowadzenie modyfikatorów R/r. Wstaw R jedno po drugim i zobacz powstała strukturę: XXX(XX,RRRX(X,X))
        • więcej modyfikatorów kształtu: Q C L – wstaw do genotypu i odgadnij jak działają. Zajrzyj do specyfikacji kodowania f1 żeby dowiedzieć się więcej. Ogólna zasada: duze/małe litery mają przeciwne znaczenie.
        • Zauważ, że czerwone tło oznacza, że genotyp jest nieprawidłowy – np. "X[", i różowe tło oznaczają błąd genotypu, który może zostać poprawiony automatycznie – np. "X()". Niektore genotypy mają poprawną składnię , ale problemy pojawiają sie podczas budowania stworzeń. Spróbuj na przykład genotypu "X[|][|]", który ma dwa identyczne mięśnie w tym samym miejscu. Jako, że jest to niepoprawne, w menu pod strzałką w obu oknach podglądu pojawi się opcja "Build problems encountered!". Wybierz ją, żeby zobaczyć wszystkie problemy konstrukcyjne.
      • Ćwiczenie 1: Odgadnij genotyp na podstawie takiej budowy ciała:

        Rozwiązanie: zapytaj prowadzącego.
      • Ćwiczenie 2: Czy potrafisz napisać inny genotyp, który opisywałby ten sam kształt?
      • Ćwiczenie 3: Zbuduj interesujacy kształt używając tego języka genetycznego.
      • Wniosek: Ograniczenia kodowania genotypu 'f1'
        • Tylko struktury drzewiaste: zamknięte pętle nie są możliwe (ale zawsze można zbudować otwartą kwadratową pętlę - spróbuj to zrobić, a potem zasymuluj ją przy użyciu symulatorów MechaStick i ODE, potrząśnij nią przy pomocy manipulatora i zauważ różnicę).
        • Łodyga i jej odgałęzienia są zawsze w tej samej płaszczyźnie, taki kształt nie jest możliwy:
        (Jednakże takie kształty da sie uzyskać korzystając z innego kodowania o nazwie 'f0')
    7. Neurony
    8. Cel: dołaczyć neurony (efektory, receptory) do stworzeń

      • Opis sieci neuronowej jest wymieszany z genotypem ciała, tak jak tutaj: X[1:2]X[-1:3,0:1]X
        Każda jednostka zawarta pomiędzy nawiasami kwadratowymi to pojedyńczy neuron. Przecinki oddzielają poszczególne wejścia (połączenia) danego neuronu. W opisie każdego połączenia, liczba przed dwukropkiem jest względnym numerem połączonego neuronu (0=polączenie z samym sobą, +1=następny neuron w genotypie, −1=poprzedni). Następna liczba (po ":") to waga połączenia. W powyższym przykładzie nie wyspecyfikowano żadnej nazwy neuronu, tak więc przyjmuje się że to domyślny neuron "N". Przeanalizuj poniższe przykłady i upewnij się, ze rozumiesz je dobrze. Wprowadź je do programu jako genotyp:
        • cccXXXXX[0:0][-1:1][-1:1][-1:1][-1:1] (Łańcuch neuronów)
        • cccX[0:0]X[-1:1]X[-1:1]X[-1:1]X[-1:1] (Inne ulożenie neuronów w ciele)
        • cccX[4:1]X[-1:1]X[-1:1]X[-1:1]X[-1:1] (Zamknięta pętla)
        • cccXXXXX[0:0][0:0]X[0:0]X[0:0]X[-1:1,-2:1,-3:1,-4:1] (Wiele wejść)
      • Jest wiele typów neuronów, zajrzyj do "Simulation Parameters: Genetics: Neurons to add" żeby zobaczyć krótkie zestawienie. Przykłady:
        • X[Sin,f0:0.1]
          – "Sin" to typ neuronu (generator funkcji sinus)
          – potem musisz napisać przecinek (inna, przestarzała – i bardziej skomplikowana – notacja nie wymaga przecinka, ale lepiej używać nowszej i prostszej notacji)
          – "f0" jest atrybutem neuronu Sin – to bazowa częstotliwość dla generatora funkcji sinus
        • X[T][G][S][-3:1,-2:1,-1:1]3 receptory podłączone do neuronu
        • XX[T][-1:1][|,-1:1]receptor (sensor dotyku) → neuron → efektor (miesień)
      • Zobacz interaktywne pokazy podstawowych rodzajów sensorów i efektorów.
      • Możesz zerknąć na podsumowanie kodowania f1.
    9. Kontrola mózgu
    10. Cel: monitorować i kontrolować "żywe" neurony

      • Zacznij od takiej struktury: X(X,XXRRX(X,X,,),X)
      • Dostosuj długość kończyn: X(X,lllXRRlllXlllX(lX,lX,,),X)
      • Dodaj dwa neurony mięśni. Jednemu z nich ustaw siłę (własność "p") na maksimum (1):
        X(X,lllX[|]RRlllXlllX[|,p:1](lX,lX,,),X)
      • Upewnij się, że symulator ma tak ustawione parametry:
        • Experiment/Populations/Creatures: Death jest wyłączone
        • Experiment/Populations/Creatures: Neural net simulation na "Immediate"
        • Experiment/Populations/Creatures: Performance calculation na "Immediate"
        • Experiment/Parameters: Simulated creatures jest ustawione na 0
      • Stwórz organizm na podstawie tego genotypu (Simulate → Creatures) i rozpocznij symulację (Simulation → Run). Stworzenie pojawi się na listach świata i populacji.
      • Wybierz stworzenie klikając na liście populacji. To spowoduje skojarzenie okna Body&Brain z żywym stworzeniem (a nie z genotypem) i skierowanie na nie kamery.
      • Kliknij podwójnie na neuronie #1 w oknie Body&Brain (na diagramie sieci neuronowej).
      • Małe okienko na diagramie to próbnik. Może być używany do monitorowania i zmiany sygnału. Przeciagnij gruby czarny suwak w górę i w dół. Widzisz zapewne natychmiastową reakcje mięśni – stworzenie sie porusza. Spróbuj znaleźć najlepszą sekwencję sprawiającą, że stworzenie będzie poruszało się do przodu.
      • Dodaj wskaźnik prędkości do listy populacji: prawy klik na liście populacji → "Show columns" → "Velocity". Teraz możesz odczytać aktualną prędkość podczas sterowania stworzeniem.
      • kliknij na czerwonej etykiecie hold żeby uwolnić wyjście neuronu.
    11. Budowanie mózgu
    12. Cel: sprawić, żeby stworzenie poruszało się samodzielnie

      Użyjemy neuronu "Sin" (generatora funkcji sinus) żeby uzyskać sygnał sterujący mięśnia.

      • Dołącz nowy neuron Sin:
        X[*][N][Sin,f0:0.1,-1:0.2][N,-1:1,-3:-0.5](X,lllX[|]RRlllXlllX[|,-2:-0.5,p:1](lX,lX,,),X)
          Wyjaśnienie:
        • [Sin,f0:0.1] to generator funkcji sinus o domyślnej częstotliwości 0.1. Częstotliwość wyjściowa zależy też od wejść neuronu Sin.
        • -2:0.5 oznacza "podłacz do neuronu przed poprzednim (-2), waga 0.5"
        • [*] to neuron dający stały sygnał o wartości (1).
      • Stwórz organizm i wybierz go z listy. On się rusza!
      • Tym razem próbniki będą pokazywały zmieniające się sygnały: sterujący mięśniem oraz sterujący sinusem. Dodaj pierwszy próbnik do neuronu przed mięśniem. Kliknij i przytrzymaj lewy przycisk myszy na etykiecie "1x" i przesuń w prawo. To zwiększy rozdzielczość czasową wyświetlanego sygnału i sprawi, że będzie bardziej czytelny.
      • Dodaj drugi próbnik do neuronu przed generatorem Sin. Przesuwaj powoli suwak w górę i w dół. W taki sposób możesz kontrolować częstotliwość generatora, ponieważ generator Sin zmienia częstotliwość zgodnie z sygnalem wejściowym. Obserwuj pierwszy próbnik.
      • Ćwiczenie 1: Ustaw Experiment/Populations/Creatures: Performance sampling period = 1000. Ożyw na nowo stworzenie. Dobierz optymalny wzorzec sterujący (dający największą prędkość). Możesz zmieniać zarówno częstotliwość generatora, jak i stałą wartość (drugie wejście dla neuronu z przodu mięśnia).
      • Dodaj próbnik do drugiego mięśnia. Zmieniając sygnał spróbuj sprawić, żeby stworzenie skręcało w lewo i w prawo.
      • Ćwiczenie 2: Spraw by stworzenie skręcało w stronę jedzenia. Możesz zacząć od tego genotypu:
        X[*][Sin][N,-1:44,-2:3](X[S],,lllllX[|,3:1]RRlllllXlllllX[|,-3:-0.5,p:1](lX,lX,,),,X[S][N,-1:0,-4:0])
        Nowe receptory [S], umieszczone po bokach, będą generowały różne sygnały gdy w pobliżu (z lewej lub z prawej strony) znajdzie sie jedzenie. Czy potrafisz wykorzystać tę informację aby poprawnie ustawić w kontrolnym (środkowym na rysunku) neuronie? Spróbuj dobrać wagi tak, żeby stworzenie się nie przewracało kiedy zakręca!
      • Ćwiczenie 3: Nasz poprzedni organizm nie był zbyt stabilny podczas skrętów. Stwórz idealnego pożeracza pożywienia dodając dwa sensory zapachu do Back Crawler'a z walking.gen!
      • Ćwiczenie 4: Weź Right Angler'a z walking.gen i zobacz, jak jego prędkość zależy od częstotliwości generatora sinusa. Następnie, używając neuronu-sensora "Energy", spowoduj by Right Angler poruszał się szybko kiedy ma dużo energii, i stopniowo zwalniał aż do śmierci. Potem zaimplementuj odwrotne zachowanie.
    13. Komunikacja
    14. Cel: nauczyć stworzenia komunikować się ze sobą

      Ten podrozdział nie jest przetłumaczony na polski. Zajrzyj do angielskiego tutoriala.

  2. Ewolucja
    1. Optymalizacja ewolucyjna
    2. Cel: niech ewolucja usprawni twoje stworzenie!

      W poprzednich ćwiczeniach próbowaliśmy ręcznie stworzyć szybko poruszające się stworzenia. Zobaczmy czy algorytm ewolucyjny Framsticks moze być użyty do tego celu.

      • Usuń wszystkie genotypy i stworzenia (albo nawet uruchom od nowa program, jeśli dużo wcześniej zmieniałeś)
      • dodaj następujący genotyp:
        X[*][Sin][N,-1:1,-2:1](X,lllX[|]RRlllXlllX[|,-2:-0.5,p:1](lX,lX,,),X)
        (ten genotyp to uproszczona wersja genotypu, który używaliśmy wcześniej: usunięto wejście generatora Sin)
      • Ustaw parametry symulacji:
        • Experiment/Populations/Creatures: Death: włączone
        • Experiment/Populations/Creatures: Neural net simulation: "After stabilization" (i tak samo Performance calculation)
        • Experiment/Populations/Creatures: Performance sampling period: 1000
        • Experiment/Parameters: Gene pool capacity: 20
        • Experiment/Parameters: Simulated creatures: 1
        • Experiment/Parameters/Selection: Crossed over: 0 (dlaczego nie chcemy krzyżowania?)
        • Experiment/Parameters/Fitness: Velocity: 1 (pozostałe na 0)
        • Genetics/f1/Morphology: wszystkie na 0 (nie chcemy mutować ciała)
        • Genetics/f1/Neuron net: "Add/remove neuron" i "Add/remove neural connection" na 0, reszta na 1.
      • Zapoznaj się z zapisem i odczytem plików. Z menu:File zapisz genotypy (np. pod nazwą moje_genotypy.gen), parametry symulatora (np. pod nazwą moje_parametry.sim) oraz stan eksperymentu (np. pod nazwą stan_poczatkowy.expt). Zamknij program Framsticks. Następnie znajdź na dysku trzy zapisane pliki i obejrzyj ich zawartość w dowolnym edytorze tekstowym lub przeglądarce plików. Otwórz program Framsticks, a następnie otwórz plik stanu eksperymentu – albo używając menu:File→Load, albo metodą drag-and-drop upuszczając plik stanu eksperymentu na pasku tytułowym programu.
      • Otwórz wykres. Przejdź do "Interface Options → simulator charts", wybierz "Genotypes: Fitness: Average Fitness", kliknij Apply, kliknij Add chart. Wybierz "Genotypes: Fitness: Maximal Fitness", kliknij Apply, kliknij Add chart. Zamnknij okno (naciśnij ESC), i pokaż okno wykresów naciskając [Shift-F6]. Pomyśl jak będą wyglądały te wykresy, wyjaśnij dlaczego.
      • Rozpocznij symulację. Obserwuj okno "gene pool". Możesz posortować kolumnę "velocity" żeby przekonać sie czy ewolucja robi postępy. Naciśnij [F9] żeby ukryć okna i przyspieszyć ewolucję ([Shift-F4] pokaże okno z genotypami). [F4] przywróci domyślne rozstawienie okien.
      • Jest wiele parametrów wpływających na algorytm. Zajrzyj do "parameters reference" w dokumentacji Framsticks.
      • Spójrz na wykresy. Porównaj średnie i maksymalne dopasowanie (prędkość). Czy twoje oczekiwania się sprawdziły?
      • Po jakimś czasie, kiedy nie zauważasz polepszeń, ustaw "Delete genotypes" na "Only the worst". Obserwuj wykresy. Co się stało? Po jakimś czasie kiedy nie widzisz polepszeń, zanotuj największą wyewoluowaną prędkość.
      • Kto zwyciężył? Czy stworzenie powstałe w wyniku ewolucji jest szybsze od tego, które zaprojektowałeś ręcznie?
      • Zobacz, które fragmenty aryginalnego genotypu zostały zmienione przez ewolucję. Jakie znaczenie mają te zmiany?
      • Pozwól ewolucji dobierać długość sticków. Ustaw "Genetics: f1: morphology: add/remove a modifier" na 1. Ustaw "Excluded modifiers" tak, żeby zawierały wszystkie modyfikatory oprócz "L" oraz "l" (czyli RrCcQqFfMmIiDdGgBbHhEeWwAaSs). Kontynuuj ewolucję sprawdzając, czy zmienia się budowa organizmów. Możesz przełączać ustawienie "Delete genotypes" pomiędzy "Only the worst" i "Randomly". Po jakimś czasie kiedy nie widzisz polepszeń, zanotuj największą wyewoluowaną prędkość.
      • Pozwól ewolucji dodawać i usuwać neurony, receptory i mięśnie. Ustaw wszystkie wartości w "Genetics: f1: neural net" na 1. Kontynuuj ewolucję obserwując wykresy. Możesz przełączać ustawienie "Delete genotypes" pomiędzy "Only the worst" i "Randomly". Po jakimś czasie kiedy nie widzisz polepszeń, porównaj największą wyewoluowaną prędkość z dwoma poprzednio zanotowanymi.
      • Spróbuj zgadnąć jakie byłyby wyniki ewolucji po zmianie Experiment/Populations/Creatures: Neural net simulation: na "Immediate". Wyczyść pulę genów i populacji i sprawdź swoje przypuszczenia eksperymentalnie. Ustaw wszystkie parametry odpowiednio, wyczyść wykresy, uruchom ewolucję i porównaj wyniki z poprzednimi.
    3. Wysokie struktury, projektowanie i ewolucja
    4. Cel: porównać ręczne projektowanie i ewolucję w budowaniu wysokich stworzeń

      • Spróbuj zbudować jak najwyższe stabilne stworzenie używając kodowania 'f1'. Nie używaj neuronów, chodzi tylko o ciało. Zapisz ten genotyp do pliku, e.g. "my_tall.gen".
      • Wyjdź z programu i uruchom go ponownie (żeby się upewnić, że wszystkie parametry mają domyślne wartości).
      • Ustaw parametry symulacji:
        • Experiment/Populations/Creatures: Death: włączona
        • Experiment/Populations/Creatures: Neural net simulation: "Off"
        • Experiment/Parameters: Gene pool capacity: 20
        • Experiment/Parameters: Simulated creatures: 1
        • Experiment/Parameters/Fitness: Vertical position: 1 (pozostałe: 0)
      • Dodaj prosty genotyp X.
      • Rozpocznij symulację. Obserwuj okno gene pool. Możesz dodać kolumnę "Vertical position" (prawy klik na liście genotypów) i ją posortować, żeby zobaczyć czy ewolucja robi postępy. Naciśnij [F9] żeby ukryć okna i przyspieszyć ewolucję ([Shift-F4] pokaże okno z genotypami). [F4] przywróci domyślne rozstawienie okien.
      • Kto zwyciężył? Czy stworzenie powstałe w wyniku ewolucji jest lepsze od tego, które ręcznie zaprojektowałeś?
      • Spróbuj odgadnąć jakie byłyby wyniki ewolucji po zmianie Experiment/Populations/Creatures: Neural net simulation: na "Immediate". Wyczyść pulę genów i populacji i sprawdź swoje przypuszczenia eksperymentalnie. Ustaw wszystkie parametry odpowiednio, wyczyść wykresy, uruchom ewolucję i porównaj wyniki z poprzednimi.
      • Zerknij na film pokazujący wyniki podobnego eksperymentu.
    5. Optymalizacja według dwóch kryteriów
    6. Cel: odkryć wielokryterialną optymalizację i związane z nią zagadnienia

      • Teraz będziesz musiał ewoluować stworzenia, które będą zarazem wysokie i proste. Spójrz na ustawienia Experiment/Parameters/Fitness. Musisz zmaksymalizować "Vertical position" i jednocześnie minimalizować liczbę części ciała ("Body parts").
      • Zasugeruj funkcję oceny. Pomyśl o wartościach "vertical position" i "body parts". Wprowadź swoje wagi dla tych kryteriów, wciśnij Apply, i sprawdź wzór Experiment/Gene pools/Genotypes/Fitness.
      • Jakie są wady tego sposobu obliczania oceny?
      • Co to jest normalizacja ("normalization")? Spróbuj odgadnąć znaczenie i cel Experiment/Parameters/Fitness/Criteria normalization.
      • Przeprowadź eksperyment ewolucyjny. Czy rezultaty są zadowalające? Jeżeli masz problemy z uzyskanie interesujacych wyników, ustal co jest przyczyną i jakie są sposoby przezwycieżenia tej sytuacji. Powtórz eksperyment parę razy i porównaj wyniki z kolegami. Kto ma najlepsze wysokie i zarazem proste stworzenie? Rozważ obydwa kryteria i porównaj stworzenia, które najlepiej weewoluowały.
      • Żeby wypróbować działanie bardziej zaawansowanej techniki selekcji dedykowanej do problemu wielokryterialnego, włącz Experiment/Parameters/Fitness/NSGA-II i wyłącz normalizację kryteriów. Powtórz eksperymenty i porównaj wyniki uzyskane za pomocą selekcji NSGA-II z poprzednimi wynikami, uzyskanymi z eksperymentów z selekcją wykorzystującą sumę ważoną.
  3. Ćwiczenia dodatkowe
    1. Kodowanie 'f9'
      • Przeanalizuj Rys. 1 na stronie 3 i zwróć uwagę, jak różne reprezentacje genetyczne są tłumaczone między sobą, oraz gdzie (na czym) działają operatory genetyczne i gdzie zachodzi ewolucja. Genotypy w reprezentacji 'f9' są tłumaczone bezpośrednio do 'f0'.
      • Używając liter L,R,U,D,F,B zbuduj kształt "plus", a później "trójwymiarowy plus". Pamiętaj o prefiksie /*9*/.
      • Sprawdź genotypy 'f0' utworzone przez konwersję z 'f9'. Wprowadź proste genotypy 'f9', wciśnij "Apply" za każdym razem i obejrzyj pole "Conversion: f0 genotype".
    2. Kodowanie 'f0'
      • Przeczytaj rozdział o kodowaniu 'f0' na stronie o reprezentacjach genetycznych.
      • Zbuduj następujące kształty: kwadrat, sześcian, tetrahedron, graniastosłup trójkątny formemny. Najpierw narysuj te kształty na kartce papieru i znajdź współrzędne.
        Potem zaproponuj inne proste, ale interesujące figury i je zbuduj.
      • Zbuduj prostą sieć neuronową z trzech neuronów połączonych w jednej lini (Touch, N, Bending muscle). Zmień umiejscowienie (embodiment) sensora dotyku (Touch) w ciele (przydziel go do różnych części - "Parts").
      • Sprawdź genotypy 'f0' utworzone przez konwersję z 'f1'. Wprowadź proste genotypy 'f1' (ciał i ciał z mózgami), takie jak w sekcji I.4, wciśnij "Apply" za każdym razem i przeanalizuj pole "Conversion: f0 genotype".
      • Dla "relatywnych" Joint'ów (tych które używają dx, dy, dz oraz rx, ry, rz), warto móc sprawdzić orientacje Part'ów w 3D. Uruchom theater -vaxes=1 -g X(X,X) oraz theater -vaxes=1 -g QQXXXX(X,X). Użyj theater -g - aby wprowadzić w konsoli wieloliniowe genotypy 'f0'; możesz też używać przekierowania < z pliku.
    3. Ewolucja z użyciem kodowania 'f0'
      • Powtórz eksperymenty II.2 i II.3, ale tym razem używając kodowania 'f0'. Żeby tego dokonać opróżnij pulę genów i populacji, uruchom symulację i wybierz najprostszy genotyp 'f0' z listy do wyboru. Najpierw zastanów się jakie będą różnice pomiedzy zoptymalizowanymi organizmami w kodowaniu 'f0' i 'f1'. Następnie sprawdź czy mialeś rację.
    4. Inne definicje eksperymentów
    5. Cel: zobaczyć jak symulator framsticks może być kontrolowany przez skrypty definicji eksperymentów

      • Zrestartuj program. Ustaw Experiment/Experiment definition na "neuroanalysis". Naciśnij "Apply". Przeczytaj opis (Description). Zamknij okno parametrów. Załaduj "walking.gen". Otwórz okno parametrów i naciśnij "Initialize experiment". Zamknij okno parametrów i uruchom symulację. Zamknij okno podglądu świata, żeby przyspieszyć symulację. Niczego nie dotykaj, aż symulacja sama sie nie zakończy. Następnie wybierz kilka genotypów i obejrzyj zawartość ich pola "Description" (w grupie "Notes"). Zastanów się, jak można wykorzystać informacje wyliczone w tym eksperymencie i jakie są znaczenia poszczególnych wartości.
      • Zrestartuj program. Ustaw Experiment/Experiment definition na "reproduction". Naciśnij "Apply". Przeczytaj opis (Description) uważnie. Naciśnij "Initialize experiment". Zamknij okno i uruchom symulację. Otwórz okno Messages. Obejrzyj symulację.
        1. Czy możesz określić, jaka może być maksymalna liczba żywych stworzeń?
        2. Czy jest możliwe aby wszystkie stworzenia wymarły?
        3. Czy można przewidzieć, ile stworzeń się pojawi? (tzn. zbudować jakiś model matematyczny liczby jabłek i stworków w czasie?)
        4. Czy w takiej konfiguracji dokonują sie jakieś usprawnienia ewolucyjne?
        5. Czego można oczekiwać po baaaaardzo bardzo bardzo bardzo długim czasie symulacji (miliony lat na potężnych superkomputerach)?
        6. Jaka jest różnica pomiędzy tą konfiguracją a analogicznym eksperymentem z typowym algorytmem ewolucyjnym jak w sekcji II?
      • Zrestartuj program. Ustaw Experiment/Experiment definition na "learn_food". Naciśnij "Apply". Przeczytaj opis (Description) uważnie. Naciśnij "Initialize experiment". Zamknij okno i uruchom symulację. Zbadaj wpływ parametru Experiment/Parameters/Share knowledge na zachowanie systemu. Sprawdź również parametr Experiment/Parameters/Energy/Food placement.
  4. Skrypty
  5. Cel: nauczyć się używania FramScript i zrozumieć jego wagę i potencjał

    1. Typy wartości i konwersje
    2. Otwóż okno konsoli (Console) we Framsticks GUI. Wprowadź i wykonaj następujące polecenia, jedno po drugim:

      ? 2+3
      ? 2.0+3
      ? 2+3.0
      ? "a"+2
      ? ""+2+3
      ? 2+"15"
      ? "2"+15
      ? Math.time
      ? Math.time%1000
      ? int(Math.time)%1000
      ? int(Math.time)%1000
      
      Sprobuj wyjaśnić jak wyliczono wyniki.

      Teraz spróbuj odgadnąć jaki będzie wynik a potem sprawdź czy miałeś rację:

      ? 2.0*3
      ? 2*3.0
      ? 1+2.0*3.0
      ? 1.0+2*3
      ? 7+"3"+4
      ? 7+("3"+4)
      

      Notacja szesnastkowa może okazać sie przydatna:

      ? 0xA
      ? 0xff+10
      ? 5+int("0xf0")
      ? "0xf0"+5
      

      A teraz zapoznaj się z tablicami (dwie ostatnie linie są celowo błędne):

      ? ["aa",4,"5"][0]
      ? ["aa",4,"5"][1]
      ? ["aa",4,"5"][2]
      ? ["aa",4,"5"][Math.random(3)]
      ? ["aa",4,"5"][3]
      ? [aa,4,"5"][1]
      

      A teraz parę wartości i typów, ale przy pomocy zmiennych:

      var a;  a=5;  Simulator.print(a);
      var a;  a=5;  a=a+3.0;  Simulator.print(a);
      var a;  a=5;  a+=3.0;   Simulator.print(a);
      var a;  a=5;  a="abc"+a;  Simulator.print(a);
      var a=5;  Simulator.print("abc"+(0.0+a));
      var a=["aa",4,"5"];  Simulator.print(a[2]+8);
      

      Typy ponownie, teraz z użyciem operatora typeof żeby sprawdzac typ wyrażenia podczas wykonywania programu:

      ? typeof(5)
      ? typeof(3.0)
      ? typeof(5+3.0)
      ? typeof(3.0+5)
      ? typeof("some text")
      ? typeof("some text"+3)
      ? typeof(3+int("0"))
      ? typeof(null)
      ? typeof(typeof(42))
      

      Porównania, konwersje i wykrywanie null ("brak wartości"):

      ? 4==4.0
      ? 4==float("4")
      ? 4==int(4.99)
      ? null==0
      ? null==0.0
      ? typeof(null)==typeof(0.0)
      

      Kilka zagadek dla geek'ów – wyjaśnij wyniki:

      ? 44 < int("5")
      ? "44" < string(5)
      ? 7 & 42
      ? 7 | 42
      ? 7 && 42
      ? 7 || 42
      ? 7 && 42 && "oh"
      ? (7  && "abc" || 0) ? "yup" : "meh"
      var dict={"a":3, "b":4};  Simulator.print(dict.hasKey(3) ? 1 : -1);
      var dict={"a":3, "b":4};  Simulator.print(dict["b"]);  Simulator.print(dict->b);
      

      Więcej informacji o FramScript można znaleźć tutaj.

    3. Przykładowy skrypt
    4. Teraz spójrz na ten fragment kodu. Przeanalizuj każdą linię tak, abyś na pewno zrozumiał jak działa.

      World.wrldsiz = 150;                        //zrób duży świat
      GenePools[0].clear();                       //usuń wszystkie genotypy w pierwszej puli genów
      Populations[0].clear();                     //usuń wszystkie stworzenia w pierwszej populacji
      Simulator.import("encoding_f1_best.gen", 2); //załaduj genotypy z pliku
      GenePools[0][7].genotype="X";               //tego genotypu nie ma w tym pliku...
      for (var i=0; i<30; i++)
      {
        var geno=GenePools[0][i];                 //pobierz i-ty genotyp (od 0 do 29)
        var c=Populations[0].add(geno);           //i utwórz na jego podstawie stworzenie
        var x = 20+(i%10)*9;                      //wylicz współrzędne docelowe...
        var y = 30+(i/10)*20;                     //(odkryj co spowoduje takie wyznaczanie wartości x oraz y!)
        c.locationSetBboxCenter(x, y, c.bboxCenter.z);  //...i przesuń środek stworzenia
      }
      

      Jeżeli odkryłeś jak są wyliczane współrzędne na podstawie numeru stworzenia (zmienna "i"), teraz upewnij się, ze symualcja jest zatrzymana, wklej ten fragment kodu do okna konsoli i wykonaj go. Zobacz jak są rozmieszczane stworzenia: powiększ okno podglądu świata na pełen ekran i obróć kamerę.

      Jak widzisz ten fragment kodu automatyzuje wiele czynności.

      Pisząc skrypty zawsze sprawdzaj ostatnie komunikaty w okienku "Messages". Jeśli zobaczysz tam ostrzeżenia lub błędy, "rozwiń" je – zwykle znajdziesz tam bardzo pomocne informacje o tym, gdzie coś niepoprawnie zaprogramowałeś. Zawsze upewniaj się, że Twoje skrypty nie generują żadnych ostrzeżeń i błędów!

    5. Własne funkcje oceny
    6. Rzuć okiem na wzór Experiment/Gene pools/Genotypes/Fitness. Jest to wzór automatycznie aktualizowany po każdej zmianie kryteriów optymalizacji. Możesz jednak stworzyć funkcję oceny lepiej dostosowaną do własnych potrzeb używając if (condition) action();, zmiennych (var) tymczasowych, pętli, itp. Najpierw jednak musisz się nauczyć czegoś o polach wykorzystywanych w funkcji oceny. We Framsticks GUI, wybierz z menu "Help" "FramScript: reference". Sprawdź kontekst "Fitness formula" oraz klasę "this", jej metody i pola.

      Następnie wybierz w kontekście globalnym klasę "Math". Teraz czas na własne eksperymenty! Zaimplementuj następujące funkcje oceny ("dopasowanie" osobnika). Dla każdej z nich wyjaśnij jej znaczenie i sprawdź w praktyce jak działa. Weź pod uwagę skrajne warunki (dzielenie przez zero, pierwiastki kwadratowe z wartości ujemnych, itp.).

      1. Liczba Joints + 0.01 * liczba neuronów
      2. Pierwiastek kwadratowy z prędkości
      3. (Ilość Parts + ilość Joints) podzielona przez ilość połaczeń neuronowych
      4. Dopasowanie warunkowe: Jeżeli stworzenie ma mniej niż 5 segmentów to dopasowanie jest wprost proporcjonalne do wzrostu. W przeciwnym wypadku dopasownie to wysokość pomniejszona o 0.1*(ilość segmentów minus 5).
      5. (bardziej skomplikowane zadanie) Dopasowanie to ilość połączeń (Joints) podzielona przez objętość (x*y*z) bounding box'a Modelu stworzonego z Geno.

      Zobacz więcej materiałów na temat pisania skryptów – znajdziesz tam pełen przegląd dostępnych kontekstów, klas i metod.

    7. Własne klasy neuronów
      1. Pisanie większych kawałków kodu we FramScript może ułatwić Ci Framclipse.
      2. Znajdź podkatalog "scripts" w katalogu instalacyjnym Framsticks. Spójrz na rozszerzenai plików i ich zawartość. Następnie wyświetl plik "threshold.neuro". Pliki *.neuro maja trzy części: preambułę (podstawowy opis neuronu), kod (oddzielony znakami ~ ) oraz właściwości (parametry neuronu). Przeanalizuj ten plik uważnie i zobacz jak działa neuron "threshold". Następnie uruchom program i użyj tego genotypu
        X[*][Thr,-1:1,t:-0.2,hi:0.3,lo:0.8]
        żeby go przetestować.
      3. Teraz spójrz na źródło neuronu noisy (plik noisy.neuro). Czy potrafisz wytłumaczyć jak on działa? (krótki opis tego neuronu znajduje się też w rozdziale poświeconym Framsticks książki Artificial Life Models in Software). Wymyśl jakiego genotypu możnaby użyć do przetestowania tego neuronu, a potem sprawdź to eksperymentalnie.
      4. Odkryj jakich procedur (metod) mozesz używać we FramScript. We Framsticks GUI, wybierz "Help" i "FramScript: reference". Poświeć chwilę, żeby przejrzeć interesujace Cię klasy. Sprawdź klasę "Math", jej metody i pola.
      5. Skopiuj i zachowaj noisy.neuro pod inną nazwą (exa.neuro), ale nadal w tym samy katalogu. Otwórz plik i zmień nazwę neuronu modyfikując odpowiednia linię: "name:ExA" (Nazwy neuronow muszą się rozpoczynać wielką literą). Pełną nazwą powinno być "Exercise A". Teraz spróbuj zmodyfikować funkcję go() tak żeby wyjściem neuronu była funkcja sinus. Zachowaj plik, uruchom ponownie program i sprawdź okno Messages w poszukiwaniu błędów. Jeżeli wszystko jest w porządku stwórz genotyp, żeby przetestować swój neuron ExA. Jeżeli coś nie będzie działać popraw błędy albo poproś o pomoc prowadzącego.
      6. Teraz pora na prawdziwe ćwiczenie (a). Musisz zaprojektować neuron, który na wyjściu daje sygnał przedstawiony na rysunku. Twój neuron ExA powinien mieć tylo jeden parametr (t) określajacy długość okresu tego wzorca (ilość kroków symulacji, po której wzorzec sie powtórzy). Zamiast uruchamiać ponownie program za każdym razem, zeby załadować nowy kod neuronu, spróbuj kliknąć Simulation Parameters/User scripts/Reload neuron definitions.
      7. Upewnij się, że Twój neuron realizujący (a) działa poprawnie. Następnie w poniższym genotypie zamień neuron Sin na nazwę Twojego neuronu:
        X[*][Sin][N,-1:1,-2:1](X,lllX[|]RRlllXlllX[|,-2:-0.5,p:1](lX,lX,,),X)
        Ustaw parametry tak jak to opisano w części II.1 i spróbuj wyewoluować to stworzenie, by poruszało się wykorzystując neuron który dopiero co zaprojektowałeś! Tak jak poprzednio, pozwól tylko na mutacje własności neuronów i wag połączeń – ciało nie powinno się zmieniać, i nowe neurony nie powinny być dodawane.
      8. Jeżeli Ci się powiodło, rozwiąż następujące trzy zadania. Dla każdego stworz oddzielny plik (exb.neuro, exc.neuro, exd.neuro). W ćwiczeniu (d), będziesz potrzebował dwóch parametrów, zeby sprecyzować długości (w krokach symulatora) wysokiego i niskiego poziomu wyjścia. W niektórych zadanich będziesz musiał użyć funkcji init(), żeby zaincjalizować niektóre pola. Zapytaj prowadzącego, jeżeli nie mozesz sobie z czymś poradzić albo pomiń problem, jeżeli nie możesz uzyskać pomocy.
      9. Przed Tobą jest jeszcze 5 wyzwań! Najpierw skonstruuj neuron wygładzający sygnał wejściowy poprzez uśrednianie wartośći aktualnego wejścia z dwoma poprzednimi. Użyj sumy ważonej a nie pojedyńczych wejsć.
      10. Następnie zbuduj neuron który zwraca na wyjściu maksymalną wartość spośród swoich wejść. Zaprojektuj odpowiednią sieć neuronową, żeby go przetestować.
      11. Potem zbuduj neuron, który mnoży wartość jednego wejścia przez wartość drugiego i wynik wystawia na wyjście.
      12. Następnie zbuduj komórkę pamieci. Pierwszym wejściem będzie wartość do zachowania a drugim sygnał kontrolny (jeżeli jest mniejsz od zera komórka zapamietuje stan pierwszego wejścia). Jeżeli sygnał kontrolny wynosi zero lub wiecej komórka pamięci zwraca zapamiętany wcześniej sygnał.
      13. W końcu, zbuduj neuron, który na wyjściu będzie dawał sygnal obu wejść na raz używając jednego kanału. Twój neuron powininen liczyć sumę ważona obu wejści i podawać ją na wyjście jako (zawsze) dodatnią wartość na kanale pierwszym i zawsze ujemną wartość na kanale drugim. Potem możesz użyć neuronu ChSel żeby wyciągnąć jeden kanał z wielokanalowego wyjścia.

      Zauważ, że pomimo, że robimu zwykłe neurony nic nie stoi na przeszkodzie, żeby projektować własne sensory (funkcja go() może wykorzystywać informacje o świecie i innych stworzeniach). Można też tworzyć efektory i receptory.

    8. Własne makra
      • Znajdź podkatalog "scripts" w katalogu instalacyjnym Framsticks. Przyjrzyj sie zawartości plików z rozszerzeniem ".script". Są bardzo podobne do plików *.neuro, nieprawdaż? Też maja segment "code:"
      • Teraz uważnie przeanalizuj pliki "neuroclsreport.script", "foodcircle.script", "creaturescircle.script" i "gallery.script". We Framsticks GUI znajdź Simulation Parameters/User scripts. Możesz uruchamiać skrypty i zobaczyć jak działają.
      • Pamiętasz przykład w rozdziale IV.2? Może zostać zachowany w pliku *.script i uruchomiony jednym kliknięciem.
      • Jeżeli chcesz trochę poeksperymentować i zmodyfikować parę plików .script, najpierw zachowaj je pod inną nazwą. Następnie zmodyfikuj źródła i uruchom ponownie program, zeby przetestowac zmainy. Możesz też testować makra wklejając ich kod w oknie konsoli. Kiedy skończysz zaimplementuj następujące makra:

      1. zwiększ poziom wody o +0.5
      2. znajdź we wbudowanym w program Class Browser (menu: Help) obiekt UserScripts, znajdź w nim nazwę procedury odpowiadającą Twojemu makru, i wywołaj ją z okienka konsoli: UserScripts.script_moj_wlasny();
      3. ustaw wszystkie stworzenia z populacji #0 na planie kwadratu (wypisz komunikat jeżeli nie będzie czego ustawiać)
      4. tak jak powyżej, ale najwyższy organizm powinien stać na środku
      5. ustaw je w lini, według wzrostu
      6. wydrukuj raport – wyświetl wszystkie obiekty (genotypy, stworzenia) we wszystkich pulach genów i populacji, wraz z nazwami puli
      7. do każdego genotypu dodaj do puli genetycznej 10 mutantów. Oryginalne genotypy powinny pozostać niezmienione, a nazwy mutantów powinny się składać z kolejnych liczb doklejanych z przodu nazwy pierwotnych stworzeń
      8. potrząśnij stworzeniami! dla wszystkich grup stworzeń, dla każdego stworzenia, dla wszystkich jego MechPart, dodaj niewielką liczbę do jego prędkości. Dużo wygodniej będzie Ci obserwować w akcji tę procedurę, jeśli umieścisz jej źródło jako funkcję w definicji eksperymentu, np. żeby wywoływała się co 200 kroków symulacji. W tym celu dopisz odpowiedni warunek (wołasz swoje makro kiedy numer kroku symulacji stepNumber modulo 200 wynosi 0) na końcu funkcji onStep() w pliku standard.expdef.
      9. (zadanie zaawansowane) tak jak powyżej, ale dla wszystkich MechParts z neuronem Touch dodaj niewielką wartość do MechPart.vz

      • Jeśli z jakiegoś powodu chciałbyś zapisywać jakieś dane z symulacji w zwyczajnym pliku, możesz użyć obiektu File. Obejrzyj scripts\neurof0html.script; nie musisz rozumieć dokładnie jak ten skrypt działa, ale zwróć uwagę na to jak wykorzystano tam obiekt File. Możesz uruchomić ten skrypt i zobaczyć plik jaki został utworzony w katalogu scripts_output.
    9. Interfejs lini poleceń (Command-line interface - CLI)
    10. Cel: zapoznać się z Framsticks CLI i nauczyć sie jak go używać do automatyzacji eksperymentów

      1. Pobierz CLI i przygotuj go do pracy.
      2. Uruchom "frams". Wprowadź "lm". Zajrzyj do pliku "frams.ini" , zwróc uwagę na funkcje init() i naucz się jak makra są powiązane z implementacjami funkcji.
      3. Poeksperymentuj z następującymi makrami: im, sa, st, lg, lc, qu.
      4. Makro go włącza symulację, Control-C zatrzymuje.
      5. Zauważ, ze możesz wprowadzać polecenia tak jak w IV.1.
      6. Zaimportuj plik "walking.gen", ustaw pulę genów na 20 (używając FramScript: ExpProperties.capacity=20;), ustaw liczbę równocześnie symulowanych stworzeń na 2 (ExpProperties.MaxCreated=2;), uruchom symulację aż nie zostanie ocenionych 1000 stworzeń (używajac pętli while, dla inspiracji zobacz jak jest zdefiniowane makro go), podczas kiedy ocenianie trwa obserwuj prędkość symulacji (wyświetlana w tytule okienka), potem wyeksportuj genotypy do "walk2.gen" (przeczytaj dokumentację Simulator.export), oraz zapisz stan symulatora do "walk2.expt" używając makra sa.
      7. Przejrzyj pobieżnie zawartość pliku "walk2.expt" używając dowolnego edytora tekstowego.
      8. Załaduj "walk2.expt" w GUI (działa drag-and-drop pliku na tytułowy pasek aplikacji), włącz symulację, naciśnij F9 i porównaj prędkość symulacji (wyświetlana w prawym górnym rogu) z prędkością jaką obserwowałeś w CLI.
      9. Utwórz plik "cmd.txt" z poleceniami, których używałeś w poprzednim ćwiczeniu. Uruchom interfejs lini poleceń Windows lub Linux (cmd.exe or sh), i wprowadź:
        frams < cmds.txt
        
      10. Naucz sie jak używać parametrów w lini poleceń – wprowadź
        frams --help
        
        a potem, na przykład,
        frams "? 2+3" "lo walking.gen" "lg" "qu"
        
      11. Spraw, żeby neuroanalysis.expdef badało wszystkie genotypy z walking.gen, a potem zachowaj pulę genów ("sa walk-analyzed.gen"). Jeśli używasz definicji eksperymentu innej niż standard.expdef, musisz ją ustawić w argumencie programu w ten sposób: frams "expdef neuroanalysis". Nie zapomnij zaincjalizować eksperymentu.
      12. Utwórz plik "cmds-neu.txt" z poleceniami użytymi w poprzednim ćwiczeniu, wyjdź z programu i użyj go w trybie wsadowym.
      13. Dojrzały, działający i użyteczny przykład skryptu powłoki (*.cmd) oraz makra (*.script) które uruchamiają kompletny sparametryzowany eksperyment to evolve-speed-vs-gravity. Możesz modyfikować ten przykład dostosowując go do swoich potrzeb.
    11. Dostosowywanie standardowej definicji eksperymentu do własnych potrzeb

      W tutorialu angielskim znajdziesz w tym miejscu bardzo przydatną podpowiedź, jak radzić sobie z oceną złożonych zachowań podczas życia organizmu (używając pól w słowniku data obiektu Creature) oraz – jeśli chciałbyś oprzeć ewolucję na takich ocenach – jak przepisać te pola do obiektu Genotype i użyć je w formule na fitness.

    12. Własne definicje eksperymentów
    13. Zajrzyj do plików scripts/*.expdef, wybierz prosty expdef, zobacz jak są zaimplementowane zdarzenia "onCośtam", zachowaj expdef pod inną nazwą, zmodyfikuj, uruchom ponownie GUI i przetestuj swoje zmiany. Obejrzyj proste learn_food.expdef i generational.expdef. Jeżeli powiodło Ci się wykonanie poprzednich zadań, jesteś teraz w stanie implementować własne definicje eksperymentów. Oto kilka pomysłów:

      1. Wylicz distance Genotypu jako różnicę pomiędzy miejscem urodzenia a miejscem śmierci.
      2. Wylicz dopasowanie jako wysokość najwyższej części ciała, uśrednioną w czasie życia (mierzoną w zadarzeniach onUpdate).
      3. Sprzątanie: w momencie kolizji dwóch organizmów poza środkiem planszy, większy z nich jest przesuwany na środek planszy. Jeśli to miejsce jest zajęte (użyj creature.boundingBoxCollisions(0) żeby wykryć kolizję z czymś innym), umieszczamy go coraz wyżej.
      4. Walka o zasoby (arena): stworzenia rodzą się w dwóch przeciwległych końcach areny ita która jest w stanei pokryć największą powierzchnie ma uzyskuje lepszy współczynnik dopasowania (oceny).
      5. Pościg i ucieczka: dwie pule genów, dwie przeciwstawne funkcje oceny, jedna grupa stworzeń ewoluuje, żeby uciec, a druga ją goni.
    14. Własny pokaz Framsticks (Theater show)
    15. Zajrzyj do plików scripts/*.show, wybierz sobie prosty pokaz, sprawdź jak są zaimplementowane zdarzenia "onSomething", zachowaj plik pod inną nazwą, zmodyfikuj go, uruchom ponownie program prezentacji i przetestuj swoje zmiany. Musisz używać zarejestrowanej wersji programu prezentacji, żeby testować własne prezentacje.

    16. Własny styl OpenGL
    17. Zajrzyj do plików 3dobj/*.style. Kontunuuj tak jak poprzednio. Przeczytaj kurs (prezentację) o skryptach - zawiera on analogiczne przykłady. Musisz zarejestrować Framsticks GUI, żeby używać nowych styli OpenGL. Przeczytaj też "jak stworzyłem Spooksticks".