Goniometrische functies in Robocode

Om in Robocode een goede robot te kunnen schrijven, krijg je vaak te maken met goniometrie. Vaak weet je bijvoorbeeld alleen de relatieve hoek en de afstand van een tegenstander, maar heb je de x- en y-coördinaten nodig (bijvoorbeeld als de positie van de tegenstander aan je teamgenoten wilt doorgeven; je teamgenoten hebben immers een andere positie dan jij en hebben dus niks aan de hoek en afstand).

Op deze pagina krijg je een korte inleiding in de goniometrie die je nodig hebt om dit soort berekeningen uit te voeren. De inhoud van deze pagina is geen tentamenstof, maar je kunt het goed gebruiken bij het programmeren van je robot.

Beantwoorde vragen:

Het slagveld

Het slagveld in Robocode is rechthoekig. Elk punt heeft een x-coördinaat (horizontaal) en een y-coördinaat. Coördinaten worden weergegeven als paren (x,y), waarvan de eerste de x- en de tweede de y-coördinaat is. Het punt (0,0) heet de oorsprong, en ligt linksonder. (3,0) ligt rechts van de oorsprong, (0,3) ligt erboven.

Hoeken

In Robocode kom je twee soorten hoeken vaak tegen:

Absolute hoeken (Heading)
Hoeken t.o.v. een vast coördinatenstelstel. Je kunt het vergelijken met noord, oost, zuid en west. Een hoek van 0 graden is in Robocode boven, een hoek van 90 graden rechts, enz. De absolute hoek waarin je robot rijdt, kan je bijvoorbeeld met de methode Robot.getHeading().
Opmerking: Op de middelbare school heb je waarschijnlijk geleerd dat een hoek van 0 graden naar rechts wijst i.p.v. naar boven. Dit heeft tot gevolg dat sinus en cosinus in Robocode anders gebruikt worden dan he misschien gewend bent.
Relatieve hoeken (Bearing)
Hoeken relatief aan de richting waarin jouw robot rijdt. Relatieve hoeken kun je vergelijken met termen als links en rechts. Als er een event plaatsvindt, kun je meestal in de event de bearing aflezen van de inslaande kogel, gescande robot, tegenaangereden muur, enz., m.b.v. de methode getBearing(). Een bearing van 0 graden is voor jouw robot, een bearing van -90 is links, een bearing van 90 is rechts, een bearing van 180 of -180 graden is achter.
Hoe kan ik een bearing (relatieve richting) naar een heading (absolute richting) omzetten?
Een relatieve richting is een hoek relatief aan de hoek waarin je robot rijdt. Je kunt dus gewoon de hoeken optellen, en zorgen dat het resultaat in het bereik 0-360 graden ligt. In Java:
public double heading(double bearing) {
  return (this.getHeading() + bearing) % 360;
}
De bovenstaande methode kan je bijvoorbeeld in je onScannedRobot event handler als volgt gebruiken om de absolute richting te vinding waarin de robot werd waargenomen:
double absAngle = heading(e.getBearing());
Hoe kan ik een heading (absolute richting) in een bearing (relatieve richting) omzetten?
Dit is het omgekeerde, dus je kan de heading van jouw robot van de gevonden relatieve hoek aftrekken, en ervoor zorgen dat het resultaat in het bereik -180-180 komt. Dat kan als volgt:
public double bearing(double heading) {
  double angle = heading - this.getHeading(); // bereken de hoek
  angle = angle % 360;                        // en normaliseer naar het bereik -180 tot 180
  if (angle > 180) angle -= 360;
  return angle;
}

Graden en radialen

Er bestaan verschillende methoden om hoeken weer te geven. In Robocode gebruiken veel functies graden. In dit systeem wordt een circel in 360 graden verdeeld. In de wiskunde is het veel gebruikelijker hoeken in radialen weer te geven. De meeste hulpmethodes uit de Java API gebruiken ook radialen, dus je moet weten hoe je graden en radialen in elkaar kunt vertalen. Dit hoef je niet met de hand te doen; je kunt er de volgende functies uit de Java API voor gebruiken: Math.toDegrees(double) en Math.toRadians(double).

Hoe kan ik radialen naar graden omzetten?
Gebruik de Math.toDegrees(double) methode.
double degrees = Math.toDegrees(radians);
Hoe kan ik graden naar radialen omzetten?
Gebruik de Math.toRadians(double) methode.
double radians = Math.toRadians(degrees);

Overigens hoef je niet deze conversies de hele tijd uit te voeren. Als je even makkelijk in radialen denkt als in graden, kan je je robot ook besturen door hoeken in radialen door te geven. Hiervoor heeft elke methode die een hoek als argument neemt ook een equivalente methode die een hoek in radialen vraagt. Dit equivalent heet hetzelfde met Radians erachter. Bijvoorbeeld turnRight(90) draait je robot 90 graden naar rechts, terwijl turnRightRadians(Math.PI) je robot 1/2π radialen naar rechts draait (beide opdrachten hebben hetzelfde effect).

Sinus en cosinus

Met sinus en cosinus kun je resp. de x- en y-coördinaat berekenen van een punt dat op afstand 1 ligt van de oorsprong. D.w.z. dat als je een punt hebt op afstand 1 met heading (absolute richting) α, sin α de x-coördinaat van dat punt geeft, en cos α de y-coördinaat. Je begrijpt dat sinus en cosinus een belangrijke rol spelen met het converteren van cartesische coördinaten (x,y) naar een paar van een afstand en hoek.

Opmerking: Op de middelbare school heb je waarschijnlijk geleerd dat sin de y-coördinaat geeft, en cos de x-coördinaat. In Robocode is dit anders, omdat de graden vanaf boven met de klok mee gaan i.p.v. vanaf rechts tegen de klok in, zoals meestal.
Ik weet de heading en de afstand van een andere robot. Hoe kan ik de coördinaten van die robot bepalen?
Je kan daarvoor de methodes Math.sin(double) en Math.cos(double) gebruiken. Beide methodes vragen de hoek in radialen.
// bepaal eerst de coordinaten relatief t.o.v. je eigen robot
double dx = Math.sin(toRadians(heading)) * distance;
double dy = Math.cos(toRadians(heading)) * distance;
// maar jij zit niet op de oorsprong! pas de resultaten dus aan
double xCoordinaat = this.getX() + dx;
double yCoordinaat = this.getY() + dy;
Merk op dat deze code een heading vraagt. Bij de meeste events kun je alleen een bearing opvragen, dus het kan zijn dat je eerst nog even een relatieve hoek naar een absolute hoek moet omzetten.
Ik weet de cartesische coördinaten van een andere robot. Hoe bepaal ik de richting naar die andere robot?
Je kan daarvoor de methode Math.atan2(double,double) gebruiken. Deze methode vraag een x- en y-coördinaat, en geeft de hoek (in radialen) terug van de oorsprong naar dit punt. Omdat de functie weer werkt vanaf de oorsprong, moet je eerst de coördinaten aan je eigen positie aanpassen.
// bereken eerst de positie t.o.v. jezelf
double dx = target.getX() - this.getX();
double dy = target.getY() - this.getX();
// gebruik de atan-methode om de hoek te bepalen
double heading = Math.toDegrees(Math.atan(dx, dy));
Ik weet de cartesische coördinaten van een andere robot. Hoe bepaal ik de afstand tussen mijn robot en de ander?
Met de stelling van Pythagoras! In Java-code:
double dx = target.getX() - this.getX();
double dy = target.getY() - this.getY();
double afstand = Math.sqrt(dx * dx + dy * dy);

Laatst gewijzigd: 23 juni 2003
H. J. Sander Bruggink