Difference between revisions of "FuturePosition"

From Robowiki
Jump to navigation Jump to search
m (Migrating page)
 
(use <syntaxhighlight>)
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{CreditForOldWikiArticle|oldpage=FuturePostion|author=[[Albert]]}}
+
[[Wave Surfing/Precise Prediction|Precise Prediction]] code by [[User:Albert|Albert]], used by many [[Wave Surfing|Wave Surfers]].
 
 
Code is by [[Albert]].
 
  
 
The parameters are like follows:
 
The parameters are like follows:
Line 7: Line 5:
 
* b - is your robot. Just use "this".
 
* b - is your robot. Just use "this".
 
* maxVel and maxTurnRate - the maximum velocity and turn rate allowed. Use them only if you have used setMaxVelocity() or setMaxTurnRate()  
 
* maxVel and maxTurnRate - the maximum velocity and turn rate allowed. Use them only if you have used setMaxVelocity() or setMaxTurnRate()  
----
+
 
<pre>
+
<syntaxhighlight>
 
package apv;
 
package apv;
  
Line 122: Line 120:
 
 
 
}
 
}
</pre>
+
</syntaxhighlight>
----
+
<syntaxhighlight>
<pre>package apv;
+
package apv;
  
 
public class MovSimStat {
 
public class MovSimStat {
Line 141: Line 139:
 
 
 
}
 
}
</pre>
+
</syntaxhighlight>
 
 
----
 
Way cool. I have seen a discussion about this somewhere else, but no solution. Yet, could you enlighten us about when this could be useful? AntiMirrorTargeting comes to mind, is that correct? -- [[PEZ]]
 
 
 
I'm experimenting with two ideas that need it: first one is DodgingBullets (coded a prototype that makes FloodMicro to score 0.3 hits in average per round), second one is to build a SandBoxFlattener with pattern repetition avoidance. Right now, none of them works as expected :-( Anyway, I think there can be lots of uses for it, and it's this kind of basic routine that speeds up development (Robocode is much funnier if you can test your ideas without spending much time programming). Also, another use that comes to my mind is to avoid collitions between team mates in a team competition -- [[Albert]]
 
 
 
 
 
----
 
 
 
Wow. I'm impressed; this code seems to handle wall collisions and everything. Back when I had the good old SineSweep, I had a class similar to this, but it didn't do wall collisions and IIRC it didn't do acceleration properly. Nonetheless, since it rarely changed acceleration, it could predict it's future position with like 99.9999999% accuracy, and before shooting it's gun it always checked to make sure it was within a millionth of a degree of where it predicted it should be; any less accurate would risk missing the bullet interception. This plus it's mathematical algorithm for intersecting the bullet trails at their midpoints made for an extremely complicated robot framework because the gunning and movement were so integrated. I can't wait for summer so I can start rebuilding it... -- [[Vuen]]
 
 
 
I know I need to use this, but I am trying to figure where and how, it figures where I am going to be according to my set turn and ahead? -- [[AvihooI]]
 
 
 
If using a targeting method that tries to predict where the opponent will be in order to hit him with a bullet, you need to simulate their predicted movement within the constraints of the Robocode engine.  Similarly if you are trying to predict where your movement will take you so that you don't run into walls, robots, or anticipated bullet trajectories, you will need the same tool.  I don't use this code, but I made my own version, and I use it for the prediction I described. -- Martin
 
 
 
Yep, what he said. I only use it for WaveSurfing, predicting several movement options and finding exactly where I'd be when the bullet hits me (if it would hit me). The simple way to use it is, like you said, to use setAhead, setBack, and/or setTurnXXX, and then call _instanceOfMoveSim.futurePos(steps, _robot); that returns an array of MovSimStat objects, indexed zero (next tick) to steps-1 (steps ticks in future). Here's a pretty simple code snippet that is a good example:
 
<pre>
 
    public static double nextY(AdvancedRobot robot) {
 
        if (moveSimulator == null) {
 
            moveSimulator = new MovSim();
 
        }
 
 
 
        MovSimStat[] next = moveSimulator.futurePos(1, robot);
 
 
 
        return next[0].y;
 
    }
 
</pre>
 
When you do setXXX a second time, it overwrites whatever you did the first time. I also made that last method "public", and interact with it directly, because there are certain things I recalculate each tick (like WallSmoothing and distancing). Beware that the heading and turn rate (w) are in radians. -- [[Voidious]]
 
 
 
Ok, it seems that this allows me to create some sort of continuous movement by checking where I am going to be, and adjust my movement if I don't like it.
 
Now that I think about it, it's much more logical this way because I can't be mistaken about my movement, I'd just keep checking it until I am satisfied, ohh and just for the record, I prefer to use Radians in any case. -- [[AvihooI]]
 
 
 
Really, really handy.  Thanks for putting in all the extra work so the rest of us don't have to.  For the record, I hate java coding standards.  Line breaks and aligned parenthesis make everything so much easier to read.  What's with the fear of whitespace these days?  Oh well, I guess that's just me.  Again, very nice work. --[[Speal]]
 
 
 
Nice code, I just ran a test of it on a surfer I have in the works (not seraphim who is still running a badly written version of my own(which may explain its ranking)), but i'm sure I got something wrong. I'm attempting to use it on a go-To surfer type deal, so I am directly calling the last method. I have a question, for the distanceRemaining, what would be the value to put there? I am currently using 100. Also how do you get it to correctly map a oribit, I use the angleToEnemy+Math.PI/2 and angleToEnemy-Math.PI/2 for both the heading and angleToTurn (I tried others but it didn't work as well as this has so far) for each direction. --[[Chase-san]]
 
 
 
Well, one thing noteworthy about this code is that you can just pass it an AdvancedRobot and have it predict the position based on the commands currently given to the robot with the setXXX methods. The "distance remaining" would be the distance the robot still has to travel until it has completed its movements and comes to a stop; it should be negative if you're moving backwards and positive if you're not. The heading is your current heading, and the "amount to turn" would be (angle you want to move at - your current heading), all in radians. In the current [[Dookious]], you could look at my usage in <nowiki>/voidious/utils/DUtils.java</nowiki>, it should be relatively clear and is definitely correct. -- [[Voidious]]
 
 
 
Yah, I noticed when I got home that I had that exact file up, I was searching through your code looking for how dookious used MovSim, I had to break off my saerch for it early for class. However, I wanted to know the best distanceREmaining for prediction multiple turns into the future, as so I can get the positions leading up to when the closest wave would hit. --[[Chase-san]]
 
 
 
I just use 1000 or -1000, it would tick 125+ ticks to go that far and it doesn't matter how big it is. -- [[Voidious]]
 
 
 
Well, I made a version of this that has built in smoothing (via Voidious' method), however it seems to not work for the left side(which may be due to shortcuts I took in simplifing the method, but I doupt this). But at any rate, now I need to tell the bot how to orbit with a combination of TurnAngle and the maxTurnAngle. --[[Chase-san]]
 
  
[[Category:Discussions]][[Category:Code Snippets]]
+
[[Category:Source Code]]

Latest revision as of 07:03, 1 July 2010

Precise Prediction code by Albert, used by many Wave Surfers.

The parameters are like follows:

  • steps - number of ticks you want to predict.
  • b - is your robot. Just use "this".
  • maxVel and maxTurnRate - the maximum velocity and turn rate allowed. Use them only if you have used setMaxVelocity() or setMaxTurnRate()
package apv;

import java.awt.geom.Point2D;
import java.util.Vector;
import robocode.util.*;
import robocode.*;

public class MovSim {
	
	private double systemMaxTurnRate = Math.toRadians(10.0);
	private double systemMaxVelocity = 8.0;
	private double maxBraking = 2.0;
	private double maxAcceleration = 1.0;
	
	
	public double defaultMaxTurnRate = 10.0;
	public double defaultMaxVelocity = 8.0;
	
	
	public MovSim() {};
		
	
	public MovSimStat[] futurePos(int steps, AdvancedRobot b) { return futurePos(steps, b, defaultMaxVelocity, defaultMaxTurnRate); }
		
	public MovSimStat[] futurePos(int steps, AdvancedRobot b, double maxVel, double maxTurnRate) {
		return futurePos(steps, b.getX(), b.getY(), b.getVelocity(), maxVel, b.getHeadingRadians(), b.getDistanceRemaining(), b.getTurnRemainingRadians(), maxTurnRate, b.getBattleFieldWidth(), b.getBattleFieldHeight());
	}
	
	
	private MovSimStat[] futurePos(int steps, double x, double y, double velocity, double maxVelocity, double heading, double distanceRemaining, double angleToTurn, double maxTurnRate, double battleFieldW, double battleFieldH) {
		//maxTurnRate in degrees
		MovSimStat[] pos = new MovSimStat[steps];
		double acceleration = 0;
		boolean slowingDown = false;
		double moveDirection;
	
		maxTurnRate = Math.toRadians(maxTurnRate);
		if (distanceRemaining == 0) moveDirection = 0; else if (distanceRemaining < 0.0) moveDirection = -1; else moveDirection = 1;
		
		//heading, accel, velocity, distance
		for (int i=0; i<steps; i++) {
			//heading
			double lastHeading = heading;
			double turnRate = Math.min(maxTurnRate, ((0.4 + 0.6 * (1.0 - (Math.abs(velocity) / systemMaxVelocity))) * systemMaxTurnRate));
			if (angleToTurn > 0.0) {
	    		if (angleToTurn < turnRate) { heading += angleToTurn; angleToTurn = 0.0; } 
				else { heading += turnRate; angleToTurn -= turnRate; }
			} else if (angleToTurn < 0.0) {
	    		if (angleToTurn > -turnRate) { heading += angleToTurn; angleToTurn = 0.0; } 
				else { heading -= turnRate;	angleToTurn += turnRate; }
			}
			heading = Utils.normalAbsoluteAngle(heading);
			//movement
			if (distanceRemaining != 0.0 || velocity != 0.0) { 
				//lastX = x; lastY = y;
				if (!slowingDown && moveDirection == 0) {
					slowingDown = true;
					if (velocity > 0.0) moveDirection = 1;
					else if (velocity < 0.0) moveDirection = -1;
					else moveDirection = 0;
			    }
			    double desiredDistanceRemaining = distanceRemaining;
	    		if (slowingDown) {
					if (moveDirection == 1 && distanceRemaining < 0.0) desiredDistanceRemaining = 0.0;
					else if (moveDirection == -1 && distanceRemaining > 1.0) desiredDistanceRemaining = 0.0;
			    }
	    		double slowDownVelocity	= (double) (int) (maxBraking / 2.0 * ((Math.sqrt(4.0 * Math.abs(desiredDistanceRemaining)+ 1.0)) - 1.0));
		    	if (moveDirection == -1) slowDownVelocity = -slowDownVelocity;
		    	if (!slowingDown) {
					if (moveDirection == 1) {
		    			if (velocity < 0.0) acceleration = maxBraking;
			    		else acceleration = maxAcceleration;
				    	if (velocity + acceleration > slowDownVelocity) slowingDown = true;
					} else if (moveDirection == -1) {
				    	if (velocity > 0.0) acceleration = -maxBraking;
		    			else acceleration = -maxAcceleration;
		    			if (velocity + acceleration < slowDownVelocity)	slowingDown = true;
					}
			    }
	    		if (slowingDown) {
					if (distanceRemaining != 0.0 && Math.abs(velocity) <= maxBraking && Math.abs(distanceRemaining) <= maxBraking) slowDownVelocity = distanceRemaining;
					double perfectAccel = slowDownVelocity - velocity;
					if (perfectAccel > maxBraking) perfectAccel = maxBraking;
					else if (perfectAccel < -maxBraking) perfectAccel = -maxBraking;
					acceleration = perfectAccel;
		    	}
			    if (velocity > maxVelocity || velocity < -maxVelocity) acceleration = 0.0;
		    	velocity += acceleration;
			    if (velocity > maxVelocity)	velocity -= Math.min(maxBraking, velocity - maxVelocity);
		    	if (velocity < -maxVelocity) velocity += Math.min(maxBraking, -velocity - maxVelocity);
		    	double dx = velocity * Math.sin(heading); double dy = velocity * Math.cos(heading);
			    x += dx; y += dy;
			    //boolean updateBounds = false;
	    		//if (dx != 0.0 || dy != 0.0) updateBounds = true;
			    if (slowingDown && velocity == 0.0) { distanceRemaining = 0.0; moveDirection = 0; slowingDown = false; acceleration = 0.0; }
			    //if (updateBounds) updateBoundingBox();
	    		distanceRemaining -= velocity;
				if (x<18 || y<18 || x>battleFieldW-18 || y>battleFieldH-18) {
					distanceRemaining = 0;
					angleToTurn = 0;
					velocity = 0;
					moveDirection = 0;
					x = Math.max(18,Math.min(battleFieldW-18,x));
					y = Math.max(18,Math.min(battleFieldH-18,y));
				}
			}
			//add position
			pos[i] = new MovSimStat(x,y,velocity,heading,Utils.normalRelativeAngle(heading-lastHeading));
		}
		return pos;		
	}
		
}
package apv;

public class MovSimStat {
	public double x;
	public double y;
	public double v;
	public double h;
	public double w;

	
	public MovSimStat(double x, double y, double v, double h, double w) {
		this.x = x; this.y = y; this.v = v; this.h = h; this.w = w; 
	}
	
	
	
}