Robocode Processing Loop
The order that Robocode runs is as follows:
- All robots execute their code until taking action
- Time is updated (currentTime++)
- All bullets move and check for collisions
- All robots move (heading, accel, velocity, distance, in that order)
- All robots perform scans (and collect team messages)
- The battlefield draws
- Where do the events get processed? -- filmil
- When does firing occur?
- On the next tick. The difference between fire() and setFire() is that fire() also runs the next tick. However, it is fired from your current location.
- Just to check, this would be the order of events (each bullet is a different tick, events ordered through tick)
- Enemy Fires a power 3
- Bullet moves 11, I see change, I move, I call setFire 3
- Bullet moves to 22, I move, My bullet moves to 11 from my current position
- or is the bullet fired from the position I move to the tick I called setFire?
- Here's how I believe it works:
- Enemy Fires a power 3
- Bullet is still at the location the enemy was last turn, you see the change, move, call setFire(3)
- Bullet moves to 11, you move, your bullet is now fired at your old location.
- Enemy bullet has moved 22, your bullet moved 11.
- This part was confusing to me for a while so here goes my shot at explaining it: -- Martin Alan Pedersen
- In this example, I am breaking down turns into server side (-) and client side (+). The server side turn occurs first, with bullet and bot movement calculated. The results perceived in the client turn have the same turn number, but all of your instructions are going to be processed in the next turn's server side portion. Though I think of it as client/server, really the 'client' is your bot's run() processing loop.
- Turn 30+: you tell your bot to move somewhere and also to fire.
- Turn 31-: your bullet fires and travels from the center of your bot outward one unit of velocity (e.g. 11.0 for a power 3.0 shot). If your enemy is in the path of the line segment (highly unlikely in the first tick) it is hit. After all bullets fire / move, all bots are moved. Events are sent to bots as things happen during this 'server side' processing.
- Turn 31+: Control is returned to your bot's run() processing loop. Your getXX() methods are populated with your present demographics. (Position, etc may be updated earlier and visible while processing an OnHitWall? / Robot event, for example .. not really sure.)
- You cannot send team messages back and forth in the same tick; that is, if Bot 1 sends a message to Bot 2, and Bot 2 responds to Bot 1, the response won't come until the next tick.
- It seems that team messages won't be send until the robot calls execute() and hence won't be received until the end of the turn. I have two robots sharing enemy data and it goes like this:Gir
- Server Side (getTime() == n): Robot A & Robot B scan Enemy 1 at getTime() == n. Robot B sends a team message to Robot A with the data for Enemy 1 at tick n.
- Robots Side (getTime() == n): Robot A has only his own scan informations for Enemy 1 at tick n.
- Server Side (getTime() == n + 1): Robot A receives the team message from Robot B with the data for Enemy 1 at tick n.
- I'm not sure - the message might be received on the same turn. However, it is definitely the case that you cannot respond to the message and have that received the same turn. It is probably like onMessageReceived? is triggered "simultaneously" in each tank each tick, so you can't really send messages back and forth in the same tick. You could easily test it, though, by sending the time (getTime()) to your teammate, and in onMessageReceived?, print the real time and the time that the message contains. -- Voidious
- Well that's what I did, so it really seems to be this way... too bad.Gir
- I think the easiest way to answer the "When do bullets fire?" question would be to add "Bullet's fired this turn appear at firing robot's position" in between "All bullets move and check for collisions" and "All robots move (heading, accel, velocity, distance, in that order)" in the order of actions listed above. While I am at it, I have a question myself. When robocode is calculating collisions, it pretends that all robot's are facing directly north/east/south/west, right? So rotating to face a bullet that is coming at you would not help at all? -- Avi?
- I thought about it some more and I think my suggestion is wrong. Really, the action "all bullets appear" happens at some point between heading and distance. If it happened before heading then the bullet object would not have the correct direction. So my new suggestion is that right after "...heading, " and right before "accel" you put "bullets appear" -- Avi?
- nope, a robot is represented as a non-rotating square of 36x36, if the 'line' of the bullet (8 pixels long) intersects with this square, it is a hit. -- GrubbmGait
- what? 'line' of the bullet? I thought bullets were pixels. Can somebody explain to me how bullets colliding with other bullets works in light of this new information? --Avi?
- a pixel is shown as a dot, but internally handled as a 8-pixel long line. Bullets collide with each other when their lines do intersect. I could not find the info on the BeginnersFAQ, but I know it is around somewhere. --GrubbmGait
Time and distance measurements in Robocode
Time (t) Robocode time is measured in "ticks", which are equivalent to frames displayed on the screen. Each robot gets one turn per tick. 1 tick = 1 turn = 1 frame.
- How much in fact is the robot allowed to think? A "Tick" does not correspond to real time, but there exists a realtime limit on how long one can 'contemplate'. What is this limit, and does it depend upon the system the Robocode simulator is running on? -- filmil
- The Robocode environment tries to measure the performance of the system when it is started. This in order to make it not dependent on this. How much you are allowed to think I don't know really. It's seldom a problem anyway. You'll tire of the bot being a really SlowBot before reaching this limit I think... -- PEZ
- Ok, I just tested this, and if it takes more than 5 seconds in a tick Robocode determines not to calculate score for the bot, and after 10 seconds the bot is stopped and is no longer processed. When it comes to skipped turns however, I am a bit confused. A bot in an infinite loop will not recieve skipped turn events, but other robots in the battle will still execute (although at a slower framerate) this leads me to believe that robocode does not run battles strictly sequentially. It appears that ticks still continue while the bot loops (a getTime within the loop shows anywhere from 7 to 20 ticks a second on my comp)for the first 5 seconds, and then for another 5 seconds Robocode solely runs that robot (no ticks pass) until it is disabled. -- Jokester
- IIRC your robot is warped to the next tick. Your robot continues running where it was, as if it is still in the previous tick (besides getting new data from getX() etc). You only receive events when you move to the next tick normally. -- Jonathan
Distance Measurement Robocode's units are basically measured in pixels, with two exceptions. First, all distances are measured with double precision, so you can actually move a fraction of a pixel. Second, Robocode automatically scales down battles to fit on the screen. In this case, the unit of distance is actually smaller than a pixel.
- With all due respect, equating pixels with robocode units is simply an error. Robocode units (runits) do not correspond to pixels since display can be scaled. As it is now, the explanation says: the units are pixels, except sometimes when they are not. It does not seem to clarify too much. Thanks for your patience in reading this. :) -- filmil
- It doesn't really matter. It's like with time ticks. Just units. -- PEZ
- That's why I said the above: introducing pixels serves no purpose. But I guess if it has become a custom, let they be pixels... -- filmil
- It does serve a purpose, though. The distance will always be in pixels unless the user makes the window too small to display the battlefield, in which case Robocode will scale the whole battlefield down. But it certainly is pixels by default, and will never be any larger than pixels. -- Kawigi
- This is just like scaling down a large image to fit an average screen. It is still, say, 2048 pixels wide, even though it is 1024 on that screen. -- Jonathan
Robot Movement Physics
Acceleration (a) Robots accelerate at the rate of 1 pixel/tick. Robots decelerate at the rate of 2 pixels/tick. Robocode determines acceleration for you, based on the distance you are trying to move.
- Note that this is different than real, 'live' tanks, i.e. with motors, where you can set the speed, and acceleration is of course dependent on the horsepower count of the motor. This difference also gets the system control people a surprise. -- filmil
- How different is this, aside from the fact that we can assume constant acceleration / deceleration? -- Kawigi
- Acceleration and deceleration does happen with full numbers, except for the last one reaching 0 or the intended speed. That last tick just fills the remaining part. Spinbot for example accelerates from 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 5.5 and if it would decelerate, it would go 5.5 -> 3.5 -> 1.5 -> 0 -- GrubbmGait
- Deceleration can also be greater than 2, which occurs during collisions.
- Even if you decelerate past 0 your max speed difference is 2. This means that if your speed is -0.5 it is possible to have 1.5 in the next tick, and vice versa.
- There are a few exceptions to these basic ideas, which most bots will either never run into or not care about. However, for those using GoTo? (can someone find a page describing goto & make that a link, then delete this request?) style movement and PrecisePrediction, you need to read about GamePhysics/BotSpeed. -- Simonton
Velocity Equation(v) v = at. Absolute velocity can never exceed 8. Note that technically, velocity is a vector, but in Robocode we simply assume the direction of the vector to be the robot's heading.
Distance Equation (d) d = vt.
Robot, Gun, and Radar rotation
- Max rate of rotation of robot (10 - .75 * abs(velocity)) degrees / tick. The faster you're moving, the slower you turn.
- (pi/18) - (pi/240) * abs(speed) radians/tick
- Max rate of rotation of gun 20 degrees / tick. This is added to the current rate of rotation of the robot.
- Max rate of rotation of radar 45 degrees / tick. This is added to the current rate of rotation of the gun.
- Damage = 4 * firepower. If firepower > 1, it does an additional 2 * (power - 1).
- Velocity 20 - 3 * firepower;
- GunHeat generated 1 + firepower / 5. You cannot fire if gunHeat > 0. All guns are hot at the start of each round.
- How hot do the guns start?
- 3.0 IIRC
- Power returned on hit 3 * firepower.
In short: when two robots collide, each takes .6 damage. If either of them is moving toward the collision, it will be stopped and awarded ram damage for scoring. If they are both moving toward each other, they will both take 1.2 damage and both be awarded .6 for scoring.
In detail: a robot is moving "toward" the collision if its velocity is non-zero and less than 90 degrees away from the enemy. Each bot takes turns (in a random order each tick) deciding if it collided with another, by determining if its bounding box intersects that of another on the field (after they have all moved for that tick). When an intersection is found, and the bot is at fault, it gets moved back to its original position. Therefore, it is possible that even if the second bot moved toward the collision it will not detect it because the bounding boxes no longer intersect, and therefore not be awarded the ram damage for scoring.
AdvancedRobots? take Math.abs(velocity) * .5 - 1 damage (but never < 0)
Bullets Hitting Robots
Robots are 36x36 squares centered on the (x,y) coordinate. Even when you have rotated, you collide with walls and robots and are hit by bullets based on 18 pixels in all four directions. Bullet collisions are based on whether the line between the bullet's last position and its new position intersect that square.
Note: If you are using virtual bullets and taking a short cut of estimating a hit based on a bullet passing within 18 pixels distance (as though the Tank were a circle) you are losing a significant amount of area. A robot has an area of 1296 pixels (square) as opposed to a circle of 18 radius having an area of 1018, or about 79%. -- Martin Alan Pedersen
I think a quick way to get around this would be to model your virtual bullets as Point2D objects and the other bot as a 36x36 Rectangle2D. Then you can just use the Rectangle2D.contains(Point2D) method to check for hits. I used this method in Stampede, which feeds its gun data with VBs.--wcsv
I don't check for collisions with a bot, I just mark down the angle the gun shot at on the virtual bullet (actually, I use a factor index, but it works the same); when the virtual bullet / wave passes the bot, I find the min and max angles that would have hit the bot, and check if the angle was between those. It seems quite a bit less CPU intensive to do it this way, and it fits well into my wave-based targeting systems... (I highly doubt I'm the first to do it this way.) -- Voidious
That is indeed what I do with waves in PowerHouse, but using VBs that way is essentially the same as using waves; at least the way I understand it. --wcsv
Theres alot of good stuff on the [Robocode FAQ] with regards to physics. I will try to include this stuff and rework the page if I have time -- Jokester
Does anyone know if there is a size limit fo team message, because my bot throws exception when I try to broadcast my hashmap containing all the scan stores of the last survivor at the begining of the next round. Note that all the objects contained in the hash map are serializable. -- Florent
- I don't know of any size limit, but that doesn't mean there isn't one... Have you tried sending a very small hashmap to see if the same thing happens? I don't know much about Serializable objects, but is it possible it is still referencing Bot A's objects in the hashmap it sends to Bot B? -- Voidious
- Florent, i use a different approach so i don't need messages to synchronise the data. I made the hashmap a static so that all instances (in a team) of Freya read from and update the same hashmap. I haven't checked if this really works though... --Loki
I will try those ideas, but I have some doubts regarding Loki's one. -- Florent
- well, i was inspired by this text from my Java textbook: "Variables and methods marked static belong to the class, rather than to any particular instance. In fact, you can use a static method or variable without having any instances of that class at all. You need only have the class available to be able to invoke a static method or access a static variable. Static variables, too, can be accessed without having an instance of a class. But if there are instances, a static variable of a class will be shared by all instances of that class; there is only one copy."
Why do you doubt that it works? --Loki
I remember reading that Robocode loads each bot with a separate classloader. This elimates the possibility of reading into another bot's statics and allows bots of the same class to compete in the same battle without static variable conflicts. (It also takes away your ability to share statics.) So, you are correct about Java statics but Robocode hijacks their behavior for its own purposes. --Corbos
I found this info on JavaAPI as well.
I'm working on team play right now... look for it soon. Messages will be
through serializable objects.
A static class works fine? This is a bug, if that's the case.
Each robot is loaded in a separate classloader to prevent this.
ok, thanks for the info. So there is room for a little improvement. --Loki
I think there is a size limit, after a few experiment here is what I get when I transfer the gun date at the begining of round 2.
java.io.IOException: Buffer is full.
at java.io.OutputStream.write(Unknown Source)
at java.io.ObjectOutputStream$BlockDataOutputStream.write(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
After looking at code on sourceforge, I found that the limit is 32768 bytes and it is set in
A quick question: From the list at the top of this page, it looks like a bot's max turn rate is computed using the previous tick's velocity. Is that right? (this is probably really obvious, so I apologize in advance) --wcsv
You are correct. Your turn rate is based on your velocity before acceleration / deceleration. The distance you travel is based on your adjusted velocity though. -- Martin
I think I've found a way to (sort of) exploit the movement system. A robot's acceleration is one, but its deceleration is 2. This means going from velocity 2 to 0.1 to -1.9 is faster than going 2 to 0 to -1. I don't know of any robots that do this, but it could be useful trick for moving a little faster. Does this work? -- Kev
Probably - I know a tank can vibrate between 1 and -1 velocities. Not sure it's worth the trouble of implementing it, but a neat idea for sure :) -- Voidious
You could probably use it to throw off people using guess factors. You'd be able to squeeze 7-8 additional units of distance if you went from -2 to -0.00001 to 1.99999 rather than -2 to 0 to 1. The additional nearly 1 unit of velocity would give you that edge. If someone were limiting their guess factors to aim for your rear corner rather than your center they be hard pressed to hit you, and you might even make them throw an exception. Still, that's a very small set of bots (if any at all). -- Martin
- Indeed, the great majority of of GF guns use an imprecise GF 1/-1, Math.asin(8/bulletVelocity), but Dookious certainly tries to calculate an "exact" GF -1, which doesn't use this trick. However, he also records up to GF +/-1.1, so I think he'd still be able to hit ya. -- Voidious
FYI your suspicions were correct, that does indeed work. I tried it. A small trick to increase escape angles. Nice thought, Kev! -- Simonton
Thanks! Although it might be a lot of work to implement (in WaveSurfing at least), every little improvement counts. -- Kev
One thing I thought worth noting is that onHitByBullet? events are not sent immediately upon being hit by a bullet. They are sent after all of your instructions have been processed (e.g. movement, turret rotation). They are also sent before onScannedRobot events. The significance of this is that calls to this.getX(), for example, don't reflect the robot's position at the time of being hit, even though you are calling it while processing an onHitByBulletEvent?. It is your bots position after being hit and then moving. In the event that the bullet killed you and you can't move, I think that rather than getting an onHitByBullet? event you are instead given an onDeath event. In the event that your energy is <= 0.0, you can't move anyway so the observation is moot. -- Martin
- The onHitByBullet? event is not triggered after onDeath, but it is queued up, and you can handle it yourself. David Alves posted some info about it on the onDeath page a few weeks ago. -- Voidious
About the Collisions part from above - if you are moving away from the collision, it will not be stopped - what exactly does that mean? Does it mean when you hit a robot and you try to move away, you can't? --Starrynte
I think it refers to another robot rear-ending you - in that case, you shouldn't abruptly stop (they will, though). -- Kawigi
A question: Sometimes when ramfire hits my bot, my bot is "stuck" to ramfire and can't move away. Sometimes it can move away, though. Does it have to do with e.isMyFault?()? --Starrynte
[v1.5.4] I was under the impression that you were not allowed to fire bullets with less than 0.1 energy, but in testing just now one of my bots fired a shot in round 735 with a power of 0.06049954275264291. That is the power returned by the event's bullet.getPower() method, reported from both the BulletHit? and HitByBullet? events, from their respective perspectives. I speculate that the shot was fired immediately after being hit by a bullet, and the host didn't bother to check the firepower constraints. Alternatively, it may be that a robot can fire it's last energy regardless of the 0.1 constraint. -- Martin
Yes, I think the only time a robot can fire less than 0.1 power bullets is when firing the bullet disables the bot. I've tried specifying less than 0.1 and it didn't work =) -- Skilgannon