setAhead
method). It has a few caveats that are worth noting, as listed below. The code Robocode uses (as of version 1.6.1.1) is posted after the three caveats listed below.
(int) Math.sqrt(4 * distanceRemaining + 1) - 1)
, will pick the wrong value when distanceRemaining
is between [3.75, 4). It will pick 3, leaving your bot with [.75-1) pixels left to travel. The slowest it can go at that point, however, is 1, so it will necessarily overshoot your desired distance. Without intervention, robocode will just stop your bot at that overshot location.
Your bot will reach this situation when you call setAhead([3.75, 4))
explicitly, or when Robocode slows your bot down to it. Those cases are for [7.75, 8), [8.75, 9), [13.75, 14) plus any distance a multiple of 8, and [14.75, 15) plus any distance a multiple of 8. The same holds for the negative direction.
For example, if your bot's speed is 8 and you call setAhead(22.8)
, it's speed / distanceRemaining per tick after that will be:
Your bot will reach this situation when its speed is greater than 2 and you call setAhead((1, 2)) yourself, or when Robocode slows your bot down to it. Those cases are for (4, 5), (8, 8.75), and (14, 14.75) plus multiples of 8. The same holds for the negative direction.
For example, if your bot's speed is 8 and you call setAhead(22.5)
, it's speed / distanceRemaining per tick after that will be:
For example, if your bot's speed is 8 and you call setAhead(-200)
your bot would normally travel at speed 6 next tick. However, if you also call setMaxVelocity(7)
, you will instead travel at speed 7 next tick.
private void updateMovement() {
if (distanceRemaining == 0 && velocity == 0) {
return;
}
lastX = x;
lastY = y;
if (!slowingDown) {
// Set moveDir and slow down for move(0)
if (moveDirection == 0) {
// On move(0), we're always slowing down.
slowingDown = true;
// Pretend we were moving in the direction we're heading,
if (velocity > 0) {
moveDirection = 1;
} else if (velocity < 0) {
moveDirection = -1;
} else {
moveDirection = 0;
}
}
}
double desiredDistanceRemaining = distanceRemaining;
if (slowingDown) {
if (moveDirection == 1 && distanceRemaining < 0) {
desiredDistanceRemaining = 0;
} else if (moveDirection == -1 && distanceRemaining > 0) {
desiredDistanceRemaining = 0;
}
}
double slowDownVelocity = (int) ((sqrt(4 * abs(desiredDistanceRemaining) + 1) - 1));
if (moveDirection == -1) {
slowDownVelocity = -slowDownVelocity;
}
if (!slowingDown) {
// Calculate acceleration
if (moveDirection == 1) {
// Brake or accelerate
if (velocity < 0) {
acceleration = Rules.DECELERATION;
} else {
acceleration = Rules.ACCELERATION;
}
if (velocity + acceleration > slowDownVelocity) {
slowingDown = true;
}
} else if (moveDirection == -1) {
if (velocity > 0) {
acceleration = -Rules.DECELERATION;
} else {
acceleration = -Rules.ACCELERATION;
}
if (velocity + acceleration < slowDownVelocity) {
slowingDown = true;
}
}
}
if (slowingDown) {
// note: if slowing down, velocity and distanceremaining have same sign
if (distanceRemaining != 0 && abs(velocity) <= Rules.DECELERATION
&& abs(distanceRemaining) <= Rules.DECELERATION) {
slowDownVelocity = distanceRemaining;
}
double perfectAccel = slowDownVelocity - velocity;
if (perfectAccel > Rules.DECELERATION) {
perfectAccel = Rules.DECELERATION;
} else if (perfectAccel < -Rules.DECELERATION) {
perfectAccel = -Rules.DECELERATION;
}
acceleration = perfectAccel;
}
// Calculate velocity
if (velocity > maxVelocity || velocity < -maxVelocity) {
acceleration = 0;
}
velocity += acceleration;
if (velocity > maxVelocity) {
velocity -= min(Rules.DECELERATION, velocity - maxVelocity);
}
if (velocity < -maxVelocity) {
velocity += min(Rules.DECELERATION, -velocity - maxVelocity);
}
double dx = velocity * sin(heading);
double dy = velocity * cos(heading);
x += dx;
y += dy;
boolean updateBounds = false;
if (dx != 0 || dy != 0) {
updateBounds = true;
}
if (slowingDown && velocity == 0) {
distanceRemaining = 0;
moveDirection = 0;
slowingDown = false;
acceleration = 0;
}
if (updateBounds) {
updateBoundingBox();
}
distanceRemaining -= velocity;
}
I have overcome all but a few cases of these sub-optimal behaviors, but it has been a real pain to discover them and make workarounds. Can I open up a discussion about getting them changed in Robocode's game engine, or is that just too radical of an idea? I don't know if there are any bots that rely on these quirks, but if not, it may be worthwhile to save future robocoders the pain I have gone through. -- Simonton
This is nice, just the kind of optimal movement im looking for in yoda. Mined if i use it, to your credit of course Simonton -- Gorded
I'll chime in with my opinion on this: I have no issue with fixing these things. I doubt there will be a large impact in practice, but where there is an impact I would expect a positive impact because to my knowledge everyone had assumed things worked 'intuitively', because I've never heard anyone else bring up this issue. -- Rednaxela
Any change in the "physics" code will impact negatively bots that use precise prediction and/or are tweaked to preform best in a world with these quirks. Future robocoders would of course welcome these changes, but I think it is a bit of a radical change. -- ABC
Well, do you know of any bots that do consider these unusual quirks in precise prediction? I don't know of any, and if there indeed aren't any, resolving these quirks wouldn't negatively impact them. As far as bots that are just manually tweaked, I really don't think these quirks are big enough to really change the balance measurably. In Simonton's bug report for this however, Fnl did say he'd make a prototype with these tweaks resolved. I believe it would be worthwhile to test a fair number of pairings with that, with focus on precise predictors like most surfers, and on some highly tweaked bots like Raiko. I do strongly suspect there will be no measurable impact on existing bots, but it testing of course would be important. -- Rednaxela
Lots of surfers use a copy the internal robocode code to simulate future positions, if you change that code those bots will lose precision. That loss will be measurable, imo. -- ABC
I haven't looked over this particular issue in-depth enough to say if I think it will affect bots' predictions, but I'm definitely against changing anything in the current Robocode physics engine. We've already changed a lot, and more than I probably would have, with fixing tweaks on bullet collisions and adding new API calls (which greatly affects competitiveness of legacy CodeSize-restricted bots). I don't mean to sound negative, that's just how I feel about it. My take on it is that I think this kind of enhancement should be poured into Robocode 2. -- Voidious
I understand that game physics are a sacred thing. Like Voidious, I would not have supported a change in the bullet collision code if asked, and we saw it made a very large difference in the scores of bots that used the extra information gained by them vs. those that did not. However, in this case I would support the change, since I believe it's the way the physics engine was probably intended (or if not, should have been), I doubt it would make much difference to legacy bots, and the benefits of intuitive-izing the physics for future robocoders could be substantial. (Now that our 1v1 king is a goto surfer, I expect more coders to take up that style.) As for those space-saving API methods ... are any of those new in the last year? Because if so I'll be taking advantage of them! :) -- Simonton
I would think that, if we are building a new set of rumble stats, it would be interesting to compare a version with a 'fixed' physics engine and the regular engine. Perhaps just do a test with a relatively small number of bots, but be sure to include several of each type of surfing. The thing is, all WaveSurfing bots were designed with the physics *as we intend to change them to* in mind, *not as they actually are*. For most TrueSurfers? it won't make any difference, because they all call setAhead(Infinity). It's when you are trying to accurately predict deceleration of setAhead(<20) that things start getting fuzzy. AFAIK no bots implement any way to get around the caveats listed above, instead assuming that the engine will make the smartest choice for them. Unfortunately this is not true. OTOH Simonton, if you've figured out a 'smart goto' method that fools the bot engine into doing the right thing, I'd be very grateful if you shared it =) -- Skilgannon