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

Problemy [programowanie] - jak zrobić goto

sajmon313 - 24-12-2009, 22:00
Temat postu: jak zrobić goto
Problem jest następujący:
jak zrobić funkcje działającą identycznie jak goto(), z użyciem move() i turn(), lub motor().

Po co?
Żeby dodać fajne rzeczy do goto, np. omijanie obcych, nie lądowanie w wodzie, nie wpadanie do dziur o stromych scianach i inne tego typu przydatne rzeczy.

Berserker - 24-12-2009, 22:22

Moim zdaniem przy uzyciu CBot to jest niemozliwe. Dlaczego? goto() (przynajmniej z domyslnymi parametrami) wybierajac droge uwzglednia pochylenie terenu, objetosc obiektow i pare takich innych bzdur, ktore sa niemozliwe do sprawdzenia przy uzyciu CBota (pochylenia terenu nie sprawdzi sie nie wjezdzajac samemu, nie mozna sprawdzic czy sie zahaczy o budynek bo pozycja budynku zwraca tylko srodek). Jesli wierzysz, ze ci sie uda, to proponuje zaczac rozgryzanie goto() od zagadki: dlaczego jesli robotowi kaze sie podjechac na pozycje identyczna z pozycja robota to robot musi z niej zjechac, obrocic sie i wrocic? :)
sajmon313 - 24-12-2009, 22:41

Berserker napisał/a:
Moim zdaniem przy uzyciu CBot to jest niemozliwe.

Planuję dokładnie to zbadać
Berserker napisał/a:
pochylenia terenu nie sprawdzi sie nie wjezdzajac samemu

Da się!
Kod:
point pos1,pos2;
pos1=position;
pos2=pos1;
pos2.x=pos1.x+0.5;
pos1.x=pos1.x-0.5;

teraz można porównac topo(pos1) i topo(pos2) i mamy pochylenie w x
oczywiście musiałoby to być bardziej rozbudowane.
Berserker napisał/a:
nie mozna sprawdzic czy sie zahaczy o budynek bo pozycja budynku zwraca tylko srodek

ale znamy też kategorię - a więc mozna sporządzić tablice z wymiarami wszystkich możliwych obiektów
Berserker napisał/a:
Jesli wierzysz, ze ci sie uda, to proponuje zaczac rozgryzanie goto() od zagadki: dlaczego jesli robotowi kaze sie podjechac na pozycje identyczna z pozycja robota to robot musi z niej zjechac, obrocic sie i wrocic? :)

moje nowe lepsze goto nie będzie się zachowywało w ten sposób. ;P

Berserker - 25-12-2009, 02:30

Hm, najtrudniejsze moim zdaniem jest znalezienie drogi do podazania. No i jeszcze jest piekna Matka Natura, ktora sadzi rozne grzyby nie wykrywalne przez radar. O tym sie pomysli.

Proponuje za pomoca tablic ustalic szereg punktow, ktore trzeba osiagnac by dojsc do celu. Jak znajde w sobie checi to sprobuje cos takiego napisac. Podejrzewam, ze takie cos bedzie wcale dlugo liczylo te punkty (dla pozycji odleglej o 50m zakladajac, ze takie punkty liczymy co metr bedzie ich ponad 50). Trzeba bedzie rowniez napisac cos, aby robot potrafil sam wjechac np. do odgromnika (jadac na wprost ma 50% szansy, ze zahaczy o ten smieszny slupek), ale to da sie zalatwic. Fajnie by tez bylo, by robot omijal slepe uliczki. I to chyba wszystko.

sajmon313 - 25-12-2009, 09:58

możnaby zacząć od czegoś takieggo:
Kod:
 p1=position;
 move(x);
 p2=position;
 if(p1==p2) turn(d);

przy czym d byłoby ustalane przez robota po dokładnym zbadaniu najbliższej okolicy: pochyłość terenu, inne obiekty.

Berserker - 25-12-2009, 12:43

Ja myslalem, zeby najpierw ustalic cala sciezke, a dopiero pozniej nia isc, a nie chodzic tak po kawalku. Fajnie by bylo gdyby rowniez ktos oswoil instrukcje search(), bo ona mnie sie nie slucha :(

Prosba:
Ma ktos spis obiektow w taki sposob:
Kod:

list[UraniumOre] = UraniumOre;

Albo ktos ma duzo czasu i moglby zrobic?

FE4R - 25-12-2009, 13:28

Twoje pytanie jest bez sensu, gdyż funkcja goto(); omija wszystkie przeszkody, omija wodę, budynki, ląduje robotem latającym, gdy silnik się przegrzeje. Gdy wpiszesz daną kategorię, podchodzi pod odpowiednie miejsce. Gdy wpiszesz Converter, podejdzie tak, aby postawić coś na środku. Nie stanie na środku. Gdy wpiszesz WheeledGrabber, stanie za robotem, by zmieni baterię. Nie będzie starał się na niego wjechać. A mimo to, pozycja robota, do którego podchodzisz to środek.

A omijanie obcych? Nie wpadanie do wody?
Nie lepiej najpierw obcych zabić? Można również wykorzystać program z Wyzwania -> Przetrwanie we wrogim środowisku
A co do wpadania do wody, to Berserker miał dobry pomysł w temacie AlienKiller2.

Berserker - 25-12-2009, 14:02

@up
Moze nie jest to mozliwe, ale jestem bardzo ciekaw, ile uda nam sie zrobic.

@topic
Jeszcze jedna prosba: jak wyliczyc orientacje wymagana w danej pozycji by zwrocic sie w kierunku pozycji docelowej? :|

adiblol - 25-12-2009, 18:51

Berserker napisał/a:
jak wyliczyc orientacje wymagana w danej pozycji by zwrocic sie w kierunku pozycji docelowej?

Kod:
direction(siedziba_microsoftu.position);

FE4R - 25-12-2009, 20:42

Berserker napisał/a:
Jeszcze jedna prosba: jak wyliczyc orientacje wymagana w danej pozycji by zwrocic sie w kierunku pozycji docelowej? :|

Też się zastanawiam, o co chodzi z tą zmienną 'orientation'. Dwa roboty ustawione koło siebie i skierowane w tym samym kierunku. Jeden ma orientation 43, a drugi 400 coś... myślałem, że max to jakieś 180 albo 360...

Berserker - 25-12-2009, 21:27

Cytat:
direction(siedziba_microsoftu.position);

Naprawde uwazasz mnie za tak glupiego, ze bym na to nie wpadl? Raz, to pokazuje kierunek a nie orientacje, a dwa, ja chce znac orientacje bez podjezdzania robotem w dane miejsce, sprawdzania kierunku i wracania...

Cytat:
Też się zastanawiam, o co chodzi z tą zmienną 'orientation'. Dwa roboty ustawione koło siebie i skierowane w tym samym kierunku. Jeden ma orientation 43, a drugi 400 coś... myślałem, że max to jakieś 180 albo 360...

Orientacja to jest "kierunek bezwzgledny", pokazuje o ile stopni jest odchylony kierunek patrzenia robota od osi x (czyli od kierunku wschodniego). Dodanie/odjecie od tej wartosci 360° w praktyce nie zmienia jej, wiec 3600° = 0°, tylko prawdopodobnie pierwszy robot zrobil 10 obrotow w lewo.

sajmon313 - 26-12-2009, 00:11

Berserker napisał/a:
Cytat:
direction(siedziba_microsoftu.position);

Naprawde uwazasz mnie za tak glupiego, ze bym na to nie wpadl? Raz, to pokazuje kierunek a nie orientacje, a dwa, ja chce znac orientacje bez podjezdzania robotem w dane miejsce, sprawdzania kierunku i wracania...

Cytat:
Też się zastanawiam, o co chodzi z tą zmienną 'orientation'. Dwa roboty ustawione koło siebie i skierowane w tym samym kierunku. Jeden ma orientation 43, a drugi 400 coś... myślałem, że max to jakieś 180 albo 360...

Orientacja to jest "kierunek bezwzgledny", pokazuje o ile stopni jest odchylony kierunek patrzenia robota od osi x (czyli od kierunku wschodniego). Dodanie/odjecie od tej wartosci 360° w praktyce nie zmienia jej, wiec 3600° = 0°, tylko prawdopodobnie pierwszy robot zrobil 10 obrotow w lewo.

możnaby podjechac 1m do przodu, i zobaczyć jak się zmieniły x i y
Kod:

point p1,p2;
dloat dir;
p1=position;
move(1);
p2=position;
dir=atatn((p1.x-p2.x)/(p1.y-p2.y));

i kontynuując możemy dojść do wartości takiej jak w CreateObject.

FE4R - 26-12-2009, 00:53

Berserker napisał/a:
Orientacja to jest "kierunek bezwzgledny", pokazuje o ile stopni jest odchylony kierunek patrzenia robota od osi x (czyli od kierunku wschodniego). Dodanie/odjecie od tej wartosci 360° w praktyce nie zmienia jej, wiec 3600° = 0°, tylko prawdopodobnie pierwszy robot zrobil 10 obrotow w lewo.

Doszedłem do tego, że 0 / 360 stopni to kierunek wschodni, ale dwa roboty prosto z fabryki skierowane w tym samym kierunku? Robiłem testy na PracticeBot, to orientation się resetowało po przekroczeniu zera / 360 stopni.

A co do sposobu sajmona, to chyba jest jakiś sposób, aby sprawdzać ten kąt bez użycia move();, np. mierzyć go na bieżąco, prawda? Jest trochę późno, więc nie mogę nic konkretnego napisać.

Berserker - 26-12-2009, 02:35

Cytat:
Doszedłem do tego, że 0 / 360 stopni to kierunek wschodni, ale dwa roboty prosto z fabryki skierowane w tym samym kierunku? Robiłem testy na PracticeBot, to orientation się resetowało po przekroczeniu zera / 360 stopni.

Mi sie wydaje, ze w pewnych momentach po prostu gra nie zauwaza, ze przekroczono magiczna granice pelnego kata i liczy dalej. Jesli chodzi o orientacje, to po wystarczajaco dlugim dodawaniu/odejmowaniu 360 w koncu sie wyrownaja.

Cytat:
kontynuując możemy dojść do wartości takiej jak w CreateObject.

Moze to przez godzine o ktorej pisze, ale za cholere nie rozumiem co ty napisales :P .

Chodzi mi o to, ze napisalem funkcje (ktora nie dziala, ale nvm). Wyglada ona tak:
Kod:
int object::Goto(point pos)
{
point center, dest[], F, R, L, adest;
int list[], i;
float dist, len;
float dir, orient, angle, pMax;
orient = orientation;
center = position;
pMax = 30;
len = 0.5;
pos.z = topo(pos);
do
{
F.x = center.x + cos(orient) * len;
F.y = center.y + sin(orient) * len;
F.z = topo(F);
if(atan((topo(F)-topo(center))/len) < pMax)
{
adest = F;
}
else
{
i = 0;
do
{
i++;
L.x = center.x + cos(orient+i*5) * len;
L.y = center.y + sin(orient+i*5) * len;
L.z = topo(L);
R.x = center.x + cos(orient-i*5) * len;
R.y = center.y + sin(orient-i*5) * len;
R.z = topo(R);
}
while(atan((topo(L)-topo(center))/len) > pMax and atan((topo(R)-topo(center))/len) > pMax);
if(topo(L) < topo(R)) adest = L;
else adest = R;
}
center = adest;
dest[sizeof(dest)] = adest;
if(sizeof(dest) > 1000) return 1;
dir = acos((pos.x-center.x)/distance2d(center, pos));
orient = dir+orient;

}
while(distance2d(center, pos) > 1);
i = 0;
while(distance2d(pos, position) > 1)
{
adest = dest[i++];
while(distance2d(position, adest) > 1)
{
dir = direction(adest);
motor(1-dir/90, 1+dir/90);
}
}
return 0;
}

Dziala ona tak: sprawdza ona punkt na pol metra w kierunku punktu docelowego. Jesli jest on zdatny do uzytku (wjechanie na niego jest mozliwe i nie powoduje katastrofy) to robot zapisuje go w tablicy dest. Jesli nie, sprawdza punkty na lewo i prawo, dopoki ktorys bedzie zdatny do uzytku. Teraz jednak pojawia sie problem. Od zatwierdzonego jako 'adest' punktu liczymy kolejny punkt. I w tym momencie potrzebna jest mi ta orientacja, bo nie wiem w ktorym kierunku mam zaczac liczyc kolejny punkt. Sprawdzilem za pomoca message() dystans kazdego punktu od pozycji docelowej. Zwieksza sie O_O z kazdym nowym punktem.

sajmon313 - 26-12-2009, 10:16

Berserker napisał/a:
Moze to przez godzine o ktorej pisze, ale za cholere nie rozumiem co ty napisales

Chodzi o to że można prosto dojść do wartości np. 1.5, 1.2
A jeszcze lepiej zamiast się ruszac robotem policzyć pozycje baterii względem robota.

Znamy oriantacje bezwzględną robota (taka same jak w punkcie startowym). W pkt startowym oriantacje obliczamy porównując position robota i jego baterii
(Pożniej w kolejnym punkcie orientacja będzie taka jak obliczona w poprzednim)
I znamy pozycję do której chcemy dotrzeć, więc mozemy obliczyć orientację bezwzględną w jakiej musi znajdować się robot żeby patrzył w tę stronę.

W tej chwili nie mam czasu, ale jeszcze potestuje ten sposób w grze.

adiblol - 26-12-2009, 14:09

Berserker napisał/a:
bez podjezdzania robotem w dane miejsce, sprawdzania kierunku i wracania

Nie wiedziałem.

Ale można tak (UWAGA teoria rodem z postów pipoka!):


(źródło: patrz URL obrazka)


(źródło: Wikipedia, "Funkcje trygonometryczne")


(źródło: własne :) )

A - działo, "dany punkt"
B - siedziba Microsoftu (cel)
C - nieistotne

alfa - trza obliczyć
beta - orientacja działa
gamma - potrzebny obrót

Musimy obliczyć alfę:
z tabelki bierzemy a/b albo b/a, ja wybrałem a/b czyli tan alfa (w programowaniu jest tan, w matematyce tg).
Kod:

tan(alfa) = c/b
alfa = ?

i wychodzi nam
Kod:
alfa = atan(a/b);

dzięki arcusom (newbies odsyłam na Wikipedię)

Dalej już prosto :)
Aby obliczyć obrót (gammę) trzeba od orientacji (bety) odjąć alfę.

Cały algorytm:
(kod jest trochę bardziej skomplikowany bo trzeba liczyć a i b)
Kod:

object ms = radar(Microsoft);
point siedziba_microsoftu = ms.position;
object shooter = radar(WingedShooter);
point dzialo = shooter.position;

float beta = shooter.orientation;
float a = siedziba_microsoftu.y - dzialo.y;
float b = siedziba_microsoftu.x - dzialo.x;
float alfa = atan(a/b);
float gamma = beta - alfa;



UWAGA mogłem się pomylić ze znakiem funkcji turn() bo dawno nie grałem, jak coś źle działa to zamiast gamma=beta-alfa dajcie gamma=alfa-beta, będzie to odpowiadało zmianie znaku ;)

NIE TESTOWANE (nie mam Colobota)

Berserker - 26-12-2009, 20:36

@up
Dziala z pewnymi poprawkami.

@topic
Narazie usiluje napisac tak funkcje Goto(), zeby mogla przejsc cwiczenia "Stacje przekaznikowe" 1 i 2. Aktualnie robot pakuje sie centralnie w mine i probuje sprawic, by ja omijal. Jak ktos chce sie pobawic:
Kod:
int object::Goto(point pos)
{
    ipf(1000);
    point center, dest[]; //punkty sciezki
    point F, R, L, adest; //punkty docelowe
    int list[], i;
    float len; //odleglosc do nastepnego punktu
    float lenstart;
    float dir;
    float orient;
    center = position;
    lenstart = 0.5; //odleglosc domyslna miedzy kolejnymi punktami
    do
    {
        len = lenstart;
        orient = getOrient(center, pos); //kierunek pozycji docelowej
        F = getPos(center, orient, len); //oblicz pozycje w kierunku pozycji docelowej
        if(OK(center, F) == true) //sprawdz, czy osiagniecie jej jest mozliwe
        {
            adest = F;
        }
        else
        {
            i = 0;
            do
            {
                i++;
                L = getPos(center, orient+i*5, len); //oblicz pozycje skierowana o 5dgr na lewo
                R = getPos(center, orient-i*5, len); //oblicz pozycje skierowana o 5dgr na prawo
                if(i >= 180/5) // jesli program zatoczy kolo
                {
                    i = 0; //ustal mnoznik stopni na 0
                    len += 0.5; //zwieksz odleglosc do kolejnego punktu o 0.5m
                }
            }
            while(OK(center, L) != true and OK(center, R) != true);
            if(topo(L) < topo(R)) adest = L;
            else adest = R;
           
        }
        center = adest;
        dest[sizeof(dest)] = adest; //dodaj nowy punkt do sciezki
        if(sizeof(dest) > 9999) //jesli ilosc punktow w sciezce jest za duza
        {
            return 1; //przerwij
        }
       
    }
    while(distance2d(center, pos) > 2);
    dest[sizeof(dest)] = pos; //dodaj punkt o wspolrzednych punktu docelowego
    i = 0;
    while(distance2d(pos, position) > 1 and i < sizeof(dest))
    {
        adest = dest[i++]; //uzyskaj kolejny punkt sciezki
        while(distance2d(position, adest) > 0.2) //i dojedz do niego
        {
            dir = direction(adest);
            len = distance(position, pos);
            len = len/5;
            if(len > 1) len = 1;
            //motor(1-dir/90, 1+dir/90);
            turn(dir);
            motor(len, len);
        }
    }
    motor(0, 0);
    return 0;
}
bool object::OK(point center, point dest) //sprawdzanie czy punkt jest osiagalny
{
    int list[];
    float radius[];
    object p;
    list[Mine] = Mine;
    radius[Mine] = 2.5;
    p = search(Mine, dest);
    if(p != null)
    {
        if(distance(p.position, dest) < radius[p.category]) return false;
    }
    return true;
}
point getPos(point center, float orient, float lenght) //otrzymaj punkt w danym kierunku
{
    point dest;
    dest.x = center.x+cos(orient)*lenght;
    dest.y = center.y+sin(orient)*lenght;
    dest.z = topo(dest);
    return dest;
}
float getOrient(point center, point dest) //uzyskaj kierunek
{
    float x, y;
    float angle;
    y = dest.y-center.y;
    x = dest.x-center.x;
    if(x == 0)
    {
        if(y > 0)
        {
            angle = 90;
        }
        else
        {
            angle = 270;
        }
    }
    else
    {
        angle = atan(y/x);
        if(x < 0)
        {
            angle += 180;
        }
    }
    return angle;
}

sajmon313 - 27-12-2009, 21:09

@up
Może dopisz komentarze w kodzie, coby był bardziej czytelny?
Chociaz ogólnikowo, do czego funkcja, do czego zmienna (przy jej deklaracji), itp.

Berserker - 27-12-2009, 21:45

@up
Edytowalem poprzedni post, dodalem tez troche zmian, teraz robot zgrabnie omija miny i ladnie laduje w docelowym punkcie :)

sajmon313 - 28-12-2009, 10:35

teraz dobrze.

Ale w funkcji OK, dlaczego sprawdzasz tylko miny? A jeżeli będzie tam stała fabryka robotów? Albo królowa obcych?

Tylko dla miny znamy radius, dla innych obiektów trzeba będzie wyznaczyć eksperymentalnie.

i w ostatniej linii tej funkcji ja bym (tak dla pewności) dał:
Kod:
else return true;

Berserker - 28-12-2009, 13:04

Cytat:
Ale w funkcji OK, dlaczego sprawdzasz tylko miny? A jeżeli będzie tam stała fabryka robotów? Albo królowa obcych?

Efekt tego, ze instrukcja search() nie wykrywa kategorii umieszczonych w tablicy jak radar(), trzeba napisac osobna funkcje.

Cytat:
Tylko dla miny znamy radius, dla innych obiektów trzeba będzie wyznaczyć eksperymentalnie.

Dla budynkow mozna wykorzystac powierzchnie potrzebna do budowy.
Cytat:
i w ostatniej linii tej funkcji ja bym (tak dla pewności) dał: Kod:
else return true;

Ja nie dam, na to samo wychodzi a pozniej bedzie jeszcze mnostwo warunkow.

adiblol - 29-12-2009, 17:07

Nie trzeba sprawdzić eksperymentalnie, jest taki fajny plik na stronie Epsiteca... http://www.epsitec.ch/colobot/program/prog058.txt
gg - 25-02-2010, 21:59
Temat postu: a
a moze po kazdym "cyklu" znajdowania takiego punktu zrobic :

turn(direction(//nasz ce//.position));

a czy ktos wie jak napisac i odczytac wielolinijkowy plik by np. robic listy a'la tablice ?


Powered by phpBB modified by Przemo & WRIM © 2003 phpBB Group