I released it as "the first nanobot with a pattern matcher". It is not completely true (Cyclops uses also a pattern matcher and it is older than NanoLauLectrik) but there are not many of them. In any case, it was the first real killer pattern matcher, and leaded the way for a new generation of nano bots.
It is designed for 1vs1 only, and features a nanonized pattern matcher.
NanoLauLectrik got a clear win in the Minibot Challenge (Feb 16) !!!
NanoLauLectrik 0.9 released! Features an state-of-the-art variable-pattern-size nanonized pattern matcher.
NanoLauLectrik 1.0 released! With improved movement. Source code available.
NanoLauLectrik 1.0 goes up +35 positions in the Eternal Rumble and becomes the #1 nanobot (Apr 26) !!! It also scores the best score ever for a nanobot and enters the Hall of Fame !!!
NanoLauLectrik 1.0 wins the Rookie 1v1 league in the Robocode Outpost.
Old as it is (I have not updated it since Apr 2003) it won the RobocodeLittleLeague (nanobots) -- 21/9/2003.
It's nice to see that the new entrants to Nanos competition at RR@H helped NanoLauLectrik and now it is second. With all my bots without serious updates because lack of time, this is the only one that stands and even goes up. (26/3/2004). -- Albert
Won the RobocodeLittleLeague (Nanos 1v1) on 2004-04-24, 2004-06-26, 2004-07-03 and 2005-08-13.
-- Albert
NanoLauLectrik is just a gun. For movement, it uses a very simple Oscillator?. Starting from version 1.0, it features a complex Oscillator?.
It uses a nanonized symbolic PatternMatcher.
Now that it won the Minibot Challenge, here it goes the code for the nanonized symbolic pattern matcher (for version 0.8):
//This is the information you keep for the pattern matcher static int n; static double ev[] = new double[50000]; static StringBuffer pattern = new StringBuffer(); //This code goes into the ScannedBot event //ev contains the accumulated perpendicular velocity of the enemy //pattern contains the velocity of the enemy //the pattern matcher calculates the best gun bearing to fire based on target previous movements double targetBearing; setTurnRadarRightRadians(Math.sin((targetBearing = e.getBearingRadians() + getHeadingRadians()) - getRadarHeadingRadians())); ev[++n] = ev[n - 1] + e.getVelocity() * Math.sin(e.getHeadingRadians() - targetBearing); pattern.append(Character.forDigit((int)e.getVelocity() + 8, 20)); int pointer = pattern.toString().indexOf(pattern.substring(Math.max(pattern.length() - 10, 0))) + 9; setTurnGunRightRadians(Math.sin(((ev[Math.min(pointer + (int)e.getDistance() / 11, n)] - ev[pointer]) / e.getDistance () + targetBearing) - getGunHeadingRadians())); setFire(3);Note that for matching the patterns, it translates the data into a set of symbols (that's why it is a symbolic pattern matcher) and then uses the java built-in functions to find the right pattern.
For a variable pattern-size pattern matcher (like the one featured on NanoLauLectrik 0.9), just replace the lines 3-5 above with the following code:
int pointer; ev[++n] = ev[n-1] + (pointer = (int) (e.getVelocity()*Math.sin(e.getHeadingRadians()-targetBearing))); pattern.append((char)pointer); //AIMING & FIRING int len = 30; do { pointer = pattern.lastIndexOf(pattern.substring(Math.max(pattern.length()-len,0)),pattern.length()-100); } while (--len*pointer < -1); pointer += len;
No dodging at all.
It is a OneOnOne bot. It hasn`t melee strategy.
... It is a kind of private joke ...
Code is open source for version 0.9. Please, if you use it give credit, and if you use it in a significant portion of your bot (ie. the gun), make your bot open sorce.
First, wait and see you it does against real enemies.
NA. I developed a new pattern matching technology for it, so some bots in the future will be based on it.
targetBearing = e.getBearingRadians() + getHeadingRadians()) - getRadarHeadingRadians()And then on the next line do:
Math.sin(e.getHeadingRadians() - targetBearing)It seems that the second line could be:
Math.sin(e.getBearingRadians())But then again, I don't know nothing about making nano-code. =) -- PEZ
Realize that one is e.getHeadingRadians(enemy heading) and the other getHeadingRadians(my heading) so I can not eliminate it. -- Albert
Ah, yes that little "e." actually means something. =) -- PEZ
My goodness, someone usign Java's built in functions for something useful. Makes me wish I knew Java better than as a watered down version of C... ;) --Mike Dorgan miked0801
Ok, my version of the pattern matching lives in my Moebius robot page. Slightly smaller and slightly better. -- Miked0801
Great job! I have been thinking about some kind of symbolic representation of logged enemy moves since working on Relativity, but I never managed to sort it out because I got stuck on combining velocity and turn. Then when I used the
e.getVelocity() * Math.sin(e.getHeadingRadians() - targetBearing)construct in Calypso? I had the feeling that a nano pattern matcher was close, but it still didn't connect in my brain. Very well done, Albert! Thanks for sharing it! -- tobe
Hey i've heard alot of great things about this bot and would like to go one on one with it, but the repository is down. Does anyone know a link to the .jar so i could battle it.
The problem originates in the pattern matcher itself, and not any supplementary code. I've been able to backtrack as far as the equivalent of this line from Moebius:
// Aim at target (asin() in front of sin would be better, but no room at 3 byte cost.) setTurnGunRightRadians(Math.sin( (arcLength[matchIndex+((int)(e.getDistance()/BULLET_SPEED))]-arcLength[matchIndex])/e.getDistance() + targetBearing - getGunHeadingRadians() ));
More specifically, I know that it isn't the sin function or anything to do with it. The subtraction of the two arc lengths yields an enormous length of arc change as being upcoming. It keeps doing this consistently, with the exact same change predicted every time. I'm somewhat unsure as to what could cause a change in arc length as big as the one observed, I can't imagine a robot could move fast enough unless it was in contact with me and swinging around me.
It's obviously triggering a false pattern recognition, but I can't imagine the situation where a robot is sitting still for that long, then moves a radian's worth of arc around me, it certainly doesn't come up in the tests before this happens. I do currently have a theory as to how to combat it, however. It occured to me while writing this. I'm implementing it in NanoSatan development and seeing how it pans out, I'll keep everyone updated. -- Kuuran
Update: I now know the exact cause of the bug. I don't believe there's any way to fight it and still let the gun fight in a nano, unfortunately. Looks like I'll have to spent more bytes on movement to compensate. -- Kuuran
What's causing the bug then? I have a similar issue in my AngularTargeting/Factor? bots. Where Walls often get delta bearings larger than the supposed maximum. I believe the maximum delta bearing in a tick should be some 44 degrees. But with walls I now and then measure delta bearings of 70 or even 100 degrees. For the momenbt I just disregard mesures over the maximum. Is this at all similar to your nano-pattern-matcher probs? -- PEZ
It's similar, I don't know if the cause if the same or not, though. I know I had this problem before with a non-standard linear targetting I tried to squeeze into one of my bots, but the cause there was completely different. My current working theory, which I am 99 percent sure of, and have some empirical data to back, is as follows: The bot is recording the standstill of a disabled or corner-stuck bot at the end of the round, then it records the sharp movement at the start of the next round. This pattern, being recent, matches when it reaches it's standstill in the corner, and the movement from the beginning of the next round is predicted. It also explains why it's much more common with bots like Corners than bots who just occasionally get stuck in corners, like Moebius.
I should also add that the corners problem will occur for an entirely different reason if a bot is in the corner and the pattern matcher is in the far corner. The pattern matcher looks for the latest occurance of the not moving pattern, which will be very recent, and then looks ahead however far the bullet would need to reach the target. However, the factor set in all the bots I've seen using this targetting means, on an 800x600 field, they wouldn't yet have data for the point they actually need. This is the tradeoff for it learning pattern-changing bots before round 50. -- Kuuran
You can fix this problem by changing the "pattern.length()-100" part of the code to a bigger number (ie. 120) so it will always have data. -- Albert
The latter, yes, not the former, and it sacrifices learning speed on bots that change every round. -- Kuuran
I think the trick with n was actually mike's trick, I don't recall exactly. Anyway, there's another one that saves you quite a few bytes. Give me your email or something and I'll send you NanoLauLectrik as codesize 236. :) (or just e-mail me: kuuran at idirect dot ca) -- Kuuran
I've had this exact same problem (as PEZ) with my waves not being able to reach Walls sometimes (meaning that Walls moves farther than the supposed maximum). Someone needs to figure out why this happens. Till then though, I just multiply my maximum angle constant by 1.2. That seems to be able to always hit Walls. -- nano
I did that as well, but then removed it since it only helps against Walls (or so I figured). Reasonable movement (as fits in a micro or mini) can outsurvive Walls without high hitting rate against it. -- PEZ
What are you using as your maximum angle for your waves? I think I've been using Math.asin(8/bulletv) and it only seems to go off occasionally (rarely enough that I blame it on the turn-based movement). -- Kawigi
Whee... here's my first shot at a second-generation NanoSatan. Still lots to be tweaked:
1st: apv.NanoLauLectrik 1.0 8478 2450 490 4948 585 4 0 56 46 0 2nd: arthord.NanoSatanPlus 8289 2300 460 4944 584 0 0 53 49 0-- Kuuran
Well, here's the math I used to generate my maximum angle. Someone please let me know where it's wrong. First, the equation for the arc-length of a circle is:
s = rTWhere s is the arc-length, r is the radius of the circle, and T (usually called theta) is the angle of the arc. Rearranged to solve for theta, it becomes:
T = s / rNow, in our case, the arc-length is the maximum distance that our enemy could travel in the amount of time it will take for our bullet to get there. So, if b is our bullet's speed, d is the distance to the enemy, and 8 is the maximum velocity, then the equation becomes:
T = (8 * (d / b)) / rThe variable r is, of course, just the distance to the enemy, so:
T = (8 * (d / b)) / dWhich, when the d's divide out, becomes:
T = 8 / bSo, in the case that the bullet speed is 11, T is 8/11, or about 41.67 degrees. That means that the total range of bearing-change that a bot could fall into for any distance with a bullet power of 3 is (-41.67, 41.67).
Now that I look back on it, I believe my mistake is the assumption that perpendicular motion (where the circle is centered on our bot, with the enemy orbiting) will always create the maximum angle change. Now that I think about it, if a bot is moving at an angle toward my bot, it may be possible that that could (in many cases) create a larger maximum angle.
In any case, multiplying T by 1.15 always (in practice) creates a large enough wave.
I'm curious though if someone can come up with a real equation for finding the maximum angle change.
-- nano
It's funny that you say 1.15 - I've been trying to figure out that problem for some time, and I'm sure that an arc is not the answer (just because there's a faster way to get from the start of the arc to the end of it if they follow a straight path). I took a couple different scenarios. One of them is the case where the radians from 8/b IS the angle, which I discarded. If they move laterally from me now and keep going straight (instead of making an arc), they form a right triangle where the hypotenuse is the bullet path, and the sine of the max angle is 8/b. So internally, I've been using asin(8/bulletv) for awhile. Another option is if they go toward you such to make a right triangle where the hypotenuse is the line to them and the adjacent leg is the bullet path. In that case the tangent is 8/b, but that seems to give smaller angles than the arc, not larger.
So my question now is whether the maximum angle is determined by moving even further away from your opponent? So I was thinking this morning about how you'd generalize this to non-right triangles (using the law of sines). Basically what I decided is that the sine of the max angle divided by the sine of some angle x (the angle your opponent moves in relative to you) equals 8/bulletv, and we want to find some x that will give us the highest possible max angle. So, if:
sin(maxangle) = sin(x)*8/bulletv
Then we want to pick the x with the biggest sine. The largest possible sine is 1, which is at 90 degrees, so it appears my asin(8/b) answer WAS in fact correct. Occasionally, someone still gets out of that window, which I blame on the tick-based physics in Robocode, although if I make sure to consider that the bullet isn't fired until the time after I call setFire, this stays down enough for me to blame it on the ticks.
The reason I say it's funny you came up with 1.15 is that in order to compensate, I changed it to asin(10/bulletv), which comes out to about 1.41 for power-3 bullets. -- Kawigi