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:16
Program dla robota obsługującego hutę.
Autor Wiadomość
FE4R 


Twoja ulubiona misja: Saari - Inwazja
Pomógł: 4 razy
Wiek: 24
Dołączył: 21 Paź 2009
Posty: 144
Wysłany: 01-11-2009, 22:07   Program dla robota obsługującego hutę.

Hej...

Tak, tak... wiem, że pipok ma taki temat 2 linijki niżej, ale ja jestem narcyz, lubię mieć swój temat dla swojego programu.

Stworzyłem trochę bardziej rozbudowany program do zbierania rudy tytanu niż ten, który przysyłają Wam z Houston podczas misji. ;)


Założenia:

1) Standardowe:


*robot znajdzie rudę
*robot znajdzie hutę
*robot podniesie tytan i odłoży w wolnym miejscu


2) Mniej standardowe:

*na początku robot wyrzuci to, co ma w uchwycie
*robot sprawdzi, czy są obiekty potrzebne do produkcji
*robot powiadomi o kłopotach w wykonaniu procesu wiadomościami
*robot po dojściu do huty i zastaniu tam gotowego tytanu nie spanikuje, tylko odniesie tytan w wolne miejsce, a potem kontynuuje pracę z rudą
*robot dwa razy sprawdzi, czy ma wystarczająco energii


Objaśnienia:
NA KOŃCU POSTU.


Oto wersja obrazkowa:
http://img689.imageshack....collect2000.png

A oto wersja tekstowa:
(Czy jest lepszy sposób na pokazanie programu? Ma on 5 bloków i ten sposób nie jest zbyt przejrzysty.)

Kod:
extern void object::Collect2000()
{
errmode(0);

if(this.load != null)
{
drop();
}

while(radar(TitaniumOre) != null)
{
ipf(40);

object o, c, t;

o = radar(TitaniumOre);

if(energyCell.energyLevel < 0.3)
{
object p;

p = radar(PowerStation);

if(p != null)
{
goto(p.position);

do
{
wait(0.1);
}
while(energyCell.energyLevel < 1);
}
else
{
message("Potrzebuje ogniwa - robot od tytanu!");

do
{
wait(5);
}
while(energyCell.energyLevel < 1);
}

}

goto(o.position);
grab();

c = radar(Converter);

if(c != null)
{
goto(c.position);

t = search(Titanium, c.position);

if(t != null)
{
if(distance(t.position, c.position) < 6)
{
turn(90);
drop();
turn(-90);
grab();
goto(space(position));
drop();

o = radar(TitaniumOre);
goto(o.position);
grab();

goto(c.position);
drop();

}
}

drop();
move(-3.5);

do
{
wait(1);
}
while(radar(Titanium, 0, 15, 0, 6) == null);

move(3.5);
grab();

goto(space(position));
drop();

if(energyCell.energyLevel < 0.3)
{
object p;

p = radar(PowerStation);

if(p != null)
{
goto(p.position);

do
{
wait(0.1);
}
while(energyCell.energyLevel < 1);
}
else
{
message("Potrzebuje ogniwa - robot od tytanu!");

do
{
wait(5);
}
while(energyCell.energyLevel < 1);
}

}
}
else
{
message("Brak huty!");
break;
}

}


wait(2);
message("Brak rudy tytanu!");
}


Objaśnienia:

1) Początkowe sprawdzanie - czy robot ma coś w chwytaku?


Dlaczego użyłem bardzo prostego sprawdzenia czy robot ma coś w chwytaku? pipok zakładał bodajże, że sprawdzi najpierw czy przedmiot w chwytaku, jeśli istnieje, to ruda tytanu. Jeśli tak, to robot odniesie ją do huty. Ale to jest już zadanie pętli 'while', aby się tym zająć. Dlatego robotowi uprościłem zadanie - zamiast sprawdzać, co ma w chwytaku, wyrzuci, to co ma. Jeśli jest to ruda - następna pętla i tak nakaże mu to podnieść. W końcu to najbliższy kawałek rudy. A poza tym ze znanego programu 'SwitchCell' wiadomo, iż funkcje takie jak 'grab()' czy drop()' nie kosztują robota ani grama energii.

2) Po co funkcja ipf?

Nie wiem, jak z waszymi procesorami, ale mój ma się dobrze z takim ipf, a robot jako tako wychodzi na tym dobrze.

3) Dlaczego robot sprawdza czy ma pełną baterię, zanim zacznie proces?


Zdarzało mi się tak, że robot nie docierał do elektrowni przed skończeniem procesu tworzenia tytanu, a zatem bateria kończyła mu się zanim dotarł do sprawdzania baterii. Poza tym robot na początku nie musi mieć pełnego ogniwa. Dla usprawnienia mogłem dać program na każdym kroku robota, jednakże nie zawsze się to opłaca, gdy elektrownia jest blisko i jesteś pewny, że robot dojdzie. Później spróbuję opracować program, który liczy zużycie energii poszczególnych napędów(dla ścisłości robotów z fabryki, a nie takich podrasowanych w 'CreateObject').

4) Co to za blok ze zmienną 't'?

Zmienna 't' określa tytan. Ale nie byle jaki. Określa tytan, który czasami robot potrafi tam zastać po przybyciu do hut z rudą tytanu. W takiej sytuacji odpowiednio się zachowa i odniesie tytan w bezpieczne miejsce, a potem wróci do rudy.

5) Po co te wiadomości od robota?

Otóż ja zazwyczaj gram tak, iż mam: roboty obronne i ofensywne, czyli działa, 1 robota chwytaka latającego - do wszystkiego, od produce do zbierania tytanu w wolnym czasie(on również nadzoruje wszelkie prace) oraz robota szperacza, który zazwyczaj stoi koło radaru i na nim trzymam programy typu 'prędkościomierz'. Otóż, gdy taka wiadomość się pojawi - używam latającego chwytaka, aby osobiście(czyli na sterowaniu ręcznym najszybciej i najprecyzyjniej) wymienić mu ogniwo czy postawić hutę / kopalnię, gdy czegoś brakuje.

**Usprawnienia programu**

Ponieważ program, który napisałem zajął mi może kilka minut, więc jest daleki od perfekcji. Tutaj postaram się zapisać listę rzeczy / pomysłów na usprawnienie robota.

- Zwiększenie samodzielności związanej z ogniwem i jego wyczerpaniem.

- Funkcja do uciekania do najbliższego bezpiecznego miejsca, gdy jakikolwiek wróg zbliży się na ~50 metrów (chociaż osobiście zostawiłbym obronę innych robotów robotom, które od tego są - działom)

- Funkcja zatrzymania produkcji, jeśli tytanu jest więcej niż potrzeba.

- Odwołując się do powyższej linijki - stworzenie funkcji, która rozpocznie produkcję ogniw atomowych(jeśli można), gdy tytanu jest już wystarczająco.

- Dla robotów latających - opanowanie temperatury silników oraz mocy ogniwa.
( z silnikami będzie problem, gdyż nie da się tego przewidzieć - jedyne wartości jakie zwraca temperatura silnika to '0' lub '1')


Pozdrawiam,
FE4R
 
     
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 03-11-2009, 09:07   Re: Program dla robota obsługującego hutę.

FE4R napisał/a:
(Czy jest lepszy sposób na pokazanie programu? Ma on 5 bloków i ten sposób nie jest zbyt przejrzysty.)
W ogóle nie jest przejrzysty, bo coś Ci przy wklejaniu na forum zjadło wszystkie wcięcia.
Poza tym możesz i powinieneś użyć kilku innych środków dla poprawienia czytelności:
1. "Komentarze są za darmo"...
2. Jednoliterowe nazwy zmiennych ułatwiają pisanie kodu, ale znacznie utrudniają późniejsze zrozumienie (a więc i konserwację). Lepiej nadawać takie nazwy, które coś mówią o ich zawartości.
3. Spacje nie gryzą - postawienie odstępu po "if" czy "while" poprawi czytelność (słowo kluczowe nie będzie się zlewać optycznie z resztą, umieszczoną w nawiasach).
4. Krótkie bloki można zapisywać w jednej linii:
Kod:
if (this.load != null)   {drop();}

5. Jeśli kod ma więcej niż powiedzmy 2-3 ekrany, często dobrze podzielić go na mniejsze kawałki, umieszczając osobne akcje w osobnych funkcjach np.
Kod:
extern void object::przyklad() {
   poczatek();
   while (...)   {
       SprawdzEnergie();
       ZnajdzTytan();
       SprawdzEnergie();
       ZaniesDoHuty();
   }
}


FE4R napisał/a:
Dlatego robotowi uprościłem zadanie - zamiast sprawdzać, co ma w chwytaku, wyrzuci, to co ma. Jeśli jest to ruda - następna pętla i tak nakaże mu to podnieść. W końcu to najbliższy kawałek rudy. A poza tym ze znanego programu 'SwitchCell' wiadomo, iż funkcje takie jak 'grab()' czy drop()' nie kosztują robota ani grama energii.
Owszem, oszczędzasz energię. Ale tracisz czas. Położenie i podniesienie tego samego kawałka rudy trwa całkiem sporą chwilę. Kiedy scenariusz wymaga budowy bazy przed atakiem obcych, każde 3 sekundy są cenne.

FE4R napisał/a:
Dla usprawnienia mogłem dać program na każdym kroku robota, jednakże nie zawsze się to opłaca, gdy elektrownia jest blisko i jesteś pewny, że robot dojdzie.
To niejawne założenie ogranicza uniwersalność programu. Nic nie stoi na przeszkodzie, żeby badać potrzebę podładowania baterii bota po każdym kroku. Przy obecnej koncepcji programu to tylko wykonanie jednej instrukcji warunkowej, jednego sprawdzenia:
Kod:
if (energyCell.energyLevel < 0.3) {
   Podladuj;  // funkcja 'Podladuj' zawiera cala obsluge energii
}


FE4R napisał/a:
4) Co to za blok ze zmienną 't'?

Zmienna 't' określa tytan. Ale nie byle jaki. Określa tytan, który czasami robot potrafi tam zastać po przybyciu do hut z rudą tytanu. W takiej sytuacji odpowiednio się zachowa i odniesie tytan w bezpieczne miejsce, a potem wróci do rudy.
Takie rzeczy dobrze wyjaśniać w komentarzach wewnątrz programu, nie sądzisz?

Kod:
message("Potrzebuje ogniwa - robot od tytanu!");
[...]
message("Brak rudy tytanu!");
Gdzieś spotkałem takie sprytne budowanie komunikatów. Może Tobie też się spodoba:
Kod:
cMyName = "TytanBot: ";
[...]
message(cMyName +"Potrzebuje ogniwa!");
message(cMyName +"Brak rudy tytanu!");


FE4R napisał/a:
- Dla robotów latających - opanowanie temperatury silników oraz mocy ogniwa.
( z silnikami będzie problem, gdyż nie da się tego przewidzieć - jedyne wartości jakie zwraca temperatura silnika to '0' lub '1')[/i]
Skądże znowu! Cecha temperature zwraca temperaturę pomiędzy 0 (zimne) a 1 (max. przegrzanie). Kłopot w tym, że w swoim programie do przemieszczania bota używasz wyłącznie funkcji goto(). To powoduje, że od momentu startu (początek wykonywania polecenia goto(punkt)) do momentu dotarcia na miejsce (koniec wykonywania) nie masz żadnej kontroli nad botem. Funkcja goto() jest wygodna w użyciu, ale zapewnia tylko prymitywną obsługę przegrzewania się silnika odrzutowego: w momencie, kiedy się przegrzeje (temperature==1), bot opada. Bez względu na miejsce przymusowego lądowania (np. chlup do wody! kiedy parę metrów obok jest suchy i płaski ląd). Następnie odczekuje do czasu całkowitego wystudzenia silnika (temperature==0) i leci dalej do celu. Czeka do pełnego ostudzenia nawet, kiedy cel jest już całkiem blisko i wystarczyłoby ostudzić silnik tylko trochę.
TIP1: najprecyzyjniej można opanować temperaturę silnika odrzutowego, kiedy bota przemieszcza się przez odpowiednie sterowanie silnikami (motor() i jet()).
TIP2: można pilnować temperatury nawet przy użyciu samego goto(). Trzeba tylko przed lotem sprawdzić, czy trasa będzie wymagać międzylądowania technicznego i w okolicy takiego punktu wyznaczyć pośredni cel lotu:
Kod:
void object::mygoto(point gdzie) {
  float odl;
  point punkt;
 
  // obsługa temperatury
  if (category==WingedGrabber || category==WingedShooter || category==WingedOrgaShooter || category==WingedSniffer) {
    // 50m w powietrzu to wzrost temperatury o ~0.17 (1/50=0.02) 
    odl=distance(position, gdzie);
    while (temperature+0.17*odl*0.02 > 0.75) {
      // staraj się nie dopuścić do przekroczenia 75% max.temp. silnika
      // 75% = ok.220m
      odl=(0.75-temperature)/(0.02*0.17);
      turn(direction(gdzie));
      punkt.z=position.z;
      do {
        punkt.x = (odl*cos(orientation))+position.x;
        punkt.y = (odl*sin(orientation))+position.y;
        odl = odl-5;
      } while (!(bezpiecznylad(punkt, 1)));
      goto(punkt);
      czujnikTemp(0);
      odl=distance(position, gdzie);
    }
  } // koniec obsługi temperatury
  goto(gdzie);
}

gdzie czujnikTemp(nTemp) to własna funkcja obsługi przegrzania, np.:
Kod:

void object::czujnikTemp(float maxTemp)
{
  if (temperature > maxTemp) {
    message("TytanBot: Szukam miejsca do lądowania technicznego", DisplayInfo);
    [...] // poszukaj odpowiedniego miejsca, wyladuj i poczekaj
  }
}
Zaś bezpiecznylad(punkt, wys) to funkcja własna, która sprawdza czy w miejscu punkt, podanym jako argument, można bezpiecznie wylądować (teren położony nad poziomem morza, nie za bardzo nachylony).

Luke, trust me. Use FUNCTIONS, Luke.
 
     
FE4R 


Twoja ulubiona misja: Saari - Inwazja
Pomógł: 4 razy
Wiek: 24
Dołączył: 21 Paź 2009
Posty: 144
Wysłany: 03-11-2009, 17:12   Re: Program dla robota obsługującego hutę.

pipok napisał/a:
W ogóle nie jest przejrzysty, bo coś Ci przy wklejaniu na forum zjadło wszystkie wcięcia.
Poza tym możesz i powinieneś użyć kilku innych środków dla poprawienia czytelności:
1. "Komentarze są za darmo"...
2. Jednoliterowe nazwy zmiennych ułatwiają pisanie kodu, ale znacznie utrudniają późniejsze zrozumienie (a więc i konserwację). Lepiej nadawać takie nazwy, które coś mówią o ich zawartości.

Tak myślałem, że mi zje wszelakie odstępy. Forum nie jest przystosowane do programów z Colobota, a ręcznie nie będę 'spacjować' każdej linijki. Dlatego też dałem graficzne przedstawienie programu. Mam nadzieję, że jest czytelne, aby zrozumieć, o co chodzi. Tekstową dałem, gdyby ktoś chciał go sobie użyć.

Cytat:
Owszem, oszczędzasz energię. Ale tracisz czas. Położenie i podniesienie tego samego kawałka rudy trwa całkiem sporą chwilę. Kiedy scenariusz wymaga budowy bazy przed atakiem obcych, każde 3 sekundy są cenne.

Zauważ jednak, że program zakłada, iż wszelkie budynki i surowce będą dostępne - więc jest to głównie program dla robota, który jest bez zagrożenia ze strony obcych czy presji czasu. 3 sekundy są cenne, owszem, ale znacznie ułatwiają życie przy pisaniu programu, gdyż nie muszę powtarzać całego projektu, zanim w ogóle zacznę pętlę 'while'. Program, owszem przystosowałem do swojej mapy i robota, tak aby robił, to, co chcę od niego. Gdybym chciał napisać program do misji, prawdopodobnie wyglądałby inaczej.

FE4R napisał/a:
To niejawne założenie ogranicza uniwersalność programu. Nic nie stoi na przeszkodzie, żeby badać potrzebę podładowania baterii bota po każdym kroku. Przy obecnej koncepcji programu to tylko wykonanie jednej instrukcji warunkowej, jednego sprawdzenia:
Kod:
if (energyCell.energyLevel < 0.3) {
   Podladuj;  // funkcja 'Podladuj' zawiera cala obsluge energii
}

W poprawce jest to zmienione, gdyż dodałem funkcję podładowywania na większej ilości kroków.

Cytat:
Takie rzeczy dobrze wyjaśniać w komentarzach wewnątrz programu, nie sądzisz?

Nie jestem fanem komentarzy. Objaśniają pewne rzeczy, a mi utrudniają edycję programu.

Cytat:
Skądże znowu! Cecha temperature zwraca temperaturę pomiędzy 0 (zimne) a 1 (max. przegrzanie). Kłopot w tym, że w swoim programie do przemieszczania bota używasz wyłącznie funkcji goto().

Zrobiłem test. Jeden robot, używający goto(); przeleciał spory dystans.
Drugi robot miał go na 'radarze();' i monitorował jego temperaturę silników. Miała wyskoczyć wiadomość o przegrzaniu w połowie(profilktycznie) przegrzania silnika. A jednak jedyną wartość jaką zwrócił mi robot to 0, czyli zimny do 1 czyli całkowicie przegrzany. Owszem, gdy wejdziesz w program i na pomarańczowym tle zmiennych masz np. 'a.temperature = 0.5', ale mój robot w ogóle nie interpretuje czegoś takiego jak:

'if(a.temperature > 0.5)
{
message("Przegrzanie!");
}

Poza tym jest pewny szczegół, że niektóre planety mają inne temperatury, więc na Wulkanii robot latający, przynajmniej ze zwykłym ogniwem(lub jedynym atomowym na mapie) - nie byłby zbyt skuteczny.

Zapostuję poprawiony(tylko trochę) program, gdy znajdę tą stronę adiblol'a do programów z Colobot.
 
     
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 03-11-2009, 21:04   Re: Program dla robota obsługującego hutę.

FE4R napisał/a:
Tak myślałem, że mi zje wszelakie odstępy. Forum nie jest przystosowane do programów z Colobota, a ręcznie nie będę 'spacjować' każdej linijki.
Nie obraź się, ale innym wcięć nie zjada... Widocznie wklejałeś kod jakąś dziwaczną metodą.

FE4R napisał/a:
3 sekundy są cenne, owszem, ale znacznie ułatwiają życie przy pisaniu programu, gdyż nie muszę powtarzać całego projektu, zanim w ogóle zacznę pętlę 'while'.
"Całego projektu"? Chłopie! Sprawdzenie czy bot czegoś nie trzyma i odpowiednio wyrzucenie tego lub nie, zajmuje raptem parę linijek! Napisanie modyfikacji do tego, co napisałeś zajęłoby nie więcej niż minutę. Dosłownie. Jedna ze złotych reguł: nie rób pseudo-oszczędności przy pisaniu.

FE4R napisał/a:
Zrobiłem test. Jeden robot, używający goto(); przeleciał spory dystans.
Drugi robot miał go na 'radarze();' i monitorował jego temperaturę silników. Miała wyskoczyć wiadomość o przegrzaniu w połowie(profilktycznie) przegrzania silnika. A jednak jedyną wartość jaką zwrócił mi robot to 0, czyli zimny do 1 czyli całkowicie przegrzany.
Bez przegrzania silników do maksimum(!) bot przeleci jakieś 220 metrów, nie więcej. Ale już po kilkunastu metrach można wykryć wzrost temperatury silnika.
Sprawdzanie temperatury widziałem działające w wielu programach, również własnych.

FE4R napisał/a:
ale mój robot w ogóle nie interpretuje czegoś takiego jak:

'if(a.temperature > 0.5)
{
message("Przegrzanie!");
}
Ale co to jest "a" w tym kodzie?!?
FE4R napisał/a:
Poza tym jest pewny szczegół, że niektóre planety mają inne temperatury, więc na Wulkanii robot latający, przynajmniej ze zwykłym ogniwem(lub jedynym atomowym na mapie) - nie byłby zbyt skuteczny.
Co ma do rzeczy temperatura powierzchni planety?


FE4R napisał/a:
Cytat:
Takie rzeczy dobrze wyjaśniać w komentarzach wewnątrz programu, nie sądzisz?
Nie jestem fanem komentarzy. Objaśniają pewne rzeczy, a mi utrudniają edycję programu.
Jak by to ująć... hmm... jesteś jeszcze bardzo młody.
 
     
adiblol 
Administrator forum
FLOSS FTW!


Twoja ulubiona misja: porównywanie formatów audio
Pomógł: 18 razy
Dołączył: 21 Kwi 2008
Posty: 1313
Skąd: pokój odsłuchowy
Wysłany: 03-11-2009, 21:24   

pipok napisał/a:
FE4R napisał/a:
Poza tym jest pewny szczegół, że niektóre planety mają inne temperatury, więc na Wulkanii robot latający, przynajmniej ze zwykłym ogniwem(lub jedynym atomowym na mapie) - nie byłby zbyt skuteczny.

Co ma do rzeczy temperatura powierzchni planety?

Nie chodziło mu o temperaturę powierzchni (bo tego się nie da zdefiniować w pliku misji), lecz o szybkość przegrzewania się silnika (parametr range)
_________________
1Tbps Project && Telecomix Network

 
 
     
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 03-11-2009, 21:37   

Ach, to! No, niestety, jedyna metoda, żeby było niezależnie od tego parametru, to program, gdzie bot przemieszcza się na większe dystanse tylko poprzez korzystanie z motor() i jet(), ze sprawdzaniem temperatury na bieżąco.

PS. Ale dla nowych botów, skonstruowanych podczas misji, i tak jest range ma standardową wartość...
 
     
FE4R 


Twoja ulubiona misja: Saari - Inwazja
Pomógł: 4 razy
Wiek: 24
Dołączył: 21 Paź 2009
Posty: 144
Wysłany: 03-11-2009, 23:01   Re: Program dla robota obsługującego hutę.

pipok napisał/a:
Nie obraź się, ale innym wcięć nie zjada... Widocznie wklejałeś kod jakąś dziwaczną metodą.

Ctrl+A Ctrl+C Ctrl+V dziwne chyba nie jest.

Cytat:
Ale co to jest "a" w tym kodzie?!?

Dowolny obiekt latający z temperaturą silnika? >.>

Cytat:
Jak by to ująć... hmm... jesteś jeszcze bardzo młody.

Ty też. Duchem. :P

Widać pipok, że masz dobre podejście do sprawy, a ja zacząłem tworzyć 'pod-funkcje' by skrócić program i oszczędzić miejsca. Jednak niedokładnie rozumiem typów funkcji; ok - jest główna funkcja extern i te pod-funkcje na dole.
Ale za każdym razem, gdy jakąś zaczynam, która jest trochę bardziej skomplikowana, nie wiem jakiego typu użyć. Każda więc zaczyna się:

Kod:
void object:: nazwafunkcji ()
{
       instrukcje;
}


PS.
Ok. Znalazłem cywilizowany sposób na przedstawienie programu; bez potrzeby kopiowania screenów.

Kod:
extern void object::Collect2000()
{
    while(true)
    {
        errmode(0);
       
        if(this.load != null)
        {
            drop();
        }
       
        while(radar(TitaniumOre) != null)
        {
            ipf(90);
           
            object o, c, t, f;
           
            f = radar(RedFlag);
           
            o = radar(TitaniumOre);
           
            Charge();
           
            goto(o.position);
            grab();
           
            c = radar(Converter);
           
            if(c != null)
            {
                goto(c.position);
               
                t = search(Titanium, c.position);
               
                if(t != null)
                {
                    if(distance(t.position, c.position) < 6)
                    {
                        Tytan();
                       
                        o = radar(TitaniumOre);
                        goto(o.position);
                        grab();
                       
                        goto(c.position);
                    }
                }
               
                drop();
                move(-4);
               
                do
                {
                    wait(0.1);
                }
                while(radar(Titanium, 0, 15, 0, 6) == null);
               
                move(4);
                grab();
               
                goto(space(f.position, 0, 20, 3));
                drop();
               
                Charge();
            }
        }
    }
   
    message("Brak tytanu!");
   
    do
    {
        wait(1);
    }
    while(radar(TitaniumOre) == null);
}


void object:: Charge ()
{
    int p;
   
    p = PowerCell;
   
    if(energyCell.energyLevel < 0.3)
    {
        if(this.energyCell.category == p)
        {
            object px;
           
            px = radar(PowerStation);
           
            if(px != null)
            {
                goto(px.position);
               
                do
                {
                    wait(1);
                }
                while(energyCell.energyLevel < 1);
            }
            else
            {
                Upgrade();
            }
           
        }
        else
        {
            Upgrade();
        }
    }
}

void object:: Upgrade ()
{
    object x;
    string y;
   
    y = "Brak paliwa - robot od rudy!";
   
    x = radar(NuclearCell);
   
    if(x != null)
    {
        goto(x.position);
       
        grab();
        drop(Behind);
        grab(EnergyCell);
        drop();
        grab(Behind);
        drop(EnergyCell);
    }
    else
    {
        message(y);
    }
}

void object:: Tytan ()
{
    object f;
   
    turn(90);
    drop();
    turn(-90);
    grab();
   
    f = radar(RedFlag);
   
    goto(space(f.position, 0, 20, 3));
    drop();
}


Objaśnienia:
@pipok: wolę się rozpisać niż upychać komentarze w programie...

Funkcja Charge:
Prosta funkcja do sprawdzenia, czy robot ma wystarczająco energii, jeśli nie, zaleca się podładowanie. Program sprawdza również typ ogniwa robota - jeśli jest atomowe, użyje innej funkcji, 'Upgrade'; użyje jej również, jeśli nie ma elektrowni.

Funkcja Upgrade:
Poleca wymienić stare zwykle ogniwo elektryczne, bądź zużyte atomowe na nowe, jeśli istnieje.

Funkcja tytan:
Zajmie się tytanem koło huty, jeśli robot go tam zastanie.

O co chodzi z czerwona flaga?
Utworzyłem czerwona flagę blisko huty; między nią a elektrownią, wokół której robot z użyciem 'space();' rozmieści tytan.

Jak narazie pracuję nad udoskonaleniem samoładowania; potem popracuję nad ucieczką przed obcymi lub wezwaniem pomocy.

Jak na razie nie będę się zajmował robotami latającymi.

@pipok
Mam ambicję by dogonić mistrza. ;)
 
     
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 04-11-2009, 08:57   Re: Program dla robota obsługującego hutę.

FE4R napisał/a:
Jednak niedokładnie rozumiem typów funkcji; ok - jest główna funkcja extern i te pod-funkcje na dole.
Shoter opisał posługiwanie się funkcjami w dziale 'Problemy [programowanie]' w wątku [poradnik]funkcje 'główne' i poboczne.
FE4R napisał/a:
nie wiem jakiego typu użyć. Każda więc zaczyna się:
Kod:
void object:: nazwafunkcji ()
{
       instrukcje;
}
Jeśli te funkcje powstają przez proste przeniesienie kodu z głównego programu, to na ogół nie ma potrzeby nic zmieniać. Co najwyżej funkcja niepotrzebnie jest wiązana z botem ('object::') - zob. temat o funkcjach.

Kod:
extern void object::Collect2000()
{
   while(true)
   {
      errmode(0);
Nie bardzo wiem, dlaczego wyłączasz reakcję na błędy, jeśli nie obsługujesz samodzielnie w programie... W każdym razie: nie bardzo jest sens robić to wewnątrz pętli. Skoro nigdzie nie przywracasz standardowej reakcji na błędy (errmode(1);), to raz wyłączona, pozostanie wyłączona przez cały czas działania programu, nie ma sensu wykonywanie tej instrukcji za każdym obrotem pętli.

Kod:
      while(radar(TitaniumOre) != null)
      {
         ipf(90);
Podobnie - wewnątrz pętli, a więc za każdym jej obrotem, ustawiasz parametr, który wystarczyłoby ustawić raz, przed wszystkimi pętlami. Skoro nigdzie już nie zmieniasz ipf na inne.
Kod:
         c = radar(Converter);
         
         if(c != null)
         {
            goto(c.position);
            [...]
         }
      }
Jest sprawdzenie, czy istnieje huta, ale nie ma żadnej reakcji na przypadek, kiedy nie istnieje. Albo zakładasz, że huta zawsze będzie dostępna - wtedy ten 'if' nie jest potrzebny. Albo dopuszczasz, że może się zdarzyć, że huty nie ma - wtedy wypada zrobić jakieś 'else', przynajmniej z komunikatem. Inaczej bot ugrzęźnie w jałowej pętli, nawet nie sygnalizując kłopotów. W funkcji 'Charge' zrobiłeś obsługę braku elektrowni...

Kod:
void object:: Charge ()
{
   int p;
   
   p = PowerCell;
   
   if(energyCell.energyLevel < 0.3)
   {
      if(this.energyCell.category == p)
Zmienna p nie ma większego sensu. Przechowuje stałą symnboliczną 'PowerCell' i jest w kodzie użyta tylko raz, w porównaniu. Wyobraź sobie, że do p włożysz inną wartość (bo możesz, przecież to zmienna), np. 'NuclearCell'. Czy kod będzie wówczas sensowny? Nie. Co w takim razie zyskujesz używając zmiennej p? Nic. W takim razie tylko zwiększa kod, zużywa pamięć i utrudnia zrozumienie działania:
Kod:
void object:: Charge ()
{
   if(energyCell.energyLevel < 0.3)
   {
      if(this.energyCell.category == PowerCell)


Funkcja wymiany ogniwa w zasadzie jest poprawna...
Kod:
void object:: Upgrade ()
{
   [...]   
   x = radar(NuclearCell); 
   if (x != null)
   {
      goto(x.position);
      grab();
ale wrażliwa na podstawowy kłopot: być może najbliższe, znalezione radarem ogniwo wcale nie jest dobre. Całkiem prawdopodobne, że jest mniej więcej w takim samym stanie jak to, którego bot teraz używa. Po prostu, to może być jego stare ogniwo, odłożone wcześniej. Przy okazji: tę funkcję nazwałbym nieco inaczej (żaden upgrade, jeśli już korzysta z ogniwa atomowego i wymienia na inne ;) ) Nazwa następnej funkcji, Tytan(), tez może oznaczać różne rzeczy. Możesz śmiało używać wielowyrazowych, dłuższych nazw, np.: OdlozTytanNaSklad

FE4R napisał/a:

O co chodzi z czerwona flaga?
Utworzyłem czerwona flagę blisko huty; między nią a elektrownią, wokół której robot z użyciem 'space();' rozmieści tytan.
A jeśli nie będzie flagi na planszy? ;)

FE4R napisał/a:

Funkcja tytan:
Zajmie się tytanem koło huty, jeśli robot go tam zastanie.
Przeanalizuj i przetestuj dokładnie cały ten przypadek. Wysyłasz bota prosto do huty, ma wjechać do środka. Potem sprawdzasz, czy leży w niej kostka tytanu. Robisz arbitralny obrót o 90 stopni, odkładasz (rudę), obrót z powrotem, bierzesz (kostkę). Czy te czynności na pewno doprowadzą do odłożenia rudy i pochwycenia kostki tytanu? Skąd wiesz, że bot jest we właściwej pozycji względem tytanu?
Jedziesz z kostką na składowisko, zostawiasz. Tytan załatwiony. Teraz szukasz najbliższej bryły rudy, bierzesz ją i jedziesz do huty... Czy to na pewno będzie ta sama ruda, którą zostawiłeś przed obsłużeniem kostki tytanu? Co dzieje się w tym czasie z rudą, którą odłożyłeś? (bot zapewne był wewnątrz huty, kiedy ją odkładał...).


FE4R napisał/a:
@pipok
Mam ambicję by dogonić mistrza. ;)
Tak trzymaj :)
 
     
FE4R 


Twoja ulubiona misja: Saari - Inwazja
Pomógł: 4 razy
Wiek: 24
Dołączył: 21 Paź 2009
Posty: 144
Wysłany: 05-11-2009, 23:41   

Biore poprawki i tworze co raz wiecej funkcji, aby uproscic glowna funkcje maksymalnie.
Jednak jest kilka bledow, ktore opisze ponizej.

Znowu przepraszam za brak polskich znakow - angielski laptop.

Kod:
extern void object::CollectTitaniumV3()
{
    errmode(0);
   
    ipf(90);
   
    int surowiec, produkt;
   
    surowiec = TitaniumOre;
    produkt = Titanium;
   
   
    if(this.load != null)
    {
        if(this.load.category == surowiec)
        {
            Proces();
        }
       
        if(this.load.category == produkt);
        {
            Store();
        }
       
        if(this.load.category != produkt)
        {
            drop();
        }
    }
   
    while(true)
    {
        while(radar(surowiec) != null)
        {
            object ore;
           
            ore = radar(surowiec);
           
            if(ore != null)
            {
                Recharge();
               
                goto(ore.position);
                grab();
               
                Proces();
            }
            else
            {
                message("Brak surowca!");
                wait(1);
            }
        }
    }
}

void object::Proces()
{
    object conv = radar(Converter);
   
    if(conv != null)
    {
        Recharge();
       
        goto(conv.position);
       
        Check();
       
        move(-4);
       
        do
        {
            wait(1);
        }
        while(radar(Titanium, 0, 20, 0, 6) == null);
       
        move(4);
        grab();
       
        Store();
       
        Recharge();
       
    }
    else
    {
        message("Brak przetworni!");
    }
   
}

void object::Store()
{
    object store;
   
    store = radar(RedFlag);
   
    goto(space(store.position, 0, 20, 3));
    drop();
}

void object::Check()
{
    if(radar(Titanium, 0, 30, 0, 6) != null)
    {
        object ore = search(TitaniumOre, position), conv = radar(Converter);
       
        turn(90);
        drop();
        turn(-90);
        grab();
       
        Store();
       
        goto(ore.position);
        grab();
       
        goto(conv.position);
        drop();
    }
    else
    {
        drop();
    }
}

void object::Recharge()
{
    if(energyCell.energyLevel < 0.3)
    {
        if(this.energyCell.category == NuclearCell)
        {
            NuclearRecharge();
        }
       
        if(this.energyCell.category == PowerCell)
        {
            object px = radar(PowerStation);
           
            if(px != null)
            {
                errmode(0);
               
                int err;
               
                err = goto(px.position);
               
                if(err != 0)
                {
                    turn(direction(px.position));
                    move(distance(position, px.position) - 4);
                   
                    do
                    {
                        wait(1);
                    }
                    while(err != 0);
                    move(4);
                   
                    do
                    {
                        wait(1);
                    }
                    while(energyCell.energyLevel < 1);
                }
            }
            else
            {
                NuclearRecharge();
            }
        }
    }
}

void object::NuclearRecharge()
{
    object cell = radar(NuclearCell);
   
    if(cell != null)
    {
        goto(cell.position);
        grab();
        drop(Behind);
        grab(EnergyCell);
        drop();
        grab(Behind);
        drop(EnergyCell);
    }
    else
    {
        cell = radar(PowerCell);
       
        if(cell != null)
        {
            goto(cell.position);
            grab();
            drop(Behind);
            grab(EnergyCell);
            drop();
            grab(Behind);
            drop(EnergyCell);
        }
        else
        {
            message("Na planecie nie ma zrodel energii!");
        }
    }
}


Jednak jest kilka problemow, z ktorymi musze sie uporac, zanim program bedzie w niezawodny.

1. Program czasami sie urywa po zakonczeniu funkcji 'Store', jakby 'while(true)' nie istnialo.

2. Problem, ktory pipok juz wspomnial. Robot, jesli przypadkiem znajdzie gotowy tytan w hucie, odklada go przy czerwonej fladze, ale nie wraca do kawalka, ktory zostawil przy hucie, ale do kawalka przy kopalni(gdyz jest blizej), POMIMO ze ruda przy hucie zostala przypisana do zmiennej 'ore'. Czemu wiec zmienna zamienia obiekt z rudy przy hucie na rudzie przy kopalni? Oczywiscie gdy robot wezmie rude z kopalni i uda sie do huty, zastanie tam drugi kawalek, ktory wywola blad i zatrzyma program.

3. Stworzylem rowniez pewien warunek w funkcji 'Recharge()' z errmode(0), ktorego nie jestem pewien.
Potem tworze petle do i robot czeka, az blad minie, a gdy usuwam robota blokujacego elektrownie, zbieracz dalej czeka 4 metry przed. Nie rusza sie. Nie wiem, co zrobic.

Mam nadzieje, ze po skonczeniu tych poprawek zajme sie robotem latajacym i program bedzie prawie gotowy i idealny.

Pozdrawiam,
FE4R
 
     
pipok 


Dołączył: 24 Cze 2009
Posty: 53
Wysłany: 10-11-2009, 17:43   Re: Program dla robota obsługującego hutę.

Nigdzie nie przywracasz standardowej reakcji na błędy: errmode(1). Lepiej unikać takiego podejścia, bo nie wiesz, w którym, miejscu i z jakiego powodu pojawiają się kłopoty. Powinno się wyłączać standardową obsługę błędów tylko w wybranych miejscach, gdzie wiadomo, że może się pojawić błąd i gdzie jest zaplanowane działanie, które rozwiązuje problem.

Pomijając programy dla obcych istot w COLOBOCIE, bo wtedy lepiej żeby mrówka zrobiła coś głupiego albo się zapętliła na nicnierobieniu, niż żeby walnęła komunikatem o błędzie.

Przykład niedopracowanej obsługi błędów:
Kod:
errmode(0);
int err;
err = goto(px.position);
if(err != 0)
{
     turn(direction(px.position));
     move(distance(position, px.position) - 4);
     
     do
     {
         wait(1);
      }
      while(err != 0);
      move(4);
Mianowicie: jeśli goto(px.position) się nie powiedzie (czyli err!=0), to późniejsze move(4) nie zostanie NIGDY wykonane. Program utknie w nieskończonej pętli czekania. Dlaczego? Ponieważ oczekiwanie (wait(1)) jest powtarzane w pętli tak długo, jak długo wartość zmiennej err jest niezerowa. A ona się wewnątrz tej pętli nie zmieni! Ta zmienna wciąż ma tę samą wartość, równą kodowi błędu, jaki wystąpił podczas goto(px.position).
Poprawne rozwiązanie powinno wyglądać mniej więcej tak:
Kod:
int err;
errmode(0);
err = goto(px.position);
errmode(1); // !!!
if(err != 0)
{
     turn(direction(px.position));
     errmode(0); // bo wykonanie 'move' moze sie nie udac
     move(distance(position, px.position) - 4);
     // ale jesli sie nie uda, to nie ma problemu,
     // niech bot zostanie, gdzie jest (i tak ma czekac).
     // Dlatego nawet nie analizujemy, czy sie udalo
     errmode(1);
     
     do
     {
         wait(1);
         // sprobuj znowu dostac sie do elektrowni
         errmode(0); err = goto(px.position); errmode(1);
      }
      while(err != 0);  // ponawiaj proby, jesli sie nie udaje
      // w tym miejscu jest pewne, ze goto() sie udalo,
      // czyli bot jest w hucie
 
     
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