Oryginalna strona colobot.cba.pl umarła, gdy cba.pl przestało oferować darmowy hosting. To jest statyczny mirror, pobrany w 2018. ~krzys_h
 Polski Portal COLOBOTa - COLOBOT Polish Portal
Forum - Polski Portal COLOBOTa
Strona głównaStrona główna UżytkownicyUżytkownicy GrupyGrupy StatystykiStatystyki


Poprzedni temat «» Następny temat
Przesunięty przez: Abadon
20-02-2010, 14:23
Rozbudowany program bota obsługującego hutę
Autor Wiadomość
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 25-06-2009, 16:55   Rozbudowany program bota obsługującego hutę

Rozbudowany program dla bota transportowego obsługującego hutę. Jak każdy inny tego rodzaju, działa w cyklu: zanieś rudę do huty, wyjmij kostkę tytanu i odłóż na wolne miejsce, idź po następną bryłę rudy.
Założenia:
    * drobne ułatwienia: można uruchomić nawet jeśli bot trzyma coś w chwytaku; kiedy dotrze z surowcem do huty, a zastanie w niej gotową kostkę tytanu, prawidłowo się zachowa itp.
    * dba o odpowiedni zapas energii, przewidując zużycie na trasie
    * optymalnie wykorzystuje elektrownie, także jeśli jest więcej niż jedna
    * podjeżdża blisko elektrowni i jeśli nie może zająć w niej miejsca, to czeka w pobliżu aż będzie dostępna
    * sam planuje lądowania techniczne dla ostudzenia silników (jeśli latający)
    * wybiera bezpieczne miejsca do lądowania: suche i w miarę możliwości płaskie (dla uniknięcia ryzyka ześlizgnięcia się do wody lub w przepaść).
W zasadzie program można uruchomić na więcej niż jednym bocie. Nie pamiętam, czy testowałem taką sytuację, bo ostatnie poprawki robiłem w 2005 roku.

Tytan.txt
Pobierz Plik ściągnięto 137 raz(y) 10,67 KB

 
     
pipok
Gość


Wysłany: 26-06-2009, 07:59   Re: Rozbudowany program bota obsługującego hutę

Sam skomentuję, skoro nikogo nie korci ;)

Ułatwiajmy sobie życie

Główny program wygląda tak:
Kod:
extern void object::ZbierajTytan()
{
  int surowiec     = TitaniumOre;
  int przetwornia  = Converter;
  int produkt      = Titanium;
 
  object rzecz, budynek;
  point tutaj;
  float odl;
 
  // co trzymasz w łapie, robocie?
  WyrzucInne(surowiec); 
  while (true) {            // powtarzaj w nieskończoność
    WezSurowiec(surowiec);
    // znajdź przetwórnię i idź tam
    budynek = radar(przetwornia);
    // opróznij przetwórnię, jeśli jest w niej produkt
    OproznijPrzetwornie(surowiec, produkt, przetwornia);
    // upewnij się, że masz w łapce surowiec, zostaw go w przetwórni
    WezSurowiec(surowiec);
    Idz(budynek.position); drop();
    // poczekaj na produkt i odłóż go
    ObsluzProdukt(surowiec, produkt, przetwornia);
  }
}
Pierwsze trzy linijki ciała programu (deklaracje i inicjowanie zmiennych typu int) mają za zadanie ułatwić przemianę zbieracza tytanu w zbieracza uranu.

Dalsza część to trzy inne deklaracje, i... do roboty... jednokrotne wywołanie funkcji WyrzucInne oraz pętla zasadniczej pracy. Trzy z czterech użytych funkcji własnych występują w kodzie jednokrotnie, więc dlaczego ich treść nie jest po prostu wpisana w główny program, po co zrobiłem funkcje z kawałków kodu? Program jest dość obszerny (ponad 10KB) -- podzielenie go na części ułatwia zrozumienie jego działania, testowanie i modyfikowanie. Wyobraźmy sobie zagnieżdżenie sześciu dlugaśnych pętli, jedna w drugiej... Dla początkujących programistów: jeśli kod jest dłuższy niż dwa-trzy ekrany, podziel go na kawałki.

Innego rodzaju ułatwienie występuje w pierwszej własnej funkcji. Pierwszym działaniem bota w cyklu pracy jest znalezienie, dojazd i wzięcie rudy tytanu. Bardzo irytowało mnie, że przed uruchomieniem programu zbieracza musiałem upewnić się, że na pusty chwytak. W przeciwnym razie jechał sobie do najbliższej bryły i próbował ją podnieść mając zajęte "ręce". Na dodatek błąd pojawia się dopiero przy próbie podniesienia! Czy powinien mieć wolne łapki? Odpowiedni fragment programu Kempiora wygląda tak:
Kod:
    while( load == null )
    {
        item = radar(TitaniumOre);
        [ ... ]
        goto(item.position);
        grab();
    }
    item = radar(Converter);
    while ( item == null );
    while(goto(item.position) != 0 )
Jeśli bot nic nie niesie, to ma iść i zabrać rudę tytanu. Następnie udaje się do huty. Co się stanie, jeśli przed uruchomieniem programu bot już trzyma rudę? Wtedy nie pójdzie po rudę, tylko od razu do huty. W porządku. Ale zrobi to samo, jeśli w chwytaku ma coś innego: kostkę tytanu, ogniwo, uran... Nie uda się po rudę, ale z tym, co trzyma, od razu pójdzie do huty. I tam zostawi, czekając aż huta przerobi to na kostkę :)
Warto upewnić się przed rozpoczęciem pracy, czy coś trzyma. Ale... Jeśli tak, to powinna to być ruda. Inne przedmioty powinien odłożyć na bok.
Kod:
void object::WyrzucInne(int surowiec)
{
  if (load != null) {
    if (load.category != surowiec) {
      // trzyma coś, ale nie surowiec!
      // zostaw to gdzieś w pobliżu
      goto(space()); drop();
    }
  }
}
 
     
pipok
Gość


Wysłany: 26-06-2009, 09:50   Re: Rozbudowany program bota obsługującego hutę

Kolejny klocek to funkcja nakazująca botowi udanie się w miejsce, gdzie leży najbliższa bryła tytanu i zabranie jej:
Kod:
void object::WezSurowiec(int surowiec)
{
  int err;
  object rzecz;
  if (load == null) { // puste łapki - weź surowiec
    // idź do surowca i podnieś go
    do {
      rzecz = radar(surowiec);   // znajdź
      Idz(rzecz.position);       // idź do surowca
      // podnieś go
      errmode(0);  err=grab();  errmode(1);
    } while (err != 0);
  }
}
Co tutaj robi instrukcja warunkowa?
Kod:
if (load == null) { // puste łapki - weź surowiec
Upraszcza kod. Mamy jedną funkcję do znajdowania i zabierania surowca, a na samym początku być może bot trzyma już w chwytaku rudę - wówczas nie musi nigdzie chodzić i niczego brać. Poza sprawdzeniem bot nic wówczas nie robi. Z kolei
Kod:
ierrmode(0);  err=grab();  errmode(1);
obsługuje sytuację, kiedy z jakiegoś powodu podniesienie surowca się nie powiodło. Szukanie, ewentualna podróż i próba zabrania są powtarzanie póki nie uda się pomyślnie pochwycić surowca. W szczególności błąd chwytania pojawi się, kiedy ktoś już zabrał surowiec podczas gdy nasz bot do niego podróżował. Dzięki umieszczeniu "szukania" surowca wewnątrz pętli, bot spróbuje wtedy dotrzeć do innej, położonej najbliżej niego bryły.
Użyta do przemieszczenia bota funkcja Idz(), przyjmująca parametr typu point, odpowiada wbudowanej funkcji goto() użytej z jednym parametrem. Dodatkowo zapewnia obsługę podładowywania ogniwa i studzenia silników w razie potrzeby.
 
     
Kempior 


Twoja ulubiona misja: Krystalia: Ziemska Strategia
Wiek: 23
Dołączył: 19 Cze 2009
Posty: 15
Skąd: Bielsko-Biała
Wysłany: 26-06-2009, 15:21   

Kod:
    while( load == null )
    {
        item = radar(TitaniumOre);
        [ ... ]
        goto(item.position);
        grab();
    }

Ten kod miał sprawić że robot nie pojedzie bez rudy do huty.
 
     
pipok
Gość


Wysłany: 26-06-2009, 16:31   

Kempior napisał/a:
Ten kod miał sprawić że robot nie pojedzie bez rudy do huty.
Ale jeśli nie uda mu się chwycić rudy, to nie powtórzy zawartości pętli, tylko przerwie działanie z powodu błędu, prawda?
 
     
pipok
Gość


Wysłany: 26-06-2009, 16:53   

Kiedy bot ma już w chwytaku bryłę rudy tytanu (surowiec), powinien udać się z nią do huty (przetwórni), żeby ją tam umieścić. Co jednak, jeśli w przetwórni leży już wyprodukowana kostka tytanu?
Jak sprawdzić, czy w hucie leży tytan? Wystarczy sprawdzić, czy w promieniu 3 metrów od centrum tego budynku znajduje się kostka tytanu. Współrzędne budynku odnalezionego funkcją radar są współrzędnymi środka budowli. Niestety, funkcja radar daje możliwość przeszukania zadanego wycinka koła, z ograniczeniem odległości, ale centrum poszukiwań stanowi nasz bot. Dlatego poszukamy kostki tytanu znajdującej się w stosunku do bota w odległości takiej jak budynek huty, plus minus 3 metry. Ponadto, ta kostka musi być z pozycji bota widoczna w tym samym kierunku, co budynek, z dokładnością do powiedzmy 5 stopni.


Stąd wziął się występujący w funkcji fragment:
Kod:
budynek = radar(przetwornia);
odl=distance(position, budynek.position);
rzecz=radar(produkt,direction(budynek.position),5, odl-3,odl+3);
Alternatywną metoda sprawdzenia jest szukanie w pętli kolejnych kostek tytanu i sprawdzanie, czy odległość miedzy kostką a hutą jest mniejsza od 3 metry.

Jeżeli w hucie (przetwórni) jest kostka tytanu, to bot powinien pojechać na jakieś wolne miejsce w pobliżu huty, odłożyć trzymaną rudę, a następnie wyciągnąć z huty kostkę tytanu i położyć ją w miejscu składowania kostek (produktów). Po to, żeby w kolejnym kroku móc swoją rude umieścić w opróżnionym budynku huty. Całość wygląda więc tak:
Kod:
void object::OproznijPrzetwornie(int surowiec, int produkt, int przetwornia)
{
  object rzecz, budynek;
  float odl;
    int err;
 
  // czy w przetwórni nie ma aby gotowego produktu? - wyjmij go
  budynek = radar(przetwornia);
  odl=distance(position, budynek.position);
  rzecz=radar(produkt,direction(budynek.position),5, odl-3,odl+3);
  if (rzecz != null) {
    // przetwórnia zajęta, leży w niej gotowy produkt
    if (load != null) {
      // trzyma coś, trzeba to odłożyć, żeby wyjąć produkt
      // odłóz w poblizu przetwórni
      Idz(space(budynek.position,5,20,2)); drop();
    }
    Idz(budynek.position);
        errmode(0);  err=grab();  errmode(1); // wyjmij produkt
        if (err == 0) { OdlozProdukt(produkt); }
  }
}
Warto zauważyć, że próba podniesienia kostki z huty nie jest zamknięta w pętli. Dlaczego? Ponieważ sprawdzenia zajętości huty dokonaliśmy zanim do niej bot wyruszył. Kiedy już dotarł w pobliże huty, być może kostki już nie ma w środku (astronauta ją zabrał?).
Z drugiej strony, jak zauważył Kempior, powstaje problem, gdy równocześnie z naszym obsługuje inny bot. Kiedy huta jest pusta w chwili, gdy bot sprawdza (ma rudę, ale jeszcze nie ruszył z nią w drogę), może się zdarzyć, że zanim dotrze na miejsce, drugi bot włoży do huty rudę. A ponownego sprawdzenia już nie ma...
 
     
pipok
Gość


Wysłany: 26-06-2009, 16:59   

Kempior napisał/a:
Ten kod miał sprawić że robot nie pojedzie bez rudy do huty.
Dopiero teraz zwróciłem uwagę, że wyłączyłeś globalnie, na samym początku programu, zatrzymywanie działania w przypadku błędu.
 
     
colobotwymiiata 
Zjem cię


Twoja ulubiona misja: Swobodna na Krystalii
Pomógł: 6 razy
Wiek: 20
Dołączył: 02 Lut 2009
Posty: 329
Skąd: Oleśnica
Wysłany: 17-08-2009, 16:04   

Istnieje też funkcja "search", która nie jest opisana w oficjalnym podręczniku. Szuka obiektu jak "radar", ale można ustalić pozycję.
 
 
     
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 25-08-2009, 15:30   

colobotwymiiata napisał/a:
Istnieje też funkcja "search", która nie jest opisana w oficjalnym podręczniku. Szuka obiektu jak "radar", ale można ustalić pozycję.
Słusznie. Zupełnie o niej zapomniałem, a jest bardzo przydatna w podobnych sytuacjach
Cytat:
search ( kategoria, pozycja );
Znajduje obiekt o określonej kategorii, będący najbliżej podanej pozycji.
 
     
Wyświetl posty z ostatnich:   
Nie możesz pisać nowych tematów
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum

Wersja do druku

Skocz do:  

Powered by phpBB modified by Przemo © 2003 phpBB Group
Polski Portal COLOBOTa © 2008 - 2012