http://robowiki.net/w/api.php?action=feedcontributions&user=RednaxelaBot&feedformat=atomRobowiki - User contributions [en]2024-03-29T09:42:34ZUser contributionsMediaWiki 1.34.1http://robowiki.net/w/index.php?title=User_talk:Voidious&diff=16933User talk:Voidious2010-07-01T08:43:27Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>==Point2D Help==<br />
Hey. I'm trying to debug my Anti-Gravity Movement I'm working on implementing into [[GITS]]. I'm trying to draw a circle with Point2D, but I can't get it to compile. The code I'm using is <code>drawCircle(java.awt.Point2D.Double, int, java.awt.Color);</code>. I just want to know if I'm doing it right. Thank you --[[User:J Litewski|HACKhalo2]] 19:47, 21 May 2009 (UTC)<br />
<br />
Hey dude - I'm guessing you saw that method in Dooki's DookiCape.java? I derived my drawing code from [[User:David Alves]]' DrawingBot (not migrated yet, see {{OldWiki|David_Alves/DrawingBot}}), which is similar to [[User:Nat/DrawingBot]]. Basically, you would need something like this to support that call:<br />
<br />
<syntaxhighlight><br />
private static Vector _renderables = new Vector();<br />
<br />
public void onPaint(Graphics2D g) {<br />
Iterator i = _renderables.iterator();<br />
while(i.hasNext()){<br />
Renderable r = (Renderable) i.next();<br />
r.render(g);<br />
}<br />
_renderables.clear();<br />
}<br />
<br />
public static void drawCircle(Point2D.Double center, double radius, Color color){<br />
_renderables.add(new Renderable.Circle(center, radius, color));<br />
}<br />
</syntaxhighlight><br />
...plus the Renderables class from DrawingBot (linked above). Does that help / make sense? --[[User:Voidious|Voidious]] 20:08, 21 May 2009 (UTC)<br />
<br />
== Redirects ==<br />
Hey, thanks for fixing all those redirects. I never knew that you had to do that to remove them from the category listings. --[[User:AaronR|AaronR]] 03:17, 12 November 2007 (UTC)<br />
<br />
== Misc Chatter ==<br />
<br />
Why not you run more TwinDuel now? I'd like to participated it. --[[User:Nat|Nat]] 07:50, 4 January 2009 (UTC)<br />
<br />
Hey, have you read my message? Look [[User_talk:Nat#New_Thai_RoboWiki|here]] &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 09:24, 25 March 2009 (UTC)<br />
<br />
So I see Nat said he'd be interested in the TwinDuel - is anyone else still interested? If I recall correctly, I needed to update my automation for newer versions of Robocode, but that shouldn't be a problem when I get some time. I've definitely been getting the itch recently to do some real Robocoding again, but I'm afraid that if I start, none of the rest of the wiki migration stuff will ever get done. =) <br />
<br />
And whether just for TwinDuel or for some active Robocoding, I really need to either explore this "Soy Latte" version of Java 6, or find another machine to work on, as I've come to accept that I will never see Java 6 on my Mac. =(<br />
<br />
--[[User:Voidious|Voidious]] 14:58, 23 April 2009 (UTC)<br />
<br />
Thanks for reply. I think I add that comment very first day on this wiki ;D I don't really think the migration stuff will never finish even you start robocoding again. I'm currently take a pause from developing robot for migration work (and few other reasons) But, do you think I should finished Challenge 2K9 before start my own migration work? Does robocode require Java 6? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:23, 23 April 2009 (UTC)<br />
<br />
: I don't know, I think that's up to you about Challenge 2K9. I haven't really read all the Challenge 2K9 info yet, but I'll try to soon. No, Robocode doesn't require Java 6, but some people use Java 6 in their TwinDuel bots, and it feels silly at this point to require people not to use Java 6 just because I don't have it on my Mac! --[[User:Voidious|Voidious]] 15:54, 23 April 2009 (UTC)<br />
<br />
:: If you have time, please help me doing the thing on Komarious. I want it to controlled distance at 450 (using Dookious AgressiveDistanceController), surf non-firing wave (rolled at 1, weight 1/6), surf hit (rolled at 0.8, weight 2), surf visit (rolled 1, weight 1) from Komarious 1.78 please? Thanks. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 16:08, 23 April 2009 (UTC)<br />
<br />
I used SoyLatte successfully until I upgraded to Leopard (which has an optional 1.6 install). Let me know if you ever want to integrate TwinDuel into the rumble. --[[User:Darkcanuck|Darkcanuck]] 15:35, 23 April 2009 (UTC) <br />
<br />
: Wow, cool, thanks for the info! I definitely heard of a developer beta at some point, but I think it was only for 64-bit processors, and I'm still on a 1st gen MacBook. Looking to upgrade soon, though, so maybe Java 6 is one more thing I can look forward to there. =) --[[User:Voidious|Voidious]] 15:54, 23 April 2009 (UTC)<br />
:: You're probably right about 64-bits -- mine's one of the first 64bit models. Buy SoyLatte worked great under X11 last time I tried. --[[User:Darkcanuck|Darkcanuck]] 16:41, 23 April 2009 (UTC)<br />
<br />
: And a TwinDuel rumble sounds very appetizing! The scoring is the only kind of weird thing, since it's survivalist, ignores total score, and is 75 rounds. If we could make the ELO + Glicko + PL stuff look at % rounds won instead of % total score, that would seem more "right" to me. But even just a 2v2 team battle on an 800x800 battlefield with all the normal scoring could be cool, too, if all of the "weird scoring" is a problem. --[[User:Voidious|Voidious]] 15:54, 23 April 2009 (UTC)<br />
<br />
: (Edit conflict) I'm curious, can roborumble client handler the 2000-bytes thing? And will 75 rounds take too long on the client? I don't know really that will anyone run battle for it. MeleeRumble and TeamRumble get only little battles before Deewiant come along with melee rumble, then GrubbmGait start to run team rumble. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 16:01, 23 April 2009 (UTC)<br />
<br />
:: We would have to modify the client to add the new game type and maybe work out a modified version of scoring. The new server does have a % survival scoring option though. With a low number of participants, it wouldn't require much client processing time (less than melee rumble for sure). --[[User:Darkcanuck|Darkcanuck]] 16:41, 23 April 2009 (UTC)<br />
<br />
----<br />
<br />
Do you have any planned with any of your robots now? [[Dookious]] hasn't been updated for an ages. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:08, 12 May 2009 (UTC)<br />
<br />
: Well, rest assured that I'm working on something. =) I'm not sure when it will be released, maybe a couple more weeks? As for my existing bots, I don't have specific plans, but they have all been on my mind. I will definitely get back to Dookious sometime -- I can't let Skilgannon have all that fun all by himself. --[[User:Voidious|Voidious]] 14:20, 12 May 2009 (UTC)<br />
<br />
Testing e-mail notification when I edit a page on my watchlist.... --[[User:Voidious|Voidious]] 23:08, 22 July 2009 (UTC)<br />
<br />
----<br />
<br />
The page [[Special:AllMessages]] isn't accessible. Just FYI, I don't think I need to use it. And the only solution is to increase the PHP's memory_limit. I always set to unlimited (0) on my machine and on my host (well, I don't really care if the script stole other site that hosted on the same server memory), but you have, let see, 256MB of RAM? Are you still using David Alves' server or the Vic's one (the old server)? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:45, 23 July 2009 (UTC)<br />
<br />
----<br />
Hey, I see that you're on the wiki right now; could I get your opinion on whether my nanobot [[User Talk: CrazyBassoonist|SavantWS]] is a real wavesurfer? So far I've got one yes and one no, and you've been wavesurfing for longer than most of us. I'd like to hear what you think about it--[[User:CrazyBassoonist|CrazyBassoonist]] 01:56, 31 July 2009 (UTC)<br />
<br />
Just a quick note that I've disabled the "rollback" link for sysops, so I won't be accidentally clicking it any more... sorry about that. --[[User:Voidious|Voidious]] 18:59, 8 September 2009 (UTC)<br />
<br />
== Segmenting Help ==<br />
<br />
I WILL NOT GIVE UP! I'm going to keep trying! I need a bit of help. I understand wave surfing much better now because of the tutorial you made. Thanks! In the [[GuessFactor Targeting Tutorial]], it teaches you what to change to segment it. Very useful. I've segmented my GF gun with distance, velocity, etc. already. However, I only see part of what I have to change in the wave surfing code. Could you give a simple example in the tutorial to help me? Thanks. -- [[User:Awesomeness]]<br />
<br />
Sure, here's a real simple example. Let's say you want to segment your surf stats on distance. Let's go real simple and just segment into "distance < 300" and "distance >= 300". <br />
<br />
* In your instance variable declarations:<br />
** <code>public static double _surfStats[] = new double[BINS];</code><br />
** becomes <code>public static double _surfStats[][] = new double[2][BINS];</code><br />
* You need to track distance at fire time in your EnemyWave class now.<br />
** In the EnemyWave class definition, add <code>double distance;</code><br />
** In <code>onScannedRobot</code>, where you detect the bullet and initialize the EnemyWave class, add <code>ew.distance = e.getDistance();</code><br />
* In <code>logHit</code>:<br />
** <code>_surfStats[x] += 1.0 / (Math.pow(index - x, 2) + 1);</code><br />
** becomes <code>_surfStats[ew.distance < 300 ? 0 : 1][x] += 1.0 / (Math.pow(index - x, 2) + 1);</code>. (That's an inline if/else statement, you don't have to do it like that if you don't want. Just need to use 0 or 1 for the first array index, depending on the distance.)<br />
* Similarly, in <code>checkDanger</code>:<br />
** <code>return _surfStats[index];</code><br />
** becomes <code>return _surfStats[surfWave.distance < 300 ? 0 : 1][index];</code><br />
<br />
Basically, any information you want to segment on, you would store that information in your wave class. Then whenever you access your _surfStats, you use that data to come up with the array indexes. Effectively, you end up with a bunch of surfStats[] arrays, one for each situation (segment). Make sense?<br />
<br />
--[[User:Voidious|Voidious]] 01:05, 7 May 2009 (UTC)<br />
<br />
There is another way doing this. I'm not using that way because it more complex. I use the magic of reference to do the thing similar to the one in [[GuessFactor Targeting Tutorial]]:<br />
<br />
* In your instance variable declarations:<br />
** <code>public static double _surfStats[] = new double[BINS];</code><br />
** becomes <code>public static double _surfStats[][] = new double[2][BINS];</code><br />
* You need to reference the new segment in your enemy wave now.<br />
** In the EnemyWave class definition, add <code>double[] stats;</code><br />
** In <code>onScannedRobot</code>, where you detect the bullet and initialize the EnemyWave class, add <code>ew.stats = _surfStats[e.getDistance() < 300 ? 0 : 1];</code> (That's an inline if/else statement, you don't have to do it like that if you don't want. Just need to use 0 or 1 for the first array index, depending on the distance.)<br />
* In <code>logHit</code>:<br />
** <code>_surfStats[x] += 1.0 / (Math.pow(index - x, 2) + 1);</code><br />
** becomes <code>ew.stats[x] += 1.0 / (Math.pow(index - x, 2) + 1);</code>. <br />
* Similarly, in <code>checkDanger</code>:<br />
** <code>return _surfStats[index];</code><br />
** becomes <code>return surfWave.stats[index];</code><br />
<br />
(copy from yours, [[User:Voidious|Voidious]]) This way if you are adding more segment, you just need to change only one place (vs. 2 places). Actually I done the <code>ew.stats = _surfStats[ew.distance < 300 ? 0 : 1];</code> thing in constructor of EnemyWave class (by assigning the data to the global variable first of corse). &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:13, 7 May 2009 (UTC)<br />
<br />
== Time to upgrade ==<br />
<br />
Hi Voidious. I think the upgrade time has come. Please upgrade soon. Thanks. I know you are backing the database up, but first you need is "Wiki Lockdown" <!-- like:<br />
<syntaxhighlight><br />
$wgGroupPermissions['*' ]['edit'] = false;<br />
$wgGroupPermissions['*' ]['createpage'] = false;<br />
$wgGroupPermissions['*' ]['createtalk'] = false;<br />
$wgGroupPermissions['user' ]['move'] = false;<br />
$wgGroupPermissions['user' ]['edit'] = false;<br />
$wgGroupPermissions['user' ]['createpage'] = false;<br />
$wgGroupPermissions['user' ]['createtalk'] = false;<br />
$wgGroupPermissions['user' ]['upload'] = false;<br />
$wgGroupPermissions['user' ]['reupload'] = false;<br />
</syntaxhighlight><br />
... will totally lockdown for anonymous and registered user. (LocalSettings.php) --> or your backup will never present. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:21, 7 May 2009 (UTC)<br />
<br />
Soon. =) Probably tomorrow, as I'll be on the away from the computer this evening. --[[User:Voidious|Voidious]] 15:50, 7 May 2009 (UTC)<br />
<br />
== public class EnemyWave ==<br />
<br />
Awesome basicsurfer tutoral.<br />
<br />
Could you edit class EnemyWave to be public class EnemyWave? APIs freak out otherwise.<br />
<br />
Thanks! <small><span class="autosigned">—Preceding [[wikipedia:Wikipedia:Signatures|unsigned]] comment added by [[User:Mageek|Mageek]] ([[User talk:Mageek|talk]] • [[Special:Contributions/Mageek|contribs]]) </span></small><br />
<br />
You can changed it yourself. Robocode's robots don't need API, their classes cannot be used outside (unless you count when someone copy it over). &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 08:27, 23 May 2009 (UTC)<br />
<br />
I'm not sure what you mean by "APIs freak out"? You could define it differently, eg as a public class in its own file, but it worked fine as it is last I checked. If there is some reason it should be changed, though, I'm all for it... Glad you liked the tutorial, good luck! Feel free to make a page for yourself and tell us about your bots. --[[User:Voidious|Voidious]] 19:06, 23 May 2009 (UTC)<br />
<br />
== Robot's Image ==<br />
<br />
Voidious, I'm wondering why do you uploaded those images ([[:File:Phoenix3.jpg]] & [[:File:Silversurfer05.jpg]])? It seems to be robot's image. But you didn't migrate those pages ([[Phoenix]] & [[SilverSurfer]]) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:53, 14 July 2009 (UTC)<br />
<br />
It is because I intended to migrate the pages, I just haven't actually done it yet. =) They are the [[Special:WantedPages|most wanted pages]] right now. --[[User:Voidious|Voidious]] 17:01, 14 July 2009 (UTC)<br />
<br />
== User welcoming ==<br />
<br />
Hi Voidious, I noticed that lately you also welcome all new robocoders (usually after I insert that template) in your own test that mean the same. I wonder why don't you make changes to the template {{tl|Welcome}}, you are welcome to use it to welcome people instead of your writing. The usage is describe on its page. This is applied to all other Robocoders who might read this too.<br />
<br />
It just feels a little more personal to me. It's not like we get that many new users, I can take a minute to say hi. =) Your welcome template is fine, too, it contains some good information. --[[User:Voidious|Voidious]] 17:37, 16 July 2009 (UTC)<br />
<br />
You can post both the template and personal welcome. I sometimes did that too. I'm not 24/7 robot so I'm not active all the time. OK, all I asked is that when you welcome users using your own text and I haven't put that template on yet, you are very welcome to put that template in (on? which preposition to use here?). Thank you in advance. --Nat<br />
<br />
Ok, will do. As for correctness, I think "to put that template onto the page" would be technically correct, but if you leave out "the page", then "to put that template in" sounds right to me, though "on" does not sound wrong. I'm not sure I can even explain why -- English is really weird. --[[User:Voidious|Voidious]] 14:18, 17 July 2009 (UTC)<br />
<br />
Thank you. I did go over my sheet on preposition several time and can't find the right one. So you see why I am not sure which one to use. Both "in" and "on" don't sound wrong... You may noticed that I use both "on" and "in" in that sentence, bad I know. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:27, 17 July 2009 (UTC)<br />
<br />
== Rumble Help ==<br />
Voidious, since you've been so helpful... I created a new version without the faulty call. I've uploaded it to the repository, deleted the old one, and changed the participants in the wiki to point to the new one (1.1 version). But the server keeps using the old one? Am I doing something wrong? Thanks!<br />
--[[User:Borkstation|Borkstation]] 13:15, 17 July 2009 (UTC)<br />
<br />
The rumble clients update its list every 2 hours, and the server will allowed clients to remove the bot after four hours of no updates. You need to wait for about an hour more to watch the result. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:19, 17 July 2009 (UTC)<br />
<br />
Yeah, as Nat said, a running rumble client only updates its list every 2 hours or so. Also, once a bot has a certain number of battles (50 I think?), the server will try to run battles for it until it completes all its pairings, even if it is removed (so it might run both versions until then). I see my client (which I just fired back up) is running [[BoxCar]] 1.1, so it should be getting steady battles at this point. --[[User:Voidious|Voidious]] 14:27, 17 July 2009 (UTC)<br />
<br />
Thanks guys. I'm really just getting started and trying to create a bot that doesn't stink before I jump into anything complicated. You've all been a great help.<br />
--[[User:Borkstation|Borkstation]] 15:24, 17 July 2009 (UTC)<br />
<br />
== Upload directory not writable ==<br />
<br />
Old problem arise, I can't upload again =( &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 04:21, 19 July 2009 (UTC)<br />
<br />
: Ok, could you try again please? --[[User:Voidious|Voidious]] 04:25, 19 July 2009 (UTC)<br />
<br />
:: Thanks, fixed. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 04:33, 19 July 2009 (UTC)<br />
<br />
== OutOfMemoryError ==<br />
<br />
Hey Voidious, have you change the server? It seems that the memory_limit PHP configuretion is lower than it used to be. I got PHP's fatal error when I tried to add the header to Shadow's archived talk page. I must use dummy header to successfully add them. Please fix soon, remember that MediaWiki need at least 96MB. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 12:10, 25 July 2009 (UTC)<br />
<br />
== wget on dijitari.com ==<br />
<br />
Heya Voidious, is it known/intended that trying to do a wget on [http://www.dijitari.com/void/robocode/voidious.Diamond_1.252.jar http://www.dijitari.com/void/robocode/voidious.Diamond_1.252.jar] fails with a 403 error while using firefox or the rumble client does download it successfully? Doesn't really matter but it did leave me in confusion for a moment :) --[[User:Rednaxela|Rednaxela]] 05:47, 6 August 2009 (UTC)<br />
<br />
: No, not known nor intended. I didn't even know what "wget" was until this morning. =) I'm curious now, though, so I'll look into it when I get a chance (if I can remember)... --[[User:Voidious|Voidious]] 13:07, 6 August 2009 (UTC)<br />
<br />
== Modifying Diamond question ==<br />
<br />
Hey Voidious, I guess it's okay, but I feel it's proper to ask: Do you mind if I turn off some debugging graphics (the t-... thing) in Diamond and use it as a wavesurfing demonstration in a youtube video? :) --[[User:Positive|Positive]] 20:29, 14 August 2009 (UTC)<br />
<br />
: Of course not! =) You may have already seen, but there are variables in the gun, radar, and movement classes to disable all graphics within that class. --[[User:Voidious|Voidious]] 20:37, 14 August 2009 (UTC)<br />
<br />
: [http://www.youtube.com/watch?v=dqHmp_kMz-U Here you go] :).<br />
<br />
== Re: "stupid #@$% iPhone" ==<br />
<br />
I know your pain. The autocorrect when typing is also a pain when typing rarely typed acronyms :) --[[User:Rednaxela|Rednaxela]] 15:11, 15 August 2009 (UTC)<br />
<br />
Hehe. Yeah, I adore my iPhone, but sometimes the browser wigs out and totally clicks the wrong place - I think it's scrolling before noticing the click or something, as the touch is usually super accurate. I wish reverting edits required confirmation, too, as I've done that several times now. I hear ya on the autocorrect, but I must say it's pretty cool that it has learned (and even suggests) my favorite swear words now. =) --[[User:Voidious|Voidious]] 15:17, 15 August 2009 (UTC)<br />
<br />
You can always create another user for admin and remove sysop right from your username. That will cause the rollback link to disappear I believe =) Just kidding. (Note: but it will disappear) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 16:38, 15 August 2009 (UTC)<br />
<br />
== Wierd scores ==<br />
<br />
Hi Voidious! I'm glad you liked my bot. However i'm thoughtful about why your own bot is performing so much better on your own computer then everyone elses.<br />
Check the stats page: <br />
<br />
http://darkcanuck.net/rumble/BattleDetails?game=minirumble&name=rsim.mini.BulletCatcher%200.1&vs=voidious.mini.Komarious%201.88<br />
<br />
On your client my bot scores about 40% while on other clients my bot scores >70% --[[User:Rsim|Rsim]] 18:27, 15 August 2009 (UTC)<br />
<br />
Hmm, I have no idea. It could just be luck, that's only a few battles. I'll try running some more battles between them with 1.6.1.4 and see what happens. --[[User:Voidious|Voidious]] 18:33, 15 August 2009 (UTC)<br />
<br />
Ok, 25 battles on my main machine (MacBook, SoyLatte Java 6) had a range of 53-85% and an average of 69%, BulletCatcher winning. But on my Linux box (OpenJDK 6), Komarious wins with ~70%. Maybe there is something about Robocode's bullet collision that is JVM dependent? Is anyone else on Linux that could give this a try? --[[User:Voidious|Voidious]] 18:50, 15 August 2009 (UTC)<br />
<br />
: You could try a more controlled experiment on your machines by running the same start positions and random seed on both machines. In theory you should get an identical result on both? --[[User:Darkcanuck|Darkcanuck]] 19:00, 15 August 2009 (UTC)<br />
<br />
:: I've never done that before... Any pointers on how I'd go about configuring that? The scoring discrepancy between the two is large and consistent enough that I'm already convinced there is one, but it would still be a good test. --[[User:Voidious|Voidious]] 19:06, 15 August 2009 (UTC)<br />
<br />
::: Never done it myself, but I think it's what [[Fnl]] uses for testing and also how the engine handles replays. I know there's a command-line option <code>-DRANDOMSEED</code> (from the robocode.jar usage text) to preset the random number generator. And if you run using a saved battle file there's a property called <code>robocode.battle.initialPositions</code> that lets you set the initial positions and headings (although I'm not sure of the syntax/format). --[[User:Darkcanuck|Darkcanuck]] 19:29, 15 August 2009 (UTC)<br />
<br />
Hmm... the nature of BulletCatcher leads me to believe that this discrepency is due to a CPU or JVM dependent rounding error perhaps... Hopefully we can get this sorted out --[[User:Rednaxela|Rednaxela]] 20:31, 15 August 2009 (UTC)<br />
<br />
Having BulletCatcher in Voidious excluded list would make me happy while this is beeing sorted out :) --[[User:Rsim|Rsim]] 20:44, 15 August 2009 (UTC)<br />
<br />
: No problem, done. --[[User:Voidious|Voidious]] 20:48, 15 August 2009 (UTC)<br />
<br />
To compare, my computer shows BulletCatcher averaging 73.25% over 8 matches, using Sun JVM 1.6.0 on Linux. I'll test with OpenJDK in a moment. --[[User:Rednaxela|Rednaxela]] 20:57, 15 August 2009 (UTC)<br />
: Over 8 matches with OpenJDK 6 on Linux, the average is 74.5% in favor of BulletCatcher still. Whatever this issue is, it's neither the fault of OpenJDK 6, Linux, or Robocode 1.6.1.4... Maybe the processor on that box has a rounding bug issue or something? I don't know what else to think. --[[User:Rednaxela|Rednaxela]] 21:29, 15 August 2009 (UTC)<br />
: I'm still seeing mostly Komarious wins under the Sun JVM 1.6.0, but with 50-60% scores, compared to the 70-80% scores I see under OpenJDK. There's definitely a difference between them on this machine. I switched to OpenJDK because I suspected the Sun JVM was responsible for the machine crashing, and indeed it seemed to be more stable immediately upon switching to OpenJDK. But I guess I'll switch back to the Sun JVM for now (and cross my fingers). Still excluding BulletCatcher, though. It's Ubuntu 8.10 on an AMD2000+, if that means anything to anyone.<br />
: I'm getting a new computer in the next week or so, so the old Linux box will become almost negligible in my total rumble power. Maybe I'll just throw it out the window at that point. =)<br />
: --[[User:Voidious|Voidious]] 21:36, 15 August 2009 (UTC)<br />
:: Update: the machine totally crashed sometime yesterday after 30-40 days up-time, so I do believe it's the Sun JVM's fault (at least in part). --[[User:Voidious|Voidious]] 14:20, 18 August 2009 (UTC)<br />
: Did you check the scripts? I once had a similar problem and I had 256MB for heap size on one of the script files. --[[User:Zyx|zyx]] 22:11, 15 August 2009 (UTC)<br />
:: Good idea, but I just double-checked all three (Robocode, roborumble, meleerumble) and they all use 512 mb. --[[User:Voidious|Voidious]] 22:14, 15 August 2009 (UTC)<br />
::: This could be related to this http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6457965 --[[User:Rsim|Rsim]] 21:35, 23 August 2009 (UTC)<br />
<br />
==Faulty Score==<br />
I detected battles where your machine reports wired scored: <br />
<br />
http://darkcanuck.net/rumble/BattleDetails?game=roborumble&name=synapse.rsim.GeomancyBS%200.11&vs=apv.TheBrainPi%200.5<br />
<br />
For other battles involving GeomancyBS 0.11 you report reasonable scores (I think), could you check what's wrong with the battle against TheBrainPi? (note that this should not be releated to the issue above as i changed the line-intersecting code to be VM independent.) --[[User:Rsim|Rsim]] 18:36, 4 September 2009 (UTC)<br />
<br />
I am checking it out now. I think TheBrainPi throws exceptions sometimes, so maybe that is causing the issue. Also, just FYI, the above problems were only on my Linux RoboRumble box, which I'm not running any more, anyway... --[[User:Voidious|Voidious]] 18:40, 4 September 2009 (UTC)<br />
<br />
Here's what I'm seeing. The first round, [[GeomancyBS]] sheilds 3 bullets, then [[TheBrainPi]] gets disabled with the following:<br />
<pre><br />
apv.TheBrainPi 0.5: Exception: java.lang.NullPointerException<br />
java.lang.NullPointerException<br />
at apv.nrlibj.NNet.frwNNet(NNet.java:378)<br />
at apv.TheBrainPi.aim(TheBrainPi.java:188)<br />
at apv.TheBrainPi.onScannedRobot(TheBrainPi.java:145)<br />
at robocode.peer.robot.EventManager.onScannedRobot(Unknown Source)<br />
at robocode.peer.robot.EventManager.dispatchEvent(Unknown Source)<br />
at robocode.peer.robot.EventManager.processEvents(Unknown Source)<br />
at robocode.peer.RobotPeer.execute(Unknown Source)<br />
at robocode.peer.proxies.BasicRobotProxy.execute(Unknown Source)<br />
at robocode.AdvancedRobot.execute(Unknown Source)<br />
at apv.TheBrainPi.run(TheBrainPi.java:118)<br />
at robocode.peer.RobotPeer.run(Unknown Source)<br />
at java.lang.Thread.run(Thread.java:619)<br />
</pre><br />
GeomancyBS sits there (waiting for next bullet?) and eventually gets disabled for not doing anything, and they both die. Every round after that, TBP hits the above NPE before firing, and GBS just sits and also gets disabled. Maybe you need a clause to just fire 3.0 bullets at a disabled opponent?<br />
<br />
--[[User:Voidious|Voidious]] 18:46, 4 September 2009 (UTC)<br />
<br />
Yes, it probably should (i though it did). But the strange thing is that apv.TheBrainPi works flawlessly on my machine and doesn't throw any errors at all. Thanks for investigating it! --[[User:Rsim|Rsim]] 18:56, 4 September 2009 (UTC)<br />
<br />
Out of curiosity, are you seeing that every single time with TBP Voidious? Or is it only sometimes? --[[User:Rednaxela|Rednaxela]] 19:28, 4 September 2009 (UTC)<br />
<br />
Against everyone, it looks like -- I tried [[Raiko]], [[Duelist]], and [[Infinity]], and I tried both SoyLatte (my normal JVM) and the Apple JVM with the same results. This is in Robocode 1.6.1.4. --[[User:Voidious|Voidious]] 19:36, 4 September 2009 (UTC)<br />
<br />
I decided to do some more investigation of this. First, it looks like most of TBP's zero scores have come from me, but a few have also come from Darkcanuck: [http://darkcanuck.net/rumble/BattleDetails?game=roborumble&name=apv.TheBrainPi%200.5&vs=abc.tron3.Tron%203.11], [http://darkcanuck.net/rumble/BattleDetails?game=roborumble&name=apv.TheBrainPi%200.5&vs=cx.CigaretBH%201.03], [http://darkcanuck.net/rumble/BattleDetails?game=roborumble&name=apv.TheBrainPi%200.5&vs=stf.PanzerGeneral%200.1]. More importantly, though, I remembered that TBP saves its NN info between matches, and uses the same data against every bot (as if all opponents are just one opponent). So I thought maybe TBP had somehow corrupted its own NN data. I tried clearing the data directory and reloading the bot, and indeed, he works fine after that. I'm not sure what to do about this... obviously, it's not fair to make everyone watch out for this and baby-sit their data directories because of a buggy bot, but I also feel bad removing it (especially since [[User:Albert|Albert]] is the father of the RoboRumble). Thoughts? --[[User:Voidious|Voidious]] 20:04, 4 September 2009 (UTC)<br />
<br />
: That is indeed an ''emotional'' situation. Maybe we could make a '''fix''' version, as it was done with SilverSurfer (although reasons are different) and just try and catch that exception you posted, if it happens force a clean on the data. If people agree I wouldn't mind checking if I can fix it. --[[User:Zyx|zyx]] 20:13, 4 September 2009 (UTC)<br />
<br />
:: Sounds like a good idea to me. I vote for this --[[User:Rsim|Rsim]] 20:18, 4 September 2009 (UTC)<br />
<br />
:: Yeah, that's a great idea. I didn't think TheBrainPi was open source, but it is. Just FYI - TBP actually comes with some pre-loaded data (my test above included restoring those files), but seems to work fine starting from a clean data dir, so your proposed fix should work. --[[User:Voidious|Voidious]] 20:30, 4 September 2009 (UTC)<br />
<br />
I was looking how hard/easy would that fix be. I easily tracked down a good place to put the fix in and when I tested my fix I realized the File.delete() method was returning false(didn't delete it successfully), some reading on the web of when that happens made me realize he isn't closing the file after reading. If I add the close call to his reading method, then my delete fix works properly. But now I'm thinking that maybe the corruption comes from not closing the files after reading, so I will add the call to close and leave the delete fix, but I will print to the console whether the delete part ever happens, hopefully it will never have to actually the files. --[[User:Zyx|zyx]] 20:57, 4 September 2009 (UTC)<br />
<br />
== Choice of license ==<br />
<br />
I've been giving serious thought to changing what source code license I use for my bots. It's been a long time since I decided on [[RWPCL]], and my views have evolved a bit since then. A few things recently (including [[User:Rednaxela|Rednaxela]] opting for [[wikipedia:zlib License|zlib]], and [http://www.stevestreeting.com/2009/09/15/my-evolving-view-of-open-source-licenses/ this article] about a graphics engine going from [[wikipedia:LGPL|LGPL]] to [[wikipedia:MIT License|MIT]]) have gotten me thinking hard about why I open source my bots, and in turn, what license best fits those goals. There are 3 main reasons I open source:<br />
<br />
# To give others the opportunity to learn from my code in the same way that I have been able to learn from so many other bots and people on this wiki.<br />
# To contribute to the collective advancement of Robocode bots.<br />
# To encourage others to open source their bots.<br />
<br />
The RWPCL certainly contributes to all of these points, but I think it may put undue weight on #3, when I actually care a lot more about #1 and #2. And if a more permissive license would result in more people using/learning from my code, that might contribute to #3 more than a Copyleft license's restrictions. I'm considering [[RWLPCL]] or something like zlib or MIT. I already have a good idea where some of you stand, but I'd really appreciate hearing what you guys think about this topic. Thanks,<br />
<br />
--[[User:Voidious|Voidious]] 18:16, 25 September 2009 (UTC)<br />
<br />
Yeah, similar reflection on why I open source my bots is what led me to decide on a slightly slimmed/modified zlib licence for my kd-tree. In the future (i.e. with Glacier), I'm considering doing a practice of using a somewhat restricted licence (look at the code, learn from it, but don't copy-paste and release it without asking) for unique behavioural parts of the bot like targeting/movement, but using a permissive licence (i.e. slimmed/modified zlib) for all utility code (which seems to make up over half of my bots lately). I don't mind people reusing my code, but I'd use the more restrictive licence on the unique behavioural parts in order to encourage people to do their own thing. If people ask I'd be very open to either changing particular classes to a permissive licence or giving case-by-case exceptions. As I see it, that would be best for allowing people to learn from my code, use useful utility classes they come across, but encourage innovation. Also, for nanos/micros I'd probably just go fully in a permissive licence since it's so small anyway, I'm mainly talking about megas here. That's my position and those are my current plans anyway, as far a the licence of my bots is concerned. --[[User:Rednaxela|Rednaxela]] 18:52, 25 September 2009 (UTC)<br />
<br />
: My thoughts exactly =) I like to provide my code as a ''reference implementation'', but it needs to be clear that it's the idea behind the code that is important for people to grasp, not the code itself. If people want to use parts of [[DrussGT]], [[CunobelinDC]], [[Toorkild]] or [[Wintermute]] that make them the unique bots they are, then I really would prefer if they either 1) ask first or 2) make their own implementation based on the concept of what my code is trying to achieve. If there's a licence that provides this I'd happily use it, I'm just mostly too lazy, and too legalese-phobic, to go looking. --[[User:Skilgannon|Skilgannon]] 19:24, 25 September 2009 (UTC)<br />
<br />
You're probably right Voidious that [[RWLPCL]] contributes more to the community than [[RWPCL]]. Otoh you want to share your ideas and some utilities, not the complete source. For my bots the license is not that important, as they do not contain any unique code. --[[User:GrubbmGait|GrubbmGait]] 22:28, 25 September 2009 (UTC)<br />
<br />
[[Skilgannon]] said exactly my thoughts. I like to share my code so people can learn stuff from them but I don't want them to just copy out of them, but laziness and fear to get too legal about it makes me stay away from licenses. I just want to enjoy Robocode as a very fun game, so I prefer to have no license and let people copy from it than search for an appropriate one and worry about it being violated. At the end I think is their loss if they don't implement it themselves as that is exactly what I enjoy doing. But if this conversation leads to a license that expresses that, I'd happily go for it. --[[User:Zyx|zyx]] 03:34, 26 September 2009 (UTC)<br />
<br />
Thanks guys, I really appreciate all the input. My ideal vision for how others would use my source code is exactly the same as all of yours. What I'm not sure about is whether I want to, or even can, enforce that with a restrictive license. At what point does someone "truly understand" my code? Do they really need to understand it to be able to build innovations on top of it? There are many parts of Java's libraries that I don't fully understand, but I still use them as building blocks - how is that any different?<br />
<br />
Another part of my thought process is that a license restriction is not going to stop someone who really wants to steal my code without giving credit. But it may stop other uses that I would be OK with, such as someone with a closed source bot releasing a test/hybrid bot with my movement, to compare the guns. Kind of along the lines of, "if you outlaw guns, only the outlaws will have guns". In my mind, as long as credit is given, even copying large portions of another bot is not necessarily a bad thing in every circumstance (though I personally wouldn't enjoy doing so). I'm leaning towards RWLPCL right now (basically, "just give credit"), but I'm still thinking it over. --[[User:Voidious|Voidious]] 04:12, 26 September 2009 (UTC)<br />
<br />
I think we all have almost the same thought on this. How about my [[NPRL]] ? (I should remove the first rule of that license) Basically, it is RWLPCL with some extra to control the use and improvement of the source code (much like RWLPCL + Skilgannon's license)<br />
<br />
I don't think you need to fully understand the code before you can use it. Of course, by truly understand it you are able to use it better, but if you don't doesn't mean you can't. Such as when I first implement wave surfing, I never understand what the predictPosition() do in BasicSurfer, but I know what it is and what is it use for (like how you understand the Java's libraries). That's enough for me create wave surfer. And what point is to 'truly understand' the code? I say, when you are able to provide the pseudo-code for it. I mean, I think can provide you how Simonton's nano PM gun work, but I can't really make them nano-size. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 07:52, 26 September 2009 (UTC)<br />
<br />
I agree with everyone who responded to you. Perhaps licenses for different source files work best (like Rednaxela suggested), so people can use your utilities but don't copy what makes your bots so unique. Also, I'd like it if I could use your surf wave graphics, they're so damn cool. :) --[[User:Positive|Positive]] 21:13, 26 September 2009 (UTC)<br />
<br />
== Dookious vs. Horizon ==<br />
<br />
Hey, Voidious, it looks like [[Horizon]] is back to beating [[Dookious]]. And this time, [http://darkcanuck.net/rumble/BattleDetails?game=roborumble&name=ar.horizon.Horizon%201.2.1&vs=voidious.Dookious%201.573c it's doing it legitimately] ;). « [[User:AaronR|AaronR]] « [[User talk:AaronR|Talk]] « 11:47, 24 October 2009 (UTC)<br />
<br />
Wow, nice work! Dookious is tough. Your win/loss record looks really weird to me. You also beat [[Pris]], while Pris completely destroys [[Diamond]], but you lose to Diamond and quite a few weaker bots. My first thought is that your flattener might be turning on too often, and your [[Horizon/Version History|version history]] seems to corroborate that. I think you'll be in really good shape once you tune that a bit! --[[User:Voidious|Voidious]] 16:49, 24 October 2009 (UTC)<br />
<br />
:Thanks! The heuristic I tried was the simplest one I could think of, so it's no surprise that the flattener turns on at the wrong times. I just wanted to get this out there to see how it does. « [[User:AaronR|AaronR]] « [[User talk:AaronR|Talk]] « 00:04, 25 October 2009 (UTC)<br />
<br />
:Just an observation, DrussGT usually loses to Raiko in the 2nd or 3rd round, after Raiko disables the Musashi Trick and uses his VERY strong random movement. --[[User:Skilgannon|Skilgannon]] 14:10, 25 October 2009 (UTC)<br />
<br />
== Recent hiatus ==<br />
<br />
I have been consumed by [http://www.quakelive.com Quake Live] since last October, which is most of the reason for my Robocoding hiatus since then. Also did [http://nanowrimo.org NaNoWriMo] in November. I'm still checking the wiki and even done some Robocoding here and there, but nothing that's led to an actual new version. Figured it's been long enough that I wanted to post an explanation. =) --[[User:Voidious|Voidious]] 16:11, 19 January 2010 (UTC)<br />
<br />
== Happy Birthday ==<br />
<br />
Happy Birthday Voidious! Hope you have good day and have fun! May the surfboard be with your jewellery =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 08:50, 8 April 2010 (UTC)<br />
<br />
Thanks dude. =) Never heard that expression before... not sure I understand. ;) --[[User:Voidious|Voidious]] 20:54, 8 April 2010 (UTC)<br />
<br />
Happy birthday indeed! Haven't heard that expression either, interesting. --[[User:Rednaxela|Rednaxela]] 21:02, 8 April 2010 (UTC)<br />
<br />
Sorry, so caught up with my latest releases I must have missed it. Happy birthday man =) --[[User:Skilgannon|Skilgannon]] 05:19, 9 April 2010 (UTC)<br />
<br />
Explanation: As your name 'Voidious' came from Star War series, I adopted the sentence 'May the force be with you.' Surfboard == thing use for surfing && jewellery == Diamond =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 08:45, 9 April 2010 (UTC)<br />
<br />
I know I'm a little late, but here it goes: happy birthday! --[[User:Navajo|Navajo]] 13:28, 9 April 2010 (UTC)<br />
<br />
Well, I hope you had a good day yesterday. Our birthdays are a day and likely a few years apart. Today I turned 37. Poker party at my house tonight. --[[User:Pedersen|Martin]] 15:35, 9 April 2010 (UTC)<br />
: (Happy birthday to you too then Martin! Have fun :P --[[User:Rednaxela|Rednaxela]] 15:45, 9 April 2010 (UTC))<br />
<br />
Thanks dudes. And yeah, Happy Bday to you too, Martin. Sounds like you prolly had more fun than I did. ;) --[[User:Voidious|Voidious]] 23:23, 10 April 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Voidious/Optimal_Velocity&diff=16932User talk:Voidious/Optimal Velocity2010-07-01T08:43:24Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>I did a quick one-liner which gives almost exactly the same results as your getMaxVelocity(distance):<br />
<syntaxhighlight><br />
private static final double maxVel(double distance){<br />
return Math.floor((Math.sqrt(1 + 4*2/Rules.DECELERATION*distance) - 1));<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
The difference is that mine gives integer results, rather than all the 0.5s 0.33333s 0.25s and 0.666667s. <br />
<pre><br />
Distance Skilgannon Voidious<br />
0 0.0 0.0<br />
1 1.0 1.0<br />
2 2.0 2.0<br />
3 2.0 2.5<br />
4 3.0 3.0<br />
5 3.0 3.5<br />
6 4.0 4.0<br />
7 4.0 4.333333333333333<br />
8 4.0 4.666666666666667<br />
9 5.0 5.0<br />
10 5.0 5.333333333333333<br />
11 5.0 5.666666666666667<br />
12 6.0 6.0<br />
13 6.0 6.25<br />
14 6.0 6.5<br />
15 6.0 6.75<br />
16 7.0 7.0<br />
17 7.0 7.25<br />
18 7.0 7.5<br />
19 7.0 7.75<br />
20 8.0 8.0<br />
</pre><br />
--[[User:Skilgannon|Skilgannon]] 10:00, 16 July 2009 (UTC)<br />
<br />
Hey [[User:Skilgannon|Skilgannon]], I did a test with your one-liner with the formula's on [[Positive/Optimal Velocity]]:<br />
<br />
StartVelocity = 0.0; StartDistance = 6.0; <br />
<pre><br />
velocity = 0.0; distance=6.0<br />
velocity = 1.0; distance=5.0<br />
velocity = 2.0; distance=3.0<br />
velocity = 2.0; distance=1.0<br />
velocity = 1.0; distance=0.0<br />
</pre><br />
<br />
StartVelocity = 0.0; StartDistance = 10.0; <br />
<pre><br />
velocity = 0.0; distance=10.0<br />
velocity = 1.0; distance=9.0<br />
velocity = 2.0; distance=7.0<br />
velocity = 3.0; distance=4.0<br />
velocity = 3.0; distance=1.0<br />
velocity = 1.0; distance=0.0<br />
</pre><br />
<br />
StartVelocity = -1.9; StartDistance = 10.0; <br />
<pre><br />
velocity = -1.9; distance=10.0<br />
velocity = 0.10000000000000009; distance=9.9<br />
velocity = 1.1; distance=8.8<br />
velocity = 2.1; distance=6.700000000000001<br />
velocity = 3.1; distance=3.600000000000001<br />
velocity = 2.0; distance=1.600000000000001<br />
velocity = 1.600000000000001; distance=0.0<br />
</pre><br />
<br />
StartVelocity = 8.0; StartDistance = -2.0; <br />
<pre><br />
velocity = 8.0; distance=-2.0<br />
velocity = 6.0; distance=-8.0<br />
velocity = 4.0; distance=-12.0<br />
velocity = 2.0; distance=-14.0<br />
velocity = -0.0; distance=-14.0<br />
velocity = -1.0; distance=-13.0<br />
velocity = -2.0; distance=-11.0<br />
velocity = -3.0; distance=-8.0<br />
velocity = -4.0; distance=-4.0<br />
velocity = -3.0; distance=-1.0<br />
velocity = -1.0; distance=0.0<br />
</pre><br />
<br />
StartVelocity = 5.0; StartDistance = 40.0; <br />
<pre><br />
velocity = 5.0; distance=40.0<br />
velocity = 6.0; distance=34.0<br />
velocity = 7.0; distance=27.0<br />
velocity = 8.0; distance=19.0<br />
velocity = 7.0; distance=12.0<br />
velocity = 6.0; distance=6.0<br />
velocity = 4.0; distance=2.0<br />
velocity = 2.0; distance=0.0<br />
</pre><br />
<br />
Your solution and Voidious's one seem to preform about the same. Interesting. :) By the way, I did adjust your function to:<br />
<br />
<syntaxhighlight><br />
private static final double maxVel(double distance){<br />
if(distance<0)<br />
return -maxVel(-distance);<br />
if(distance<=Rules.DECELERATION)<br />
return distance;<br />
return Math.floor((Math.sqrt(1 + 4*2/Rules.DECELERATION*distance) - 1));<br />
}<br />
</syntaxhighlight><br />
<br />
Otherwise it gives nextVel=0.0 on distance==0.6. --[[User:Positive|Positive]] 10:50, 16 July 2009 (UTC)<br />
<br />
To tell the truth, I actually like the results Voidious's version gives better, as it keeps a slightly higher velocity the whole way through to minimise any possible gap at the end. =) I've made a simplified version of the whole predictor based on your ideas, I'll post it just now. --[[User:Skilgannon|Skilgannon]] 11:19, 16 July 2009 (UTC)<br />
<br />
Wow, that's pretty neat. While I know that, theoretically, you don't need to go max speed in every case, it's become a warning sign to me of a probable bug in solutions to this problem. For instance, for d=19.9, yours gives v=7, which will cause an extra tick (7, 6, 4, 2, d=0.9 remaining). Nevertheless, pretty cool. You darn students and your non-rusty math chops! =) --[[User:Voidious|Voidious]] 14:07, 16 July 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Urgood2&diff=16931User talk:Urgood22010-07-01T08:43:21Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{| width="100%" style="background: white; " <br />
| valign="top" width="60%" style="border: 2px solid #000; padding: .5em 1em; -moz-border-radius: 1em; -webkit-border-radius: 1em" |<br />
'''Welcome!'''<br />
<br />
Hello, {{BASEPAGENAME}}, and welcome to [[RoboWiki]]! This place contains a wealth information about [[Robocode]], from [[Head-On Targeting|basic]] to [[Wave Surfing|more advanced]]. I hope you enjoy creating robots and being a robocoder!<br />
<br />
If you are posting a comment on this wiki, please [[wikipedia:Wikipedia:Signatures|sign]] your messages using four tildes (<nowiki>--~~~~</nowiki>); this will automatically insert your username and the date stamp. If you are not familiar with MediaWiki, these links might help you out:<br />
* [[wikipedia:How to edit|How to edit]] on [[wikipedia:|Wikipedia]], [[metawikipedia:Cheatsheet|Cheatsheet]] and [[metawikipedia:File:MediaWikiRefCard.pdf|Reference Card]] of MediaWiki on the [[metawikipedia:|Meta Wikipedia]].<br />
* [[RoboWiki:ReadMe|Readme]] page.<br />
If you need [[Help:Help|help]], check out the [[Robocode/FAQ|frequently asked questions]] or ask it on this page. Again, welcome!<br />
<br />
—— RoboWiki Administrators <br />
|}<br />
<br />
Welcome to the robowiki :) --[[User:Rednaxela|Rednaxela]] 15:22, 23 April 2010 (UTC)<br />
<br />
Thank you =) --[[User:Urgood2|-- Josh S]] 08:35, 24 April 2010 (UTC)<br />
<br />
Try using the preview button instead of save to view your result. You have been spamming our [[Special:RecentChanges|RecentChanges]] list! --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 12:35, 26 April 2010 (UTC)<br />
<br />
Sorry... Got you. --[[User:Urgood2|-- Josh S]] 14:17, 26 April 2010 (UTC)<br />
==[[User:Urgood2]]==<br />
*Newbie to Robocode<br />
<br />
I am currently learning Java.<br />
I haven't made any "good" robots yet. <br />
[[User:Urgood2|-- Josh S]] 11:37, 26 April 2010 (UTC)<br />
<br />
Most of us started without a good bot in our sleeves. My first entrance, which defeated 7 others bots at work in melee, ended up on spot 285 out of 300. And see where I stand today. Just set your personal goal within reach and build up from there. Defeating (most of) the samplebots is a good start. Happy robocoding! --[[User:GrubbmGait|GrubbmGait]] 17:57, 25 April 2010 (UTC)<br />
<br />
Well, that's encouraging! I hope I can start to get a grip on things sometime in the future.. --[[User:Urgood2|-- Josh S]] 11:33, 26 April 2010 (UTC)<br />
<br />
Finally got my WallAvoiderBot working. =) The angle adjusting part was testing for only heading 0...<br />
<syntaxhighlight> <br />
//...<br />
double angle = 0;<br />
while (!field.contains(wallStickEnd = <br />
project(myLocation, angle, WALL_STICK))) {<br />
angle += .1 * direction;<br />
} <br />
</syntaxhighlight><br />
I was very frustrated about this, but I finally figured it out.. I replaced the <code>angle</code> argument with <code>getHeadingRadians() + angle</code>. <br />
-[[User:Urgood2|-- Josh S]] 11:33, 26 April 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Starrynte/Melee_Evaluator&diff=16930User talk:Starrynte/Melee Evaluator2010-07-01T08:43:19Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Nice work, I haven't used it because I've been kind of busy lately, but I will try it when I start working on melee again. I was thinking about writing some melee evaluation myself anyway, I already do with 1v1. One question though, why do you have<br />
<syntaxhighlight><br />
public MeleeEvaluate(){<br />
throw new RuntimeException("YOU MUST SPECIFY EXACTLY ONE (1) ADVANCED ROBOT AS A PARAMETER!"); <br />
}<br />
</syntaxhighlight><br />
<br />
You could simply remove the default constructor, since you have a constructor with parameters Java won't create a default constructor for the class. So a call like <code>new MelleEvaluate()</code> would give compilation error instead of having to wait for a runtime error to find out. --[[User:Zyx|zyx]] 06:35, 14 September 2009 (UTC)<br />
<br />
<br />
Hey - what kind of stuff does this keep track of? I'm curious, but it also seems like it would be good information to add to the page. Also, I don't know if you meant to do it this way, but I think [[Starrynte/Melee Evaluator Source]] should be at [[User:Starrynte/Melee Evaluator Source]] (or, at least, this page and that page should be in the same namespace). One other thought is that you don't really need to change the package name - you can have code from other packages in your bot if you want. --[[User:Voidious|Voidious]] 17:35, 14 September 2009 (UTC)<br />
<br />
Hmm, I meant to put it there...moved<br />
and it keeps track of<br />
* Survival: The average energy gain during a stage<br />
* Hitrate: The average hitrate during a stage<br />
* Infliction: The average damage inflicted during a stage<br />
* Damage: The average damage encountered during a stage<br />
* Survival up through a stage: How often you survive up to and through an ENTIRE stage<br />
* Survival in a stage only: How often your survive in one SINGLE stage<br />
* Skipped turns: The average number of skipped turns during a stage<br />
* Hit walls: The average number of wall hits during a stage<br />
Though there is occasionally a bug where survival up through stage 1 is different than survival in stage 1 only...still don't know why<br />
--[[User:Starrynte|Starrynte]] 01:13, 15 September 2009 (UTC)<br />
<br />
Ah, very cool. I think it might be good to add that info to the non-talk page, too. =) --[[User:Voidious|Voidious]] 13:44, 15 September 2009 (UTC)<br />
<br />
I just surf by random pages, find this page and I cannot understand, how it works.<br />
In this code:<br />
<syntaxhighlight><br />
static MeleeEvaluate me;<br />
// ...<br />
if(me==null){<br />
me=new MeleeEvaluate(this);<br />
}<br />
</syntaxhighlight><br />
<br />
field "me" is initialized only in first round by current robot instance.<br />
But in next rounds there're will be another instances and result of call to old instance's methods is undifined.<br />
So how it works? May be i don't see or don't know some important issues --[[User:Jdev|Jdev]] 13:20, 3 March 2010 (UTC)<br />
<br />
It's because of the way Robocode's internals work. It's not guaranteed to work, but I think the new instances of the Robot are referencing some of the same stuff as the old instances, so it's usually not a problem. But you should update the Robot reference each round. (/me goes off to check that his bots do this correctly. =)) --[[User:Voidious|Voidious]] 17:30, 3 March 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Starrynte/DCLSHResearch&diff=16929User talk:Starrynte/DCLSHResearch2010-07-01T08:43:18Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>==Various Questions==<br />
===Can't beat Walls?===<br />
OK. I temporarily set the CPU constant to 1 second, just to test this. It currently searches through ALL the points and picks the closest one. Yet it can't beat Walls yet. I believe it's one of the following problems:<br />
* GF implemented incorrectly, though I don't think it is this<br />
* DC implemented incorrectly, a possibility<br />
* Cannot just use the closest point (must use multiple ones), this is also a possibility<br />
* Other?<br />
Thoughts? --[[User:Starrynte|Starrynte]] 04:16, 22 September 2009 (UTC)<br />
<br />
If Wall fire and you don't move, you won't normally beat it with GF gun, at leat in my development. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 06:54, 22 September 2009 (UTC)<br />
* I never knew that! Thanks for the info! --[[User:Starrynte|Starrynte]] 04:02, 23 September 2009 (UTC)<br />
==="Stopping"?===<br />
Occasionally, the bot seems to freeze (the radar stops turning but there is still a scan arc, text output from onscannedrobot stops, gun stops, basically as though the robot was stop except for the radar arc). The other bot keeps moving, robocode reports no errors and no skipped turns and no "robot stopped". It always freezes at the start of the round. I have duplicated this a few times. Any reason why? --[[User:Starrynte|Starrynte]] 04:02, 23 September 2009 (UTC)<br />
<br />
I've never encountered that. What version of Robocode are you using? And have you tried any others? If it's only in the 1.7.1.4 beta, I'm sure Fnl would appreciate it if you filed a bug report [http://sourceforge.net/tracker/?group_id=37202&atid=419486 here]. --[[User:Voidious|Voidious]] 13:15, 23 September 2009 (UTC)<br />
<br />
Could you please post the code? I don't think it is a bug, for that I was once getting this too. It seems that I've some bug in my radar that time. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 15:17, 23 September 2009 (UTC)<br />
<br />
Same thing has happened to me, and in robots so simple that it really shouldn't happen unless there's a bug in the basic radar code--[[User:CrazyBassoonist|CrazyBassoonist]] 20:55, 23 September 2009 (UTC)<br />
<br />
Only radar code is setTurnRadarRightRadians(Double.POSITIVE_INFINITY) in run() and setTurnRadarRightRadians(Utils.normalRelativeAngle((absBearing=e.getBearingRadians()+getHeadingRadians())-getRadarHeadingRadians())*2d) in onScannedRobot<br />
--[[User:Starrynte|Starrynte]] 01:58, 24 September 2009 (UTC)<br />
<br />
Do you have:<br />
<syntaxhighlight><br />
while(true) {<br />
turnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
}<br />
</syntaxhighlight><br />
-- or --<br />
<syntaxhighlight><br />
while(true) {<br />
if (getRadarTurnRemaining() == 0)<br />
setTurnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
// ...<br />
execute();<br />
}<br />
</syntaxhighlight><br />
<br />
Or do you just do:<br />
<syntaxhighlight><br />
setTurnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
while (true) {<br />
// ...<br />
execute();<br />
}<br />
</syntaxhighlight><br />
? If you do the last one, than if you are not moving you might sometimes lost the radar lock, which result exactly the same as your. I'm not sure it is Robocode's bug or not. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 11:16, 24 September 2009 (UTC)<br />
* I have the last one. What doesn't make sense to me is that the scan arc is still there, the radar stopped turning but the arc isn't a line. --[[User:Starrynte|Starrynte]] 01:17, 25 September 2009 (UTC)<br />
** The scan arc is an illusion. It is not updated, nor does scanning happen (even in a line), if a robot doesn't move in the slightest. Ignore that scan arc artifact. As far as why it stops, it's my understanding that when a collision occurs, it not only clears the movement that's set, but also clears gun/radar turns. Thus you need to reset the gun/radar turn. Every properly working infinity lock I see is done with either the first of the methods Nat listed, or with the second minus the if statement which is unnecessary. It it stopping upon a collision occuring? :) --[[User:Rednaxela|Rednaxela]] 02:47, 25 September 2009 (UTC)<br />
** For now I'm using the first one, the second one the if is necessary, otherwise it doesn't lock --[[User:Starrynte|Starrynte]] 02:53, 25 September 2009 (UTC)<br />
*** Hm, I'm stuck thinking in MegaBot land, where radar processing happens outside of the onScannedRobotEvent event. The 'if' in the second one is not needed IF your radar/scan processing happens between it and execute, which isn't usually the case in small codesize bots. --[[User:Rednaxela|Rednaxela]] 03:01, 25 September 2009 (UTC)<br />
**** But in most megabots, radar processing also happens in onScannedRobot(). Normally the first method is use, the second one only use for robots that have some process in main loop too. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 11:37, 25 September 2009 (UTC)<br />
***** Most megabots eh? I'd say... most non-modular ones maybe. Doing actual processing ouside of the main loop to me seems like a recipe for making the code unclear and tangled up. --[[User:Rednaxela|Rednaxela]] 12:34, 25 September 2009 (UTC)<br />
****** But a lot of megabots use onScannedRobot as its main loop in one-on-one. And Dookious, as one of the modular megabots, have only the second method radar code in its main loop! I used to do things in main loop, but once I start to use debugging graphics, I switch to onScannedRobotEvent, or in case of my current development, a CustomEvent with priority of 6. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:04, 25 September 2009 (UTC)<br />
****** I think it's split pretty evenly. A fair number of 1v1 bots do processing on onScannedRobot, because why not? All [[User:PEZ|PEZ]]'s duelists and [[Dookious]] are among them. Any bot that was ever intended to have melee support is sure to do most real execution in the main loop instead. --[[User:Voidious|Voidious]] 13:09, 25 September 2009 (UTC)<br />
<br />
===Dealing with Surfers===<br />
I've tried segmenting on gunheat, but it leads to worse performance against non-surfers. No space for a VG array. Any other suggestions? --[[User:Starrynte|Starrynte]] 04:27, 24 September 2009 (UTC)<br />
* Is it unusual for results to vary a lot across seasons? Since for example against CC I get scores ranging from 47 to 65 and against WLO I get 52 to 78 --[[User:Starrynte|Starrynte]] 04:59, 24 September 2009 (UTC)<br />
** Very normal. In fact even larger variations are things I regularly see. It takes many many many seasons to really get stable results against surfers (100+ seasons I'd say) --[[User:Rednaxela|Rednaxela]] 05:09, 24 September 2009 (UTC)<br />
<br />
In a MicroBot? My advice would be to ignore the surfers. =) But in general, rapid decay or removal of data is probably the most important thing. This would be low [[Rolling Averages]] in a [[Visit Count Stats]] system. In [[Dynamic Clustering]] (or even the k-means in [[TripHammer]]), removing oldest scans works, or weighting scans based on age. --[[User:Voidious|Voidious]] 13:25, 24 September 2009 (UTC)<br />
* Seems to help. Now to experiment with weighting, which I'm not using yet... --[[User:Starrynte|Starrynte]] 02:43, 25 September 2009 (UTC)<br />
<br />
A few questions....<br />
: 1. On the AntiSurferTargeting page of the old wiki, it suggested decrementing slightly when you actually hit the enemy. How would you do that in [[Dynamic Clustering]]?<br />
: 2. Somewhere else on the old wiki, it said that you should count the waves 2-3 ticks before firing time as the firing waves. Why?<br />
: 3. Any codesize-friendly way to get the closest, say 3 points from a set of points? (Keep in mind the set of points won't be large, at max probably 1000 points, so speed isn't TOO big of an issue)<br />
: 4. Any recommendation for changes in the segments (currently lateral velocity, distance from center, distance from me)?<br />
--[[User:Starrynte|Starrynte]] 01:19, 29 September 2009 (UTC)<br />
<br />
: My thoughts:<br />
:# I use multiple sets of scans in my DC Anti-Surfer gun. One of them is collected from bullet hits, and I give those a negative weight in the kernel density calculation. Basically, a potential firing angle is penalized for being near a bullet hit firing angle. Doesn't sound very code size friendly, though.<br />
:# If you fire and turn your gun on the same tick, the firing happens first. So the segmentation data on the wave should be from the tick before it is fired, because that's how it will be when you actually fire.<br />
:# Not really. =) I have a [[MiniBot]] DC gun still lying around, but the part that gets the closest scans is pretty big.<br />
:# I'm not sure distance to center is very useful in 1v1. Accel is a good one (whether the enemy accelerated, decelerated, or stayed same speed since last tick), and so are time since velocity change and wall distance.<br />
: --[[User:Voidious|Voidious]] 01:37, 29 September 2009 (UTC)<br />
* Which leads to the question, any easy way to find wall distance (particularly codesize)? --[[User:Starrynte|Starrynte]] 02:07, 29 September 2009 (UTC)<br />
<br />
:: The smallest way would probably be <code>Math.min(Math.min(enemyX, battleFieldWidth - enemyX), Math.min(enemyY, battleFieldHeight - enemyY))</code>, which is the shortest distance to any wall. The smallest "good" way (imo) I know of to do it can be snagged from [[Komarious/Code]], which basically tests if a bearing offset projected <code>enemyDistance</code> from my bot would be out of bounds or not. --[[User:Voidious|Voidious]] 02:21, 29 September 2009 (UTC)<br />
<br />
===Lateral Acceleration===<br />
What is the maximum possible lateral acceleration, taking into account the fact that robocode is tick-based? --[[User:Starrynte|Starrynte]] 04:22, 26 September 2009 (UTC)<br />
<br />
Max lateral acceleration is 1 pixel per tick, and max lateral deceleration is 2 pixels per tick. Just look at the formula, if the angle inside the sin() is PI/2 (or 90 degrees), ie. they are going perpendicular, then it is exactly the same as regular acceleration/deceleration. --[[User:Skilgannon|Skilgannon]] 05:59, 26 September 2009 (UTC)<br />
<br />
No, it's not the same Skilgannon. Consider the situation where a bot is moving at 8 speed perpendicular. In order to decelerate it can reduce it's speed by 2 units, AND it can also simultaneously rotate away from perpendicular in order to reduce the lateral velocity even further. --[[User:Rednaxela|Rednaxela]] 04:00, 29 September 2009 (UTC)<br />
<br />
[[Rednaxela]] is right, I once calculated those values, but don't have them anymore. But they where somewhere around [2.02, 1.02]. --[[User:Zyx|zyx]] 01:28, 30 September 2009 (UTC)<br />
<br />
: I went ahead I try to figure them out again, this is the C++ code I used.<br />
<syntaxhighlight><br />
double max_deccel = 0, dsv, dev;<br />
double max_accel = 0, asv, aev;<br />
const double delta = 1e-5;<br />
const double pi = acos(-1.);<br />
for ( double x = 2; x < 8; x += delta ) {<br />
double y = x - 2;<br />
double vx = x * sin(pi / 2);<br />
double vy = y * sin(pi / 2 + pi / 18 - y * pi / 240);<br />
if ( vx - vy > max_deccel ) {<br />
max_deccel = vx - vy;<br />
dsv = x;<br />
dev = y;<br />
}<br />
}<br />
for ( double x = 0; x + 1 - 1e-9 < 8; x += delta ) {<br />
double y = x + 1;<br />
double vx = x * sin(pi / 2 - pi / 18 + y * pi / 240);<br />
double vy = y * sin(pi / 2);<br />
if ( vy - vx > max_accel ) {<br />
max_accel = vy - vx;<br />
asv = x;<br />
aev = y;<br />
}<br />
}<br />
printf("lat deccel (%.4f -> %.4f): %.10lf\n", dsv, dev, max_deccel);<br />
printf("lat accel (%.4f -> %.4f): %.10lf\n", asv, aev, max_accel);<br />
</syntaxhighlight><br />
: The results are<br />
<pre><br />
lat deccel (6.4478 -> 4.4478): 2.0300517561<br />
lat accel (4.1138 -> 5.1138): 1.0237884289<br />
</pre><br />
: This maximums are achieved at rather odd velocities (6.4478, 4.1138) those aren't lateral velocities but actual velocities. Changing delta to 1, uses only integer values for speed, and the maximums are:<br />
<pre><br />
lat deccel (6.0000 -> 4.0000): 2.0298153934<br />
lat accel (4.0000 -> 5.0000): 1.0237746471<br />
</pre><br />
<br />
: Hope this helps. --[[User:Zyx|zyx]] 01:53, 30 September 2009 (UTC)<br />
* It does, in fact, thank you! As for the "odd" velocities, it isn't that odd I think because if you're going slower you can turn faster. --[[User:Starrynte|Starrynte]] 02:08, 30 September 2009 (UTC)<br />
* Hmm, actually the theoretical maximum decel is 8, since if you're going full speed and you hit a wall, you could go from 8 to 0. --[[User:Starrynte|Starrynte]] 03:25, 30 September 2009 (UTC)<br />
<br />
Does assuming the direction is 1 when the enemy isn't moving cause a large performance hit, compared with assuming the direction is the last "good" lateral velocity?<br />
--[[User:Starrynte|Starrynte]] 02:08, 30 September 2009 (UTC)<br />
<br />
Well, it probably depends on your gun, but it certainly could confuse your gun a lot against a [[Stop And Go]] movement. I'd test against some of the top [[MicroBot]] duelists to see what happens when they orbit you counter-clockwise (particularly if they orbited you clockwise in the previous round(s)). --[[User:Voidious|Voidious]] 02:26, 30 September 2009 (UTC)<br />
<br />
===Max Escape Angle===<br />
Is it better to use a fixed MEA (i.e. asin(8/11) ) or a MEA that depends on enemy velocity (i.e. asin(enemy velocity/11) )? If they're about equal, what are the pros and cons? --[[User:Starrynte|Starrynte]] 05:04, 29 September 2009 (UTC)<br />
<br />
No it isn't the same. Haven't test asin(enemy velocity/11) though. But one BIG problem is when enemy is currently stop, this code will yield zero as an MEA. Now enemy moves, wave hit, and we found that the angle offset is 40°, which is ~GF0.86 (40°/46.6°) with normal MEA, but it is (40°/0°), which is Double.POSITIVE_INFINITY in java, with your variable MEA. You see the point. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 12:23, 29 September 2009 (UTC)<br />
<br />
Er, I don't think "asin(enemy velocity/11)" makes sense. That would ''only'' make sense if they never exceeded their current speed. If you mean [[Maximum Escape Angle/Precise|MEA via Precise Prediction]] (which does depend on current velocity), then some people seem to think it's good for guns but not for surfing. I don't think there's any kind of valid MEA that depends on current velocity other than "Precise MEA", or perhaps a variant on standard MEA that doesn't quite use precise prediction but considers how the enemy must accelerate (which would be almost as complicated as "Precise MEA" anyway I think) --[[User:Rednaxela|Rednaxela]] 15:06, 29 September 2009 (UTC)<br />
<br />
Ah yes, I forgot that this is *Max* escape angle :) --[[User:Starrynte|Starrynte]] 01:13, 30 September 2009 (UTC)<br />
<br />
===Shooting out of bounds===<br />
How are angles that potentially shoot out of bounds filtered? Do you just assume the current enemy distance? --[[User:Starrynte|Starrynte]] 05:07, 29 September 2009 (UTC)<br />
<br />
I don't think many bots (not DrussGT anyway) do this. But I know that [[Coriantumr]] uses what you describe. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 12:25, 29 September 2009 (UTC)<br />
<br />
Bots that do "[[Maximum Escape Angle/Precise|Precise MEA]]" cannot shoot out of bounds since the no GF with that scheme can be out of bounds. Many bots don't use that either though (none of mine do) and still have very strong guns. As I see it, if the bot has a decent wall segment (or that "Precise MEA"), then it will tend to avoid shooting out of bounds on it's own without an explicit mechanism. --[[User:Rednaxela|Rednaxela]] 15:01, 29 September 2009 (UTC)<br />
<br />
===Disabled===<br />
What are pros and cons of collecting GF data while disabled? --[[User:Starrynte|Starrynte]] 02:54, 3 October 2009 (UTC)<br />
<br />
Con: Any bot that knows there are no bullets in the air is free to move however they want and "poison" your stats (intentionally or not). Pro: Against any bot that continues to move normally, you are collecting useful data. Personally, I stop firing waves when I'm disabled, but still register ones that were already fired. --[[User:Voidious|Voidious]] 03:01, 3 October 2009 (UTC)<br />
<br />
== Comparison to segmentation ==<br />
<br />
Your description of translating a data point into a bin reminds me of [[segmentation]] and [[Visit Count Stats]]. I'm curious - could you give any more details on how this works, and/or how it's different than segmentation? --[[User:Voidious|Voidious]] 13:15, 23 September 2009 (UTC)<br />
<br />
It actually is similar to segmentation, only rather than having say stats[VELOCITY_SEGMENTS][DISTANCE_SEGMENTS][WALL_SEGMENTS][etc...], you'd have just stats[COMBINATION OF VELOCITY, DISTANCE, WALL, ETC]. The combination is the LSH process. --[[User:Starrynte|Starrynte]] 02:03, 24 September 2009 (UTC)<br />
<br />
== Maybe not a first? ==<br />
<br />
You know... I think that maybe this isn't the first Locality Sensitive Hash targeting in Robocode. Doesn't [[Locke]]'s description seem to sound like a form of locality sensitive hash targeting? It does say "Along with that Observation, a number of situational parameters are stored. The Log is ordered in such a way that similar Observations will become neighbours." and once looking at the code I noticed it stored things in a 1d list which it tried to order to preserve locality. --[[User:Rednaxela|Rednaxela]] 04:29, 24 September 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Rednaxela/kD-Tree&diff=16928User talk:Rednaxela/kD-Tree2010-07-01T08:43:10Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>So this mean I can use it int close-sourced robot? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:24, 25 August 2009 (UTC)<br />
: Yep, so long as you don't misrepresent it's origin (i.e. claim you wrote the kd-tree in use) :) --[[User:Rednaxela|Rednaxela]] 13:29, 25 August 2009 (UTC)<br />
: You used to say that it will be licensed under RWPCL and CC-BY, but I'm more happy with this though, for that I can release the code under more tricky way than usual in-jar method =) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:25, 25 August 2009 (UTC)<br />
: I decided I wanted to avoid as much complication as possible, and I found the zlib licence. Since I don't mind how people use it so long as they don't make false claims to have written it, and it doesn't conflict with the RWPCL (i.e. can be used in RWPCL bots), it seemed like a good match. I removed one clause that I deemed unnecessary. It seems reasonable to me :) --[[User:Rednaxela|Rednaxela]] 14:46, 25 August 2009 (UTC)<br />
<br />
I just tried this tree, and I'm getting problems where every now and again an Entry will have a null value in it. I've got workaround code for it, but I know it shouldn't be doing that, and I'm not sure why it is. Also, DrussGT is ''still'' skipping a LOT of turns with this tree, so I'll have to find a dimension or 3 to cull... I could even run 2 trees with 8 dimensions in less time than my 1 tree with 11. Oh yes, I changed the 2 distance functions to be Manhattan distance, but that shouldn't affect things too much. --[[User:Skilgannon|Skilgannon]] 18:21, 26 August 2009 (UTC)<br />
<br />
: Huh... that seems odd. I don't see why null entries could ever happen, I'll look into it when I get home. As far as DrussGT skipping a lot of turns still, I assume you don't mean any turns than normal do you? And yeah, even a few dimensions will make a huge difference with any kd-tree. --[[User:Rednaxela|Rednaxela]] 18:33, 26 August 2009 (UTC)<br />
<br />
: Yeah, I know it passed all the benchmarks etc. so I'm not sure what's going on. Maybe look in DrussGT 1.3.10wilo for the version I'm using if you want to test it. Lines 614 to 618 of DrussGunDC.java are where my workaround is (basically just removing all Entries with null values from the cluster). If I take that out it starts throwing errors every few rounds. (Note: just to prevent any confusion, due to me adding the first workaround - just skipping null values in the loop - it now throws the errors down on line 663 when it sorts the Indices instead of in the loop when trying to access the data inside the null value). Thanks for any light you can shed on this =) --[[User:Skilgannon|Skilgannon]] 18:55, 26 August 2009 (UTC)<br />
<br />
: Aha! I haven't tested it yet, but [http://robowiki.net/w/index.php?title=User:Rednaxela/kD-Tree&curid=1927&diff=11157&oldid=11123 this] should fix the nulls. :) --[[User:Rednaxela|Rednaxela]] 19:23, 26 August 2009 (UTC)<br />
: Oh, and also, this bug may do more than cause nulls: It may cause duplicate entries in some cases I suspect, so it may affect the results of jk.mega.DrussGT 1.3.10wilo. I don't think it wouldn't affect the results of RougeDC willow though because I'm pretty sure that bug was introduced after. --[[User:Rednaxela|Rednaxela]] 19:29, 26 August 2009 (UTC)<br />
<br />
I believe I have found the following problem, Arrays.copyOf is only supported since Java 6.0, so your code can't be compiled/run under earlier versions of Java. --[[User:Positive|Positive]] 22:49, 27 August 2009 (UTC)<br />
<br />
: Haha, Fnl also noticed that earlier today. Fixed and tested to have no/negligable affect on performance :) --[[User:Rednaxela|Rednaxela]] 00:10, 28 August 2009 (UTC)<br />
<br />
Hey Rednaxela, good job! One thing that you might improve the speed on (if I understand your tree correctly) is the sqrPointRegionDist function. You don't need to recalculate all distances between bounds and the point, only between the *changed* bound since last check. If that makes sense. :) Also, I think it would be nice to have another version of the tree which doesn't apply weighing while searching. In any case, it's a very nice piece of code, and I'm going to try to use it in Portia (thanks to your license!). :) --[[User:Positive|Positive]] 21:45, 27 August 2009 (UTC)<br />
<br />
: Hmm... you're right, that is an optimization that could be done, that is, if the overhead of caching it doesn't outweigh the benefit. I think in order to implement that I'd need to either store temporary values in the nodes, or maintain a third stack that remembers the distance of it's bounds. I'll give it a try and keep that change if it's worth it, haha. As far as a version that doesn't apply weighting, I've considered that however decided it was simpler to maintain a single version. If you want to remove the weighting capabilities, all it takes is 1) Removing the 'weights' variables where they are declared, 2) Removing the reference to them in the distance functions, and 3) Remove the couple statements that set it. Though, I suppose that if changes to the tree cease to happen for a long time I'll post the version with weighting removed as well, I just don't want to be worrying about them getting out of sync while it's in (semi-)active development. Anyways, I'm glad it's liked :) --[[User:Rednaxela|Rednaxela]] 00:10, 28 August 2009 (UTC)<br />
<br />
:: Okay, that makes sense. I have some other feature requests: A size() function to keep track of how many entries there are in the tree, and it'd be cool if there was something to make sure the size stays below a certain point. A possible problem might be the line with ''tree.weights = weights;'', because it doesn't reset the weights afterwards. Also, I'd selfishly like the addPoint functions and such to be nonstatic and without the KdTree<T> tree parameter (but I suppose that is a matter of taste). :P --[[User:Positive|Positive]] 01:03, 28 August 2009 (UTC)<br />
<br />
:: Alright, I gave that optimization of calculating the node distance as-needed from the splits a try. The result is that: 1) If replace the existing calculating of the distance to the tight boundary, the performance is worse, and 2) If I just use it to shortcut past the full distance to tight boundary calculation, the performance is about the same. This indicates to me that 1) Calculating the exact tight-boundary disance for nodes eliminates a rather significant number of node visits, and 2) The overhead of tracking the data for split-based node distance is large enough that it's not worth it to use it as a shortcut. --[[User:Rednaxela|Rednaxela]] 06:23, 1 September 2009 (UTC)<br />
<br />
::: Keeping the weights across calls I considered desired, but it was a bad API for it. It's now split into a setWeights() call. Haha, I don't know what I was thinking when I made the addPoint and nearestNeighbours functions static, I was in a strange mindset when I first wrote this beast. They're now non-static and tested to have no impact on performance. I'm not sure what you mean by "make sure size stays below a certain point". Do you mean removing old points? --[[User:Rednaxela|Rednaxela]] 03:39, 28 August 2009 (UTC)<br />
<br />
:::: Great. :) Yes, that's exactly what I meant. It seems usefull and safe to have some kind of deletePoint function and perhaps a built-in linked list system to remove old entries, so that the data stays up to date & won't eventually fill up the memory. --[[User:Positive|Positive]] 03:48, 28 August 2009 (UTC)<br />
<br />
:::: Well... support for an optional limit on size is now supported. Deleting arbitrary points however, is not supported, because that would conflict with the size limit since it would be far too painfully slow to remove that point from the linked list that tracks the the order that points were added in. Also, to make sure this doesn't impact speed normally, that list is never even created if no limit was specified. Anyways, the size of the code is getting closer to 500 lines than I'd like it to, so I think this is enough non-optimization features for any sane usage of it. --[[User:Rednaxela|Rednaxela]] 04:45, 28 August 2009 (UTC)<br />
<br />
I don't know if this is standard or not, but it seems strange that the constructors isn't the very first method in the class. And the method/sub-class ordering is more like... DrussGT's =) They are now ordering by the time you added the code and where, aren't they? I know it isn't going to improve the execution speed, but... &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:40, 28 August 2009 (UTC)<br />
<br />
: Nah, not ordered by the time added at all. At one point I had the functions for 'bounds' grouped beside the variables, but they kind of drifted apart. There wasn't any real reason for the ordering except that nearby things often had some relevance to eachother. Reformatted that a bit now as to be saner and maintain that relevance-ordering :) --[[User:Rednaxela|Rednaxela]] 14:56, 28 August 2009 (UTC)<br />
<br />
I've been testing with the pre-limit version of your tree in Portia, and it seems to be working. :) Now with your new version, I do get an error at line ''double[] location = this.locationStack.pop();'': (''The method pop() is undefined for the type LinkedList<double[]>''). --[[User:Positive|Positive]] 15:53, 28 August 2009 (UTC)<br />
<br />
: Ugh... Any reason why you're on ancient Java 5? Anyway, that method in LinkedList only exists in 6 not 5. Making it Java 5 compatible again... --[[User:Rednaxela|Rednaxela]] 16:11, 28 August 2009 (UTC)<br />
<br />
:: Haha, actually I'm on Java 6. I compile everything using the Java 5 library though, so I know for sure I don't make code that's not Java 5 compatible. :) --[[User:Positive|Positive]] 16:14, 28 August 2009 (UTC)<br />
<br />
I didn't exactly had time to look at this, but just out of curiosity, does this tree return the scans sorted by distance? By the way, congratulations on your optimization work.--[[User:Navajo|Navajo]] 00:43, 1 September 2009 (UTC)<br />
<br />
: It returns the entries in [[wikipedia:Binary_heap#Heap_implementation|max-heap array ordering]], since that is the most efficent way to construct the list of nearest neighbours. Maintaining a list of "lowest n values" doesn't actually require the list to be fully ordered, it only requires enough ordering that it's easy to throw out the largest value when over the size limit, making a max-heap the perfect structure for the task. It would be fairly simple and fast to convert this to squential order for final output, but I saw no reason to bother with it since I've never seen a DC gun/movement care about the order of the outputs, only the distances associated with them. --[[User:Rednaxela|Rednaxela]] 01:25, 1 September 2009 (UTC)<br />
<br />
: My DC Gun does care about the order of the output. It computes pif angles discarding the ones that end outside the battlefield, so I need to know that I end up with the closest entries possible. --[[User:ABC|ABC]] 10:15, 1 September 2009 (UTC)<br />
<br />
:: Err... I'm not sure I understand... Any sane DC-PIF gun would be discarding result that end outside the battlefield like you say, but it's not as if the order of output affects which ones end up inside/outside the battlefield. The outputted values are ensured the closest entries possible ones, just not in sequential order. I don't see how any gun could sanely care about the output order, but if so, which order would you prefer, ascending or descending? --[[User:Rednaxela|Rednaxela]] 12:39, 1 September 2009 (UTC)<br />
<br />
::: I'm speculating, but maybe he builds a cluster of size M and then tries to keep the best N<M that stay inside the field. But I think that a sorted cluster should be optional as it may impact the performance for most of the tree users with no gain. --[[User:Zyx|zyx]] 13:24, 1 September 2009 (UTC)<br />
<br />
::: Yes, that's exactly what I do. If it's too much trouble I can always sort them myself. --[[User:ABC|ABC]] 14:09, 1 September 2009 (UTC)<br />
<br />
:::: Nah, it's not too much trouble, and as I explain to Nat below, it's quicker for me to get sorted output from the heap than it is for you to sort the data after. I already have this implemented on my computer at home, all I have to do is test how it impacts performance, and if it's measurable, make it optional. --[[User:Rednaxela|Rednaxela]] 14:52, 1 September 2009 (UTC)<br />
<br />
:::: Hey ABC, unlike what you said... Simonton's tree may not always output in descending order always! Reading the code for Simonton's code indicates that it uses a PriorityQueue, and the order it outputs is the same as the iterator of PriorityQueue. If you read the java docs, it very clearly states "<code>The Iterator provided in method iterator() is not guaranteed to traverse the elements of the PriorityQueue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).</code>", therefore if Simonton's tree is currently returning in descending order, then it just happens that your JVM does that. This means that the behaviour of versions of Shadow using Simonton's tree are VM-dependant. But after I make the sorting supported in my tree when I get home, Shadow using my new tree will be able to be sure it's performance is not dependant on the JVM in question. --[[User:Rednaxela|Rednaxela]] 15:21, 1 September 2009 (UTC)<br />
<br />
::::: Thanks for that info! You are a true Java Guru. At the time I just blindly plugged Simonton's tree instead of my brute force method, noticed the entries were "backwards" and adjusted my code accordingly... --[[User:ABC|ABC]] 15:53, 1 September 2009 (UTC)<br />
<br />
::: I don't understand, how the order affect the result of PIF algorithm? On the other hand, returning the sorted data would take O(n log n) time more due the heap, and that definitely effect the bot that doesn't care about the ordering. If we sort them ourselves, it would still take O(n log n). I see no point to add the ordering to the tree, unless, of course, it won't effect the speed. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:23, 1 September 2009 (UTC)<br />
<br />
:::: I want to find the 10 scans closest to the current one that end inside the battlefield. I ask the tree for the 20 closest scans, and then calculate the path for each of them, starting from the closest one, until I get 10 valid ones. --[[User:ABC|ABC]] 14:39, 1 September 2009 (UTC)<br />
<br />
:::: (edit conflict, crossing out redundant things) <del>It was like Zyx said. The numbers are made up but it's like this: Shadow gets the 50 closest entries from the kD-Tree, it then runs PIF on each entry starting with the one with the last distance, '''and''' it stops processing once it has the PIF results of 10 that didn't run into walls. Again, 50 and 10 are made up numbers for sake of example.</del> Also Nat, you're very wrong about the speed there. ''Firstly'', the time taken by reordering the n final results, is MUCH quicker than the nearest-n-neighbours search itself, because O(n log n) only tells you how the speed is multiplied by changing the number of values sorted, it doesn't tell you the base speed, which happens to be far quicker than the base speed of the nearest-n-neighbours algorithm. ''Secondly'', I can make the output results sorted in notably LESS than O(n log n) time. Converting max-heap ordering to sequential ordering, only requires the second part of a [[wikipedia:Heapsort|heapsort]], rather than a full run of a sorting algorithm. --[[User:Rednaxela|Rednaxela]] 14:52, 1 September 2009 (UTC)<br />
<br />
::::: I just checked and your made up numbers (50/10) are exactly what I currently use in Shadow's melee gun. :) --[[User:ABC|ABC]] 15:53, 1 September 2009 (UTC)<br />
<br />
:::::: Is the tree really fast enough to let you query 50 neighbours for all opponents? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 16:01, 1 September 2009 (UTC)<br />
<br />
:::::: Oh wow, my guessing skills are quite good it seems, haha. As far as speed of that goes Nat, I'm pretty sure that in most DC-PIF guns, the PIF takes considerably longer than the DC. --[[User:Rednaxela|Rednaxela]] 16:08, 1 September 2009 (UTC)<br />
<br />
::::: Merge sort, which is default for Arrays.sort() is twice as fast as the heap sort according to my book on algorithms, which has the benchmarking time printed. And the second part of heap sort is still O(n log n), you still need to do down-heapify for ''n'' times. Unless there are faster ways to do it. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:13, 1 September 2009 (UTC)<br />
<br />
:::::: True, the second part of heap sort still scales at a rate of O(n log n) but should be considerably faster than a full heapsort. I may benchmark the difference later, but I'm extremely doubtful that Arrays.sort() could be faster for data that is ''already'' in heap ordering. Plus Nat, one '''very''' important consideration that you leave out, is that in order to use Arrays.sort(), unless you're sorting a simple array of numbers, your input values need to be encapsulated in objects which implement Comparable, and comparisons of Comparable are well over 5x slower than direct numerical comparison due to function call overhead. Avoiding overhead such as that is part of why my tree is just so damn fast ;) --[[User:Rednaxela|Rednaxela]] 15:31, 1 September 2009 (UTC)<br />
<br />
:::::: Oh I see. Completely forget function overhead. Thanks. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:59, 1 September 2009 (UTC)<br />
<br />
I'm not sure where in this page I should post this since there are so many topics here, but anyway, while trying to improve Gibbs I found two situations in which your tree throws exceptions. First is when searching for 0 neighbors. This one I easily solved by adding a simple <code>if(count < 1) return new ArrayList<Entry<T>>(0);</code> at the beginning of the nearestNeighbor method. The second problem is when you limit the tree size to something smaller than bucketSize. When the method removeOld() is called it throws a NullPointerEception when checking the condition of the following loop<br />
<code><syntaxhighlight><br />
do {<br />
cursor.locationCount--;<br />
cursor = cursor.parent;<br />
} while (cursor.parent != null);<br />
</syntaxhighlight></code><br />
which is easily solved by changing it to<br />
<code><syntaxhighlight> <br />
while (cursor != null){<br />
cursor.locationCount--;<br />
cursor = cursor.parent;<br />
}<br />
</syntaxhighlight></code><br />
I know these problems are quite specific and easy to solve, but I just felt like I should report them. Also, if it is not much of a trouble, could you please add an option to remove the closest scan instead of the oldest? --[[User:Navajo|Navajo]] 01:15, 13 April 2010 (UTC)<br />
<br />
Well, the version currently posted on this page I kind of consider deprecated in favor of my [http://bitbucket.org/rednaxela/knn-benchmark/src/tip/ags/utils/dataStructures/trees/thirdGenKD/ new version]. The new version is slightly faster, is more flexibly coded, happens to behave right for the zero-sized search, and adds an additional feature of providing an iterator for allowing incremental search (but still best to specify an explicit max search size for performance reasons). On the other hand, the new tree doesn't yet have this support for removing old/close data. I could add this to it shortly if there is demand though. Would you want to use that Navajo? :) --[[User:Rednaxela|Rednaxela]] 01:59, 13 April 2010 (UTC)<br />
<br />
I'm planning to test the impact of removing the closest instead of the oldest scan, but I can add this feature to the tree myself if it is too much of a trouble to you. --[[User:Navajo|Navajo]] 03:12, 13 April 2010 (UTC)<br />
<br />
== Warning! Rounding Errors! ==<br />
<br />
Argh! It seems rounding errors are evil! Evil evil evil! I was toying with my tree in a very lightly segmented gun where exact-same-locations will occur frequently and it did that stupid rampent/infinite branching again. The cause? It turns out to be rounding, indicated by this excerpt from some debugging messages.<br />
<pre><br />
...<br />
Split Dimension: 1, Split Value: 1.0, Range: 0.9999999999999999 to 1.0, Width: -1.1102230246251565E-16<br />
Split Dimension: 1, Split Value: 1.0, Range: 0.9999999999999999 to 1.0, Width: -1.1102230246251565E-16<br />
Split Dimension: 1, Split Value: 1.0, Range: 0.9999999999999999 to 1.0, Width: -1.1102230246251565E-16<br />
Split Dimension: 1, Split Value: 1.0, Range: 0.9999999999999999 to 1.0, Width: -1.1102230246251565E-16<br />
Split Dimension: 1, Split Value: 1.0, Range: 0.9999999999999999 to 1.0, Width: -1.1102230246251565E-16<br />
Split Dimension: 1, Split Value: 1.0, Range: 0.9999999999999999 to 1.0, Width: -1.1102230246251565E-16<br />
...<br />
</pre><br />
When the only values in the dimension were 1.0, and just ''BARELY'' below it, the splitValue would be set to the average of those two values. Due to rounding errors, the average happened to be the same as the higher value... causing the tree to lump all values into the left child node and try branching again, and again, and again :(<br />
<br />
So as a warning to those currently using the tree, this obscure sitaution could cause the tree to lock up... I'll release a fix soon --[[User:Rednaxela|Rednaxela]] 00:54, 30 August 2009 (UTC)<br />
<br />
: [[User:Simonton|Simonton]]'s fix to this was to only allow his tree a certain recursive depth (he used 500), after which it would start throwing away values. This way it was also (sort of) possible to have a tree with 'rolling averages' by setting the max recursive depth very low. However, it's more of a bandaid then a fix for the root of the actual problem. --[[User:Skilgannon|Skilgannon]] 13:03, 30 August 2009 (UTC)<br />
<br />
:: No, he didn't use 500. ''We'' use 500 ourselves. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:29, 30 August 2009 (UTC)<br />
<br />
:: For this particular issue, that would indeed be a very very poor bandaid, and anyways I have a proper fix in place now. As for having a limit on tree size, I very strongly prefer the limit on the number of entries I have implemented. While it won't put a hard limit on tree depth or nodes it will generally to keep it within reasonable bounds and will always toss out old data in the exact order it was entered in. --[[User:Rednaxela|Rednaxela]] 16:07, 30 August 2009 (UTC)<br />
<br />
Well, this sucks, I thought I could fix it simply by making a > into a >= because I thought it always would round one way.... turns out it doesn't... it rounds whatever way it's in the mood for it seems.. bah. Oh and by the way ABC, curse Shadow for hitting such almost-1.0 velocitities as to cause rounding issues :P --[[User:Rednaxela|Rednaxela]] 02:22, 30 August 2009 (UTC)<br />
<br />
I'm sure there are lots of ways to deal with this, but just a comment on how my insert method handles a similar situation. Values less than the split go to the left, values greater go to the right, and values equal to the split go to alternating sides. One other implication is that when removing a node, you have to check both sides when the value is equal to the split value, but that's easy enough. --[[User:Voidious|Voidious]] 02:33, 30 August 2009 (UTC)<br />
<br />
: I guess if you had 19 0.9999's and one 1.0 and it used 1.0 as the split, you'd still have this problem unless the first alternating side also alternated. So I suppose a different special case would probably work a lot better. Another thing that sucks about this, at least if you use the tree the way I do... Rounding every number to, say, 10 digits seems pretty reasonable, but I wouldn't want to do that either, because I count on the fact that the neighbors returned from the tree are the same exact objects I inserted. :-/ --[[User:Voidious|Voidious]] 02:43, 30 August 2009 (UTC)<br />
<br />
(edit conflict) I saw that alternating approach, but I really don't like that approach for several reasons. It increases the balance of the tree very slightly, but it comes at the cost of making each node wider than they need to be. Not only deletes have to search more nodes Voidious, but seraches as well. For example, presume a dimension only has values of 0.0, 0.5, and 1.0 and the first split in the tree is at 0.5. Then the full search has to be repeated completely on both sides, and thus could have a huge impact if such a split happens to be the first split in the whole tree. ''Anyways'', I now have a fix, the solution is: If split value is equal to the maximum node value (will only occur if they're so close that no Double value between could exist), then it sets the split value to the minimum node value instead which guarantees some values will be put in each node. Extensive testing is showing this is working quite nicely :) --[[User:Rednaxela|Rednaxela]] 02:48, 30 August 2009 (UTC)<br />
<br />
: Ah, cool. I agree it can unbalance the tree, but I don't think it makes searches any slower (otherwise). Mine definitely doesn't account for the equal-to-split edge case in its "findLeaf" - I recall thinking it would need to account for that, then realizing it didn't. <br />
: When coming back up the tree, you test if the other side of the tree could have a node with a distance to the search point that is lower than some threshold. Since the value could be infinitely close to the split value, you have to just assume it is the split value, right? So while you may take a wrong turn while descending the tree if you hit values equal to the split value, you'll check the other side on the way back up, which you're just as likely to have had to do anyway. In your example, you'd need to search the other side anyway - know what I mean? It's been a while since I wrote my tree, maybe I'm misunderstanding something... =) But I'm pretty sure it's just as accurate and just as fast for searches. <br />
: Deletes need to find an actual value that's already in the tree, though, which is a different scenario. (And I don't particularly care how fast deletes are.) --[[User:Voidious|Voidious]] 03:11, 30 August 2009 (UTC)<br />
:: Which reminds me, I actually wrote this case for another scenario, which might be a problem in your current solution, too: if all the nodes have the same value for the split dimension. --[[User:Voidious|Voidious]] 03:19, 30 August 2009 (UTC)<br />
::: I presume you mean all entries, not all nodes. In that case yes, I ''already'' deal with that case. I always set the split dimension to the widest dimension, and whenever "widest" is still 0 width, then it will simply double the bucket size for that particular node. My logic is that the scenario you describe could only happen with "split on widest dimension" when that all entries are in ''exactly'' the same spot, in which case there could never ever be any performance gain by putting them in seperate nodes. On a related note, one possible optimization I could also do with this, would be giving such nodes a special marking and avoiding redundent distance calculations in them. I haven't bothered with that yet though since I doubt it would occur often in practice with a well-segmented gun. --[[User:Rednaxela|Rednaxela]] 04:51, 30 August 2009 (UTC)<br />
:: Actually Voidious, in my tree checking the other side anyway wouldn't happen. I keep track of an extra-tight bounding box for each node and compare to that, and due to how my splitting doesn't alternate, the tight bounding box will never overlap on the split value actually. So.. you're right about some trees, but not my one :) --[[User:Rednaxela|Rednaxela]] 04:51, 30 August 2009 (UTC)<br />
<br />
== Some major changes ==<br />
<br />
Man, this tree keeps taking away from time to finish my melee gun, but anyways: I've done a major update now which gives the tree a bit nicer and more flexible of an API. In particular, you now construct it with things such as <code>new KdTree.SqrElucid<T>(dimensions, sizeLimit)</code> or <code>new KdTree.WeightedManhattan<T>(dimensions, sizeLimit)</code> instead of <code>new KdTree<T>(dimensions, sizeLimit)</code> and modifying the distance function in your copy of the code (I'm looking at you [[User:Skilgannon|Skilgannon]] :)). This also makes it easy to use the unweighted version which is faster by 5-10%. One interesting note I found, is that while Manhattan distance is less complicated to calculate, it makes it harder for the tree to eliminate branches and thus is twice as slow (Looking at you again [[User:Skilgannon|Skilgannon]], considering your recent concerns with DrussGT's speed). What do people think? I'm also considering making a stripped down 'lite' version with no weighting, only sqrElucid distance, some of the more agressive and less significant optimizations removed, no size limiting, and be nearly as fast. --[[User:Rednaxela|Rednaxela]] 05:52, 2 September 2009 (UTC)<br />
<br />
Hmm, so using Manhattan approximately doubles the number of branches that must be recursed? Is this dimension-dependent, ie., would the fact that I'm using 11 dimensions make this a factor of more than 2? I'd gladly switch to using Euclidean distance to get this speed increase, but from what I've found, my gun scores significantly better using Manhattan distance. The difference between the two is about 0.5 worth of [[TCRM]] score. I'm guessing that how my dimensions are defined somehow favors the use of Manhattan over Euclidean, but I don't currently have the time to tweak my segments into a form that works well for Euclidean instead =) Another point, for bots that only use one weighting scheme throughout the match, isn't it quicker to multiply the point by the weighting before storing it, and then afterwards treat the dimensions as unweighted? This is what I've been doing in DrussGT since way back when... it also means that I can apply non-linear weightings without any performance hit at runtime. --[[User:Skilgannon|Skilgannon]] 08:50, 2 September 2009 (UTC)<br />
<br />
: I didn't run an exact count of the number of branches that must be recursed, but since the time taken is doubled, I feel pretty sure the number of branches recursed is at least doubled. It being possibly dimension-dependant might indeed be the case but I don't think 11 dimensions would make it more than my test showed, since my test was with the 13-dimension data recorded from Diamond. About weighting: yes, of course it's quicker to multiply the point by weighting it before storing it. The weighted versions of the tree are only intended for bots which do dynamic weighting, like Diamond does (melee weighting vs 1v1 weighting). Static weighting is considered to be something that bots are responsible for doing when they create their dimensions in the first place. --[[User:Rednaxela|Rednaxela]] 12:42, 2 September 2009 (UTC)<br />
<br />
I haven't tested it yet, but I would like to say, fantastic job! This definitely gives "everyone what he/she wants". I only wonder, don't abstract classes make the tree that much slower (because of the overhead in having to decide which distance() function to use for example)? I'm not a java expert, so it might be that that is optimized at runtime. --[[User:Positive|Positive]] 14:29, 2 September 2009 (UTC)<br />
<br />
: Thanks! I was unsure about that myself at first, but I tried it, gave a it a good performance test, and it performed exactly the same it seemed, at least in Java 6 (I don't know for certain but old enough VMs I bet wouldn't perform equally with them). In fact, the slight tweak of having the distance functions read 'weights' from the class instead of passing it in as an argument seemed to cause this revision to have a very slight improvement in performance. --[[User:Rednaxela|Rednaxela]] 14:44, 2 September 2009 (UTC)<br />
<br />
:: Great, you've really done your homework. :) I just looked over the code, and one little thingie: It seems to me you could use a regular "int" for sizelimit instead of Integer. (You can check for sizeLimit==0 in instead of sizeLimit==null). Might give a small improvement. :P --[[User:Positive|Positive]] 14:58, 2 September 2009 (UTC)<br />
<br />
::: Hmm, true I could do that. That wouldn't have much of a performance impact though I'd think, considering how <code>== 0</code> and <code>== null</code> would be the same speed and the numerical comparison when actually checking the value only happens once per insertion call. I might make the change anyway though, considering the way I'm not really fond of the wrapper classes like Integer to begin with. --[[User:Rednaxela|Rednaxela]] 15:09, 2 September 2009 (UTC)<br />
<br />
I know I shouldn't burden you with any more feature requests, but I'd really like the following extension to your tree (because it is a lot less elegant to do outside of the class): As an addition to ''nearestNeighbor'', I'd like to give an argument like ''(double)acceptedLowest[],(double)acceptedHighest[]'', that prevents the tree from returning any matches with a dimension value outside of the specified range. (That feature would be awesome in a new sologun I'm trying to make for Portia!) --[[User:Positive|Positive]] 19:45, 2 September 2009 (UTC)<br />
<br />
: Hmm... well... that would be easy enough to add, except for one issue: The proper/efficient way to implement it would require a '''third''' distance function: Longest distance from a point to the inside of a region. I think the subclasses that implement the distance calculations are rather bloated/repetitive as it is really, without having to add that as well. So yeah, feel free to modify it for your usage, but adding that particular feature to the main version just adds too much bulk I think. --[[User:Rednaxela|Rednaxela]] 00:24, 3 September 2009 (UTC)<br />
<br />
:: Well... I gave it a good try but couldn't work the bugs out of it, nor were perliminary performance indications looking promising. --[[User:Rednaxela|Rednaxela]] 15:37, 5 September 2009 (UTC)<br />
<br />
== Spelling ==<br />
<br />
Isn't 'Elucidian' supposed to be 'Euclidean'? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:46, 5 September 2009 (UTC)<br />
<br />
: Yep, you're right :) --[[User:Rednaxela|Rednaxela]] 15:37, 5 September 2009 (UTC)<br />
<br />
== help with the Java ==<br />
<br />
Hi Rednaxela, I'm interested in learning your kdTree and playing with the possible applications. I was wondering if you or someOne might point me in the direction of an open source bot that uses your Tree... robocode is my only experience programing , a proper example of it implemented would greatly help and make my learning curve alot more fun. Thx --[[User:Jlm0924|Jlm0924]] 20:04, 17 September 2009 (UTC)<br />
<br />
[[User:Skilgannon|Skilgannon]] uses it in [[DrussGT]], which is open source. --[[User:Voidious|Voidious]] 22:06, 17 September 2009 (UTC)<br />
<br />
: Oh, and [[RougeDC]] (willow) does too, of course. =) --[[User:Voidious|Voidious]] 22:26, 17 September 2009 (UTC)<br />
<br />
: I wouldn't recomend RougeDC willow as a reference for usage of this kD-Tree, as it still used an old (and subtly buggy) version. [[DrussGT]] would be a good example indeed. When I get around to releasing [[Glacier]] that will also be an example. --[[User:Rednaxela|Rednaxela]] 23:02, 17 September 2009 (UTC)<br />
<br />
: Yeah, take a look at [[DrussGT]]. I use it in two different places, both the gun and the movement. In the gun it is used to find similar situations for finding an angle to shoot at. In the movement it is used to guess the bullet power the enemy will use to fire. Once you've extracted the source look at jk/mega/dgun/DrussGunDC.java and search for 'heapTree'. It should be fairly obvious where I create the tree, where I'm adding the data to the tree and where I retrieve the data from the tree based on how close it is to the current scan. Perhaps it would even be good to write a simple gun showing how the various trees are used, as a reference. --[[User:Skilgannon|Skilgannon]] 09:08, 18 September 2009 (UTC)<br />
<br />
: I think having a simple reference implementation is a really good idea. Though if by "various trees" you mean including those besides Rednaxela's, right now I'm not sure why anyone would choose anything else. =) I'm already debating optimizing mine or just switching to his. --[[User:Voidious|Voidious]] 13:02, 18 September 2009 (UTC)<br />
<br />
: I'm taking a look now... a couple of reference implementations in a simple bot would be a gold mine though ! DrussGt is overWhelming to me :) I get some sleep and take a better look :) Thx guys --[[User:Jlm0924|Jlm0924]] 16:00, 18 September 2009 (UTC)<br />
<br />
== sequentialSorting ==<br />
<br />
Hey Rednaxela, still an awesome tree, but perhaps you could add a little note to the tree about how the sequentialSorting works... I only just found out it sorts ''highest'' distance first. :P --[[User:Positive|Positive]] 10:36, 24 September 2009 (UTC)<br />
<br />
Yeah, it might be good to make a note of that somewhere. It was done that way to both 1) Be consistant with how ABC (falsely) throught Simonton's one was working, and 2) That's the order that values can naturally be extracted from the heap)<br />
<br />
: Okay, got it, no problem. I've done a little alteration to your code to turn the order around, all fixed. :) --[[User:Positive|Positive]] 16:34, 24 September 2009 (UTC)<br />
<br />
== Range Search ==<br />
<br />
Can I ask that you add this as well. This is part of some standard KD-Tree implementations in other languages. You can probably read over how it works in my tree, but adding support for it shouldn't cause problems. It can be used in say, older style pattern matchers for getting matches to the current enemy state within a hyper-rectangular bounds (say in this case velocity and heading delta). --[[User:Chase-san|Chase]] 02:49, 3 March 2010 (UTC)<br />
<br />
Sure, wouldn't be hard to add in my rewrite. It might be a while till I get around to that though, since I'm really anxious to try my (possibly completely novel?) ideas for making it faster and such. --[[User:Rednaxela|Rednaxela]] 03:27, 3 March 2010 (UTC)<br />
:Actually I had tested some of those on my tree the other day while trying to optimize it, the "choosing a better dimension if the current one is only one value" actually produced decent gains assuming you chose a good dimension. In my first one I chose the one with the biggest difference, but I didn't like it, even though it worked better than my "iterate through dimensions in order till you find one that has more then one value", my guess is the more values a dimension has, the better (but that is hard to track). None of the data I posted is from those, but it got around 0.3 to the listed maps 0.4. --[[User:Chase-san|Chase]] 03:55, 3 March 2010 (UTC)<br />
:: Are you talking about the dimension to split on? That's very different than the things I have in my plans section. As far as what dimension to split on and where to split in it, I already do "middle of the dimension with the widest variance" (which just today I noticed some research papers conjecturing that it is perhaps the optimal kd-tree splitting method). --[[User:Rednaxela|Rednaxela]] 04:06, 3 March 2010 (UTC)<br />
::: Oh, alright, thats what you meant when you say that. Hehe, I guess I am more than a bit out of date. --[[User:Chase-san|Chase]] 04:40, 3 March 2010 (UTC)<br />
:::: Yeah, what I meant with the "dimension-pruned" things, is that the calculation of distance between the search point and each point in a bucket, can be made to not repeat the part of the summation for dimensions where the node has a width of 0, instead calculating that part of the summation once for every point in the bucket. --[[User:Rednaxela|Rednaxela]] 05:12, 3 March 2010 (UTC)<br />
<br />
== Rewrite progress ==<br />
<br />
Well, I have my rewrite largely done now. So, to those who thought it would be neat to have a search iterator... I now have it! At no significant performance penalty in fact, though it does operate best when you give it a a 'max iteration length', but if you stop before that, you still gain some time be it never descends into nodes until they have a possibility be required for next(). The reason it's still good to provide a 'max iteration length' is so that can routinely prune it's list of points it has evaluated. In order to make this possible efficiently, I coded up a "Interval Heap" double-ended queue that is very fast. Results look encouraging so far, however I didn't see the gain I hopes to see from it's more flexible path selection code. See the following results:<br />
<pre>RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree (Unsorted Output) >><br />
: Average searching time = 0.059 miliseconds<br />
: Average worst searching time = 0.899 miliseconds<br />
: Average adding time = 7.15 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Red's "Next Gen" kd-tree (Sorted Output) >><br />
: Average searching time = 0.061 miliseconds<br />
: Average worst searching time = 0.936 miliseconds<br />
: Average adding time = 7.47 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree (Sorted Output) >><br />
: Average searching time = 0.061 miliseconds<br />
: Average worst searching time = 1.086 miliseconds<br />
: Average adding time = 7.15 microseconds<br />
: Accuracy = 100%</pre><br />
It's a pretty close race despite the code structure and details of the search algorithm being rather different. Sets a new record for fastest tree with sorted output anyway, and I should be able to improve the results further... --[[User:Rednaxela|Rednaxela]] 07:25, 4 March 2010 (UTC)<br />
: I take it the output from the iterator is sorted, so I assume you may have to search additional buckets to find the next nearest without completely exhausting the current one, how can you do that without much of a performance hit, do you just make the list internally and supply the values as needed and then grab additional batches as needed? --[[User:Chase-san|Chase]] 10:15, 4 March 2010 (UTC)<br />
:: Pretty much. It's procedure is mostly like follows:<br />
::# Could any nodes in the pendingPaths heap have points closer to the search point than the closest point in the evaluatedPoints heap? If yes, do the following. Loop it so long as this condition is true.<br />
::## Pop the smallest distance node out of pendingPaths, and descend it down the "first guess" path according to what splits lead closer to the search point<br />
::##* During the descent, put the branches not taken into the pendingPaths heap, with the distance between that path's bounding box and the search point computed.<br />
::## At the bottom of the descent, iterate through all points, computing their distance to the search point<br />
::##* Insert the point in the evaluatedPoints heap if either 1) The size of evaluatedPoints is less than the max number of points remaining to return, or 2) the distance is smaller than the largest distance in evaluatedPoints<br />
::##* After each insertion, if the size of evaluatedPoints is greater than the max number of points remaining to return, remove the largest point from evaluatedPoints<br />
::# Pop the smallest distance result out of evaluatedPoints and return it.<br />
:: Interestingly, even if I pass the iterator a 'max points to return' that is essentially unlimited, as would allow iterating the whole tree, it's merely 30% slower to get the nearest 40 points, still faster any tree other than Duyn's and my own. --[[User:Rednaxela|Rednaxela]] 15:06, 4 March 2010 (UTC)<br />
<br />
Adding "replaceMax" and "replaceMin" methods to the interval heap helped performance a bit:<br />
<pre>RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree (Unsorted) >><br />
: Average searching time = 0.061 miliseconds<br />
: Average worst searching time = 1.281 miliseconds<br />
: Average adding time = 7.23 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree (Sorted) >><br />
: Average searching time = 0.062 miliseconds<br />
: Average worst searching time = 1.372 miliseconds<br />
: Average adding time = 7.23 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Red's "Next Gen" kd-tree (Storted) >><br />
: Average searching time = 0.059 miliseconds<br />
: Average worst searching time = 1.119 miliseconds<br />
: Average adding time = 7.7 microseconds<br />
: Accuracy = 100%<br />
<br />
<br />
BEST RESULT: <br />
- #1 Red's "Next Gen" kd-tree (Sorted) [0.0591]<br />
- #2 Rednaxela's Bucket kd-tree (Unsorted) [0.061]<br />
- #3 Rednaxela's Bucket kd-tree (Sorted) [0.0625]</pre><br />
--[[User:Rednaxela|Rednaxela]] 20:06, 4 March 2010 (UTC)<br />
<br />
Interestingly, the performance improvement is more obvious on my netbook:<br />
<pre>RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree (unsorted) >><br />
: Average searching time = 0.301 miliseconds<br />
: Average worst searching time = 19.547 miliseconds<br />
: Average adding time = 14.88 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree (sorted) >><br />
: Average searching time = 0.313 miliseconds<br />
: Average worst searching time = 19.032 miliseconds<br />
: Average adding time = 15.06 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Red's "Next Gen" kd-tree (sorted) >><br />
: Average searching time = 0.283 miliseconds<br />
: Average worst searching time = 18.02 miliseconds<br />
: Average adding time = 15.24 microseconds<br />
: Accuracy = 100%<br />
<br />
<br />
BEST RESULT: <br />
- #1 Red's "Next Gen" kd-tree (sorted) [0.2832]<br />
- #2 Rednaxela's Bucket kd-tree (unsorted) [0.3009]<br />
- #3 Rednaxela's Bucket kd-tree (sorted) [0.3134]</pre>Note, both this and the above tests are done with 100 iterations, which seems to give a fair bit of accuracy. Also... it looks like the worst search times increase on my netbook by a much greater factor than the average does. I wonder what the cause of that is... --[[User:Rednaxela|Rednaxela]] 20:40, 4 March 2010 (UTC)<br />
<br />
Ouch! I just tested on a school computer, and the ratio of the average-worst-search-time to the average-search-time got over 4x worse, 19.4ms:0.05ms! I have no clue why... the only theories I have is that the computers with the slow worst times are on OpenJDK instead of normal JDK6. Whether it's the fault of javac or the jvm is unknown. I doubt it's related to CPU cache size because the netbook (Intel Atom N270) has a 512kb cache when the school computer (Intel Core2 6300) has 2048kb cache yet has a larger discrepancy. --[[User:Rednaxela|Rednaxela]] 01:37, 5 March 2010 (UTC)<br />
<br />
== R-tree variants? ==<br />
<br />
Has anyone taken a look at the R-tree variants like the R* tree? I'm currently thinking of trying to adapt my 3rd gen tree (currently unreleased) into an R-tree variant. That means that overlap between nodes will be allowed, it will cause smaller bounding boxes and also make it easy to make into a 3-ary or 4-ary tree instead of 2-ary tree. My current 3rd gen implementation happens to be coded in a way that would make conversion fairly easy I think... And my ideas for pending improvements (implicit subtree instead of bucket, and dimension pruning), should also be equally applicable to the overlap-allowing R-tree variants. The tighter bounding boxes at the cost of overlap, and wider branching, may well be worth it... --[[User:Rednaxela|Rednaxela]] 19:28, 5 March 2010 (UTC)<br />
<br />
Well, a quick hack to use an R-tree-like insertion rule (instead of inserting points on the 'correct' side of the split, it inserts points where it'll cause the volume of the child node to increase the least. This leads to nodes with less volume, but possible overlap (violates normal kd-tree rules). The performance change was negligible in either direction. Now I just need to replace KD-tree-style node splitting, with B-tree-style self balancing mechanics, which should give a good result I hope. After that, I plan to try some of the 'forced reinsertion' voodoo of the R*-tree. --[[User:Rednaxela|Rednaxela]] 18:21, 6 March 2010 (UTC)<br />
<br />
Well, I got a R-tree working, but unfortunately it's performance was was quite poor... Unsure if the issue is a bug or if that's just how it has to be. I tried adding 'forced reinsertion' of tree nodes in R*-tree style which seemed to help some but performance, while improved, was still poor. I might try forced reinsertion of data points as well, but I have doubts it would improve results to compete with my kd-bucket-tree. I'm also thinking of changing the node-selection algorithm from the standard "whatever increases volume the least" like R-trees normally do, into something that discourages overlap of nodes more, which may help. --[[User:Rednaxela|Rednaxela]] 17:16, 10 March 2010 (UTC)<br />
<br />
Haven't had much of a chance to work on this since the last post, but I did find that the current R-tree variant I have is hitting 25%ish percent of nodes, far too many. Going to indeed first try the forced reinsertion of points firstly to see if that helps. After that, I'll try something that discourages overlap more which... oh... just happens to be what the "[wikipedia:X-tree|X-tree]" does. It's encouraging to find that types of approaches that I think about going down, have already been found to be promising by others. --[[User:Rednaxela|Rednaxela]] 18:44, 29 March 2010 (UTC)<br />
<br />
Tried the reinsertion of leaf points as well, didn't help much. I'm now suspecting I have a bug in my implementation. The code is also getting a little messy. As such, I'm going to re-do the bulk of the R-tree code without basing it so much on the kD-Tree code this time. I need to both catch bugs and make the code cleaner before I feel comfortable trying out other changes like what an "X-Tree" implements. Progress is slow due to class getting busy. --[[User:Rednaxela|Rednaxela]] 02:01, 7 April 2010 (UTC)<br />
<br />
== Compressing unused dimensions ==<br />
<br />
So for an experiment, that was listed as 'Dimension-pruned distance calculations', I made a variant of my tree that compresses point data in a simple way that I expected to improve performance: In leaf nodes, the the 'points' array will omit axis whose value are the same for all points. This means some memory savings, plus it means that when adding all of those points, it calculates a 'base' distance from the the values in the 'unused' dimensions, and then calculates the additional distance for each individual point only on the dimensions necessary. It seemed that this could in theory gain some performance by skipping a couple of dimensions in each distance calculation for an individual point. Unfortunately it seems that the cost of for each node making a new 'SearchPoint' array with dimensions matching the active ones in the leaf node, outweighs the distance calculation time saved. I may be able to optimize this overhead out somewhat but I'm not so optimistic about this path anymore. The possible gains will be sure to be small with normal data sets so I'm not sure it's worth trying to squeeze the drop of performance out of it. Onto other approaches for now... --[[User:Rednaxela|Rednaxela]] 17:38, 10 March 2010 (UTC)<br />
<br />
== Tree differences ==<br />
<br />
I switched to your tree in my KNN classifier. Execution time for 1175 battles went from 855s to 582s, pretty sweet. (HOT takes 251, to give a baseline.) I was concerned at first that it hit 19 less shots out of 1,282,681 - not to say that isn't negligible, but out of concern that the results should be identical. But with this rounded off data, my guess is that it's probably just choosing some different points when two are identical, so I'm not gonna waste time investigating it. Anyway, good stuff. =) --[[User:Voidious|Voidious]] 23:25, 15 March 2010 (UTC)<br />
<br />
: Glad to see it's working well for you. Yeah, I wouldn't be surprised if that difference, one note is that if I remember correctly, the tree will (currently) prefer the older data when there are a bunch of duplicates. Just out of curiosity, which version of the tree are you using? My [http://bitbucket.org/rednaxela/knn-benchmark/src/tip/ags/utils/dataStructures/trees/thirdGenKD/ rewrite] is slightly faster past the currently posted on the page here. --[[User:Rednaxela|Rednaxela]] 06:58, 18 March 2010 (UTC)<br />
<br />
: I'm using the old one (from this page). I didn't realize the new one was available - I have some plans for that iterator. =) Thanks. --[[User:Voidious|Voidious]] 13:59, 18 March 2010 (UTC)<br />
<br />
: Hey btw, in the new tree, Eclipse yells at me that your two @Override's in SquareEuclideanDistanceFunction and the 4 in NearestNeighborIterator are Errors, since those methods don't override a superclass. --[[User:Voidious|Voidious]] 15:51, 20 March 2010 (UTC)<br />
<br />
:: In Java 6, @Override applies to interfaces as well. I've noticed Eclipse has bugs with this however and doesn't support it even when using Java 6. Anything except Eclipse likes it. Might change it I suppose though... --[[User:Rednaxela|Rednaxela]] 16:12, 20 March 2010 (UTC)<br />
<br />
== 3rd gen tree licence ==<br />
<br />
Is you 3rd gen kd-tree found in the mercurial repo licensed under the same zlip license? I found no license notice in your third gen kd-tree source code. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:38, 17 April 2010 (UTC)<br />
<br />
Hmm yeah, I forgot to deal with that. Sure, that same zlib license works. --[[User:Rednaxela|Rednaxela]] 14:56, 17 April 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Rednaxela/FastTrig&diff=16927User talk:Rednaxela/FastTrig2010-07-01T08:43:04Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Sound good! But, will it skipped turns at first tick of the first round? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 10:41, 3 March 2009 (UTC)<br />
<br />
It shouldn't. It will always be as fast or faster than standard trig functions at least so long as you do the following:<br />
* 'inline' the index calculations like was said and used in the example testfor <br />
* Run init() BEFORE the battle begins (i.e. in static initialization code of your bot class)<br />
An example of that static initialization code is like this:<br />
<syntaxhighlight><br />
public class SomeBot extends AdvancedRobot {<br />
static {<br />
FastTrig.init();<br />
}<br />
<br />
public void run() {<br />
// Not in here<br />
}<br />
{<br />
</syntaxhighlight><br />
The initialization code doesn't take long (0.0017 seconds on my computer at 2880 divisions) but just to be sure it doesn't hurt to place the initialization outside of where the bot is timed --[[User:Rednaxela|Rednaxela]] 16:27, 3 March 2009 (UTC)<br />
<br />
== My take ==<br />
<br />
Nice work. From what I remember Simonton did something similar. I'm not sure if he had any luck though. One thing I noticed, I'm not sure if it works properly for negative angles, you will be rounding the wrong way. Also, the most useful trig function would be atan2. --[[User:Skilgannon|Skilgannon]] 20:43, 3 March 2009 (UTC)<br />
<br />
Ahh yes, sine doesn't work right at all yet for negative numbers. Cosine does work correctly except for rounding. I'll fix this now. :) --[[User:Rednaxela|Rednaxela]] 21:51, 3 March 2009 (UTC)<br />
<br />
== Bugs ==<br />
I was going to change the [[User:Rednaxela/FastTrig]] to fix the bug that Skilgannon said, and another one that happens with large DIVISION numbers and saw your edit, I haven't tested the fixed version, but I think it is still buggy. I think it should be:<br />
<syntaxhighlight><br />
public static final double sin(double value) {<br />
return sineTable[(int)(((value/K + 0.5) % DIVISIONS + DIVISIONS)%DIVISIONS)];<br />
}<br />
public static final double cos(double value) {<br />
return cosineTable[(int)(((value/K + 0.5) % DIVISIONS + DIVISIONS)%DIVISIONS)];<br />
}<br />
</syntaxhighlight><br />
<br />
I'm testing it with 62832 DIVISIONS, and much bigger loops than yours and is much faster. Here is the test I used:<br />
<syntaxhighlight><br />
package ags.util;<br />
public class FastTrigTest {<br />
public static void main(String[] args) {<br />
FastTrig.init();<br />
double v=0;<br />
long ms;<br />
int A = 10000;<br />
int B = 1000;<br />
double absolute = 0;<br />
for ( int i = 0; i < A; ++i ) for ( int j = 0; j < B; ++j ) {<br />
double angle = Math.random() * Math.PI * 200 - Math.PI * 100;<br />
absolute = Math.max(absolute, Math.abs(Math.sin(angle) - FastTrig.sin(angle)));<br />
absolute = Math.max(absolute, Math.abs(Math.cos(angle) - FastTrig.cos(angle)));<br />
}<br />
System.out.printf("Wrose error: %.12f\n", absolute);<br />
v=0;<br />
ms = -System.nanoTime();<br />
for ( int i = 0; i < A; ++i ) for ( int j = 0; j < B; ++j )<br />
v += FastTrig.sin(i * j * Math.PI - Math.PI / 3);<br />
ms += System.nanoTime();<br />
System.out.printf("FastTrig time: %.2f seconds\n", ms / 1E9);<br />
v = 0;<br />
ms = -System.nanoTime();<br />
for ( int i = 0; i < A; ++i ) for ( int j = 0; j < B; ++j )<br />
v += Math.sin(i * j * Math.PI - Math.PI / 3);<br />
ms += System.nanoTime();<br />
System.out.printf("Math time: %.2f seconds\n", ms/1E9);<br />
}<br />
}<br />
</syntaxhighlight><br />
It also checks the error, so it was easy to the bugs. But anyway, including this will be a priority for me now :). Good work. --[[User:Zyx|zyx]] 22:15, 3 March 2009 (UTC)<br />
<br />
Thanks! Well, my +40*DIVISIONS one DOES work unless the angle is extremely negative, to a magnitude you wouldn't generally expect to see, but your double-modulus solution is more robust. Now making an updated version that includes that increased robustness, and atan(), and maybe atan2(). Will update the page when that's ready. --[[User:Rednaxela|Rednaxela]] 00:05, 4 March 2009 (UTC)<br />
<br />
Also discovered speed was further increased by using value*K instead of value/K and adjusting the constant to compensate, and also that the cosine table is redundant. Using the sine table for cosine with a shifted index doesn't affect speed but decreases init time and memory use. --[[User:Rednaxela|Rednaxela]] 00:12, 4 March 2009 (UTC)<br />
<br />
Hi, I have some problem. I do create new function:<br />
<syntaxhighlight><br />
public static final double tan(double value) {<br />
return FastTrig.sin(value) / FastTrig.cos(value);<br />
}<br />
</syntaxhighlight><br />
... then I add following line to test ...<br />
<syntaxhighlight><br />
absolute = Math.max(absolute, Math.abs(Math.tan(angle) - FastTrig.tan(angle)));<br />
</syntaxhighlight><br />
... then, I run, result in: Worst error: Infinity! What wrong? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 03:47, 5 March 2009 (UTC)<br />
<br />
Well Nat, at some angles cosine is equal to 0. Due to this you can't simply divide those. You should create a seperate table for tangent and use that and that would be faster anyway. --[[User:Rednaxela|Rednaxela]] 04:11, 5 March 2009 (UTC)<br />
<br />
Ahh, I forgot. I try your new way, too, but it still have a much of error, I don't understand why! &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 04:38, 5 March 2009 (UTC)<br />
<br />
What about the fact that tangent gives undefined at certain values? The error-checking code isn't designed the cope with that because (Undefined - Undefined) isn't equal to 0. --[[User:Rednaxela|Rednaxela]] 04:49, 5 March 2009 (UTC)<br />
<br />
Really? because I make all with high diff (over than 1) out, and all is number! Note that some calculator (like Google) return 1.6.....E16 for tan(PI / 2), and my machine return that, too! I don't know because trig function are java native method so it is platform dependent. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 05:06, 5 March 2009 (UTC)<br />
<br />
Ahh. At PI / 2 it is undefined in actual math, HOWEVER it seems that beause computer can't quite perfetly represent PI/2 in floating point binary, it rounds to a number just SLIGHTLY smaller, which makes the result of the function simply become a very-large-number. Which come to think of it reminds me of why the error would be so high for tangent: Tangent by nature includes some very large values which mean error is naturally similarly larger. Really, "absolute error" shouldn't be what we measure, instead "angle error" is more relevant in reality with the kinds of geometry we'd be doing in robocode. --[[User:Rednaxela|Rednaxela]] 05:16, 5 March 2009 (UTC)<br />
<br />
OK, I understand. One more I just want to know, can we create an atan map? It seem that sin,cos and atan is most use trig function in robocode. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 06:17, 5 March 2009 (UTC)<br />
<br />
I've pondered atan, but it's tricky because it doesn't repeat, and I'm not sure how much aproximation is permissiable near the edges --[[User:Rednaxela|Rednaxela]] 06:53, 5 March 2009 (UTC)<br />
<br />
== Arc Cosine Implementation ==<br />
<br />
I've made a modified version that also includes acos, because that's used in so many applications when the cos rule is used, eg non-iterative wall smoothing, non-iterative wall angle, and my linear play-it-forward function. Because the function is so steep at the edges I had to increase the number of bins substantially, but because it is non-repeating it executes extremely quickly. Just doing a linear sweep, I'm getting execution 80X faster than Math.acos(). My max error is around 0.001, and the average is somethingE-5.<br />
<syntaxhighlight><br />
public static final int acos_DIVISIONS = 131072;//uses 1 MB of memory<br />
public static final double acosK = DIVISIONS/2;<br />
public static final double[] acosTable = new double[acos_DIVISIONS + 1];<br />
<br />
static {<br />
for(int i = 0; i < acos_DIVISIONS; i++){<br />
acosTable[i] = Math.acos(i/acosK - 1);<br />
}<br />
}<br />
<br />
public static final double acos(double value){<br />
return acosTable[(int)((value + 1)*acosK + 0.5)] ;<br />
}<br />
</syntaxhighlight><br />
--[[User:Skilgannon|Skilgannon]] 21:22, 8 April 2009 (UTC)<br />
An improvement to acos:<br />
<syntaxhighlight><br />
public static final double acos(double value) {<br />
return acosTable[(int)(value*acosK + (acosK + 0.5))] ;<br />
}</syntaxhighlight><br />
This requires one less addition (and one less loading of a double literal) --[[Starrynte]] 01:10, 10 April 2009 (UTC)<br />
<br />
Nice! I didn't see that! --[[User:Skilgannon|Skilgannon]] 01:21, 10 April 2009 (UTC)<br />
<br />
Ah! I just realized: shouldn't it be <code>public static final double acosK = acos_DIVISIONS/2;</code>, and not <code>public static final double acosK = DIVISIONS/2;</code>? Or is this some Performance Enhancing Bug :) --[[User:Starrynte|Starrynte]] 18:09, 10 April 2009 (UTC)<br />
== Arc Tangent Implementation ==<br />
<br />
Here are some (hopefully) speed optimizations, mainly very minor ones, based on the code posted on main page. (However, tiny optimizations add up!)<br />
<syntaxhighlight><br />
public static final void init() {<br />
//for(int i=DIVISIONS-1;i>=0;i++) { (comparing i to 0 is faster but this is a very minor thing<br />
for (int i=0; i<DIVISIONS; i++) {<br />
sineTable[i] = Math.sin(i/K); //no need to assign "value" to a variable first<br />
}<br />
}<br />
</syntaxhighlight><br />
You may want to consider making DIVISIONS a power of two (maybe 8192), since then you can replace "% DIVISIONS" (modulo DIVISIONS) with "& (DIVISIONS - 1)" (bitwise AND with (DIVISIONS-1), which is the same thing as modulo DIVISIONS). Not sure if AND is necessarily faster, you may need to check.<br><br />
Also in main(), "Wrost error" should be "Worst error"<br><br />
Here is a atan2 method that I made based on what I read on the internet. The catch is the Math.sqrt, perhaps it would be possible to make a sqrt table. (Uses acos method posted by [[User:Skilgannon|Skilgannon]] above.)<br />
<syntaxhighlight><br />
public static final double atan2(double x, double y){<br />
//return asin(y / Math.sqrt(x*x + y*y));<br />
//robocode angles are different, if i understand correctly you just need to swap usage of sines and cosines for robocode-style angles<br />
return acos(y / Math.sqrt(x*x + y*y));<br />
}<br />
</syntaxhighlight><br />
Information from http://www.analyzemath.com/Calculators/Rect_Polar.html<br />
Please correct me if I'm wrong in how to use trig in robocode.<br />
--[[Starrynte]] 00:47, 9 April 2009 (UTC)<br />
<br />
I don't really know, but it seem that we need to swap y with x, too. And that atan2 implementations, I think using native hava method is faster since it need to call sqrt, which is slow. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 01:02, 9 April 2009 (UTC)<br />
<br />
I've done some tests, and the custom atan2 seems to be slightly faster, with a sacrifice in init time and memory (due to sqrt and acos tables):<br />
<pre><br />
FastTrig init time: 0.07575 seconds<br />
FastTrig.atan2(5000,5000) = 0.7852348917896085<br />
Took 0.00003 seconds<br />
Math.atan2(5000,5000) = 0.7853981633974483<br />
Took 0.00005 seconds<br />
</pre><br />
(The maximum values that can be used with this atan2 is (5000,5000) , since that's as far as I set the sqrt tables to go up to. Likewise, the maximum value for a sqrt is 50000000)<br><br />
I will post code as soon as I confirm it is working<br />
--[[Starrynte]] 16:59, 9 April 2009 (UTC)<br />
<br />
<syntaxhighlight><br />
public static final double atan2(double x, double y){<br />
//return Math.asin(y / Math.sqrt(x*x + y*y));<br />
//robocode angles are different, swap usage of sines and cosines<br />
return acos(y / Math.sqrt(x*x + y*y)) * (y>=0?1:-1);<br />
}<br />
</syntaxhighlight><br />
Basically same thing as above, except the sign thing (Math.signum(y) is slower than just (y>=0?1:-1)). It turns out that the FastTrig acos outweighs the time needed for Math.sqrt (where tables were slower or way too large for the accuracy needed). Compared it with using atan2 in robocode and it works. About 2 to 4 times faster than Math.atan2(). <br>I estimate (haven't tested) the worst error is about 0.05 degrees, which, in the <b>worst case</b> (when you're shooting from a corner to the corner diagonally across it on a 5000 x 5000 field, a distance of about 7071 units) gives an error of 6 units. Compare that with a bot width of 36 units.<br />
--[[Starrynte]] 17:45, 9 April 2009 (UTC)<br />
<br />
Nice stuff Starrynte and Skilgannon! Hmm, the acos and atan2 error is slightly more I'd like considering how many divisions they use but still, not bad! I'll incorporate these things into the main version on the page some time soon. About that power-of-two optimization, I've considered that myself actually though one needs to keep in mind that "& (DIVISIONS - 1)" wouldn't behave the same as modulus for negative numbers --[[User:Rednaxela|Rednaxela]] 18:44, 9 April 2009 (UTC)<br />
<br />
* cos is an even function, so negative numbers should be fine for cos at least, because "& (DIVISIONS - 1)" is the equivalent of also taking the mod. --[[User:Skilgannon|Skilgannon]] 01:21, 10 April 2009 (UTC)<br />
<br />
:* Er... As Java and C define mod, <code>(-1 % 8) = -1</code>, and <code>(-1 & 7) = 7</code>. See [http://en.wikipedia.org/wiki/Signed_number_representations#Two.27s_complement] if the result of that bitwise and surprises you. :) --[[User:Rednaxela|Rednaxela]] 01:59, 10 April 2009 (UTC)<br />
<br />
:* I blame my high school comp teacher for explaining that the negatives of 2s complement are just like the positives except with a negative bit at the front as 1 instead of 0. I took that to mean that the binary representation was exactly the same for x and -x except with that first bit 1 instead of 0 for -x. I guess not :-/ --[[User:Skilgannon|Skilgannon]] 08:07, 10 April 2009 (UTC)<br />
<br />
*OK. But couldn't you use it for the second modulus, when you know everything is going to be positive anyways? You just have to cast to int first. --[[User:Skilgannon|Skilgannon]] 10:36, 10 April 2009 (UTC)<br />
<br />
Here is another slightly more inaccurate version, but may be faster depending on the computer you're using (it's about 5% slower on my computer). It replaces the divide by square root with an inlined multiply by inverse square root (described here http://en.wikipedia.org/wiki/Fast_inverse_square_root)<br />
<syntaxhighlight><br />
public static final double atan2(double x, double y){<br />
return acos(y * (1.5 - 0.5 * (x=x*x + y*y)* (x = Double.longBitsToDouble(0x5fe6ec85e7de30daL - (Double.doubleToLongBits(x)>>1)))*x)*x)*(y>=0?1:-1);<br />
}<br />
</syntaxhighlight><br />
--[[Starrynte]] 20:46, 9 April 2009 (UTC)<br />
<br />
From atan2 arises atan (up to twice as fast), plus a (slight) optimization in both:<br />
<syntaxhighlight><br />
public static final double atan(double value){<br />
//return (value>=0 ? acos(1 / value) : -acos(1 / value)); OK if you approximate "Math.sqrt(value*value + 1)" as "value"<br />
return (value>=0 ? acos(1 / Math.sqrt(value*value + 1)) : -acos(1 / Math.sqrt(value*value + 1)));<br />
}<br />
<br />
public static final double atan2(double x, double y){<br />
return (y>=0 ? acos(y / Math.sqrt(x*x + y*y)) : -acos(y / Math.sqrt(x*x + y*y)));<br />
}<br />
</syntaxhighlight><br />
asin can also be calculated from atan, though not as fast as making a table for it:<br />
<syntaxhighlight><br />
Math.asin(x) = atan(x / Math.sqrt(1 - x*x));<br />
</syntaxhighlight><br />
Now I wonder if you could make a log table...<br />
--[[User:Starrynte]] 02:22, 10 April 2009 (UTC)<br />
<br />
Just thinking, wouldn't it be: <br />
<syntaxhighlight><br />
public static final double atan2(double x, double y){<br />
return (x>=0 ? acos(y / Math.sqrt(x*x + y*y)) : 2*Math.PI -acos(y / Math.sqrt(x*x + y*y)));<br />
}<br />
</syntaxhighlight><br />
because it is a 'negative' bearing if x is negative not y, and atan2 is meant to return between 0 and 2PI. --[[User:Skilgannon|Skilgannon]] 10:10, 10 April 2009 (UTC)<br />
<br />
That may be correct. By the way, I've found (yet) another better implementation of atan2, I'll look at it when I have time (in a few hours) --[[User:Starrynte|Starrynte]] 20:09, 10 April 2009 (UTC)<br />
<br />
OK. New atan2 implementation, and from it atan, faster (20-40% faster than old version, and about 120x faster than Math version):<br />
<syntaxhighlight><br />
public static final double atan2(double y, double x) {<br />
double abs_y = abs(y);<br />
double angle = ((x>=0d)?QUARTER_PI:QUARTER_PI*3d) + 0.1963*(x = (x + ((x>=0d)?-abs_y:abs_y)) / (abs(x)+y)) *x*x - 0.9817*x;<br />
return y < 0d ? -angle : angle;<br />
}<br />
public static final double atan(double value){<br />
double angle = abs(value);<br />
angle = QUARTER_PI + 0.1963 * (angle = (1 - angle) / (1 + angle)) *angle*angle - 0.9817*angle;<br />
return value < 0d ? -angle:angle;<br />
}<br />
public static final double abs(double a){<br />
return (a <= 0.0D) ? 0.0D - a : a;<br />
}<br />
</syntaxhighlight><br />
(Calling abs somehow seems to be faster than inlining it, just like calling sin from cos seems to be faster than inlining it...)<br><br />
Source: http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm, then optimized slightly (note that this probably can be optimized further, but I'm too lazy to).<br><br />
Now testing all the improved methods for accuracy just to make sure... --[[User:Starrynte|Starrynte]] 23:34, 10 April 2009 (UTC)<br />
<br />
Yet another new atan2/atan, but 50-100% more accuracy than the one above, and slightly faster speed.<br />
<syntaxhighlight><br />
public static final double newatan2(double y, double x){<br />
if ( x == 0d ) {<br />
return y == 0d ? 0d:(y > 0d ? HALF_PI:-HALF_PI);<br />
}<br />
double atan; double z;<br />
if ( abs( z = y/x ) < 1d ) {<br />
atan = z/(1d + 0.28d*z*z);<br />
if ( x < 0d ) {<br />
return y < 0d ? atan - Math.PI:atan + Math.PI;<br />
}<br />
} else {<br />
if ( y < 0d ) return -HALF_PI - z/(z*z + 0.28d);<br />
atan = HALF_PI - z/(z*z + 0.28d);<br />
}<br />
return atan;<br />
}<br />
public static final double atan(double value){<br />
double atan;<br />
if ( abs(value) < 1d ) {<br />
atan = value/(1d + 0.28d*value*value);<br />
} else {<br />
if ( value < 0d ) return -HALF_PI - value/(value*value + 0.28d);<br />
atan = HALF_PI - value/(value*value + 0.28d);<br />
}<br />
return atan;<br />
}<br />
</syntaxhighlight><br />
--[[User:Starrynte|Starrynte]] 03:27, 14 April 2009 (UTC)<br />
== FastTrig Re-create ==<br />
See [[User:Rednaxela/FastTrig|main page]] for source.<br />
<br />
<br />
I'm quite sure both acos and tan need a higher number of divisions, otherwise they get a lot of error due to the steepness of their functions. Your asin function looks right to me, although I cleaned it a bit by calling acos. I also changed the tan because it has a period of PI, not 2PI, so now it's more accurate, although yours did work. I think a lookup table with a single Newton's iteration might be faster and more accurate for sqrt, but that's just speculation. --[[User:Skilgannon|Skilgannon]] 10:01, 10 April 2009 (UTC)<br />
<br />
* Thanks. The reason for not calling acos is to redice overhead, although it is a little. I don't really know about sqrt, just copy over from above. Anyway, my code is not yet test in anyway. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:36, 10 April 2009 (UTC)<br />
<br />
* Math.sqrt(value) is probably faster, since the divide is expensive. If you can find a quick way of doing Double.longBitsToDouble and Double.doubleToLongBits, then it may be worth considering doing it that way (which, by the way, I edited slightly)<br>By the way, expect a slightly faster sine and cosine soon *without* using any tables at all! (Once I find the source of robocode's normalRelativeAngle) --[[User:Starrynte|Starrynte]] 17:34, 10 April 2009 (UTC)<br />
<br />
:* Here the source, if you want [http://robocode.svn.sourceforge.net/viewvc/robocode/robocode/trunk/robocode.api/src/main/java/robocode/util/Utils.java?view=markup] &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 17:52, 10 April 2009 (UTC)<br />
<br />
* OK, if you're fine with the worst error being 0.001090292603 instead of 0.000436313959, this version of sine is 20-30% faster AND uses no tables at all (cosine coming up soon)<br />
<syntaxhighlight><br />
public static final double sin(double value) {<br />
//normalRelativeAngle =)<br />
value=(value %= (2*Math.PI)) < 0.0D ? value < (-Math.PI) ? value + (2*Math.PI) : value : value >= Math.PI ? value - (2*Math.PI) : value;<br />
//approximate sine through a parabola (more details at http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/)<br />
return 0.225 * ( ( value*= (4/Math.PI) * (1 - abs(value)/Math.PI) ) * abs(value) - value) + value;<br />
}<br />
</syntaxhighlight><br />
--[[User:Starrynte|Starrynte]] 18:00, 10 April 2009 (UTC)<br />
<br />
* It turns out that <br />
<syntaxhighlight><br />
public static final double cos(double value) {<br />
return sin(value + (Math.PI/2));<br />
}<br />
</syntaxhighlight><br />
is the same or (on my computer) even slightly faster than inlining the sine method, which wouldn't be too hard anyways, so here is the cos function. --[[User:Starrynte|Starrynte]] 18:11, 10 April 2009 (UTC)<br />
** Yeah, that is a cos I think. The reason that the old one do not is there's no nomalization in sin function. (adding Math.PI/2 will always result over PI/2) Have Could you please test every method in class above and make sure they work? Also, some statistics on run time compare to Math.xxx would be nice. :-) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 18:28, 10 April 2009 (UTC)<br />
<br />
Some results (more to be added):<br />
<pre><br />
atan2: worst error = 0.010149566515914185, average error = 0.003435479898560425<br />
atan : worst error = 0.01014956651659027 , average error = 0.007611438369067416<br />
sin : worst error = 0.001090292602593357, average error = 0.000512039207871299<br />
cos : worst error = 0.001090292602468734, average error = 0.000498927373420323<br />
</pre><br />
--[[User:Starrynte|Starrynte]] 03:10, 11 April 2009 (UTC)<br />
<br />
Cool result: <br />
<pre><br />
Initializing FastMath...<br />
FastMath init time: 0.26825 seconds<br />
<br />
== Sine Test ==<br />
Math.sin() time: 22.32937 seconds<br />
FastMath.sin() time: 0.82147 seconds<br />
FastMath.sin() worst error: 0.00044<br />
FastMath.sin() without table time: 0.86786 seconds<br />
FastMath.sin() worst error: 0.00109<br />
== Cosine Test ==<br />
Math.cos() time: 22.45272 seconds<br />
FastMath.cos() time: 0.82310 seconds<br />
FastMath.cos() worst error: 0.00036<br />
FastMath.cos() without table time: 0.83544 seconds<br />
FastMath.cos() worst error: 0.00076<br />
== Tangent Test ==<br />
Math.tan() time: 29.05201 seconds<br />
FastMath.tan() time: 0.83758 seconds<br />
FastMath.tan() max error: 0.00004<br />
== Arcsine Test ==<br />
Math.asin() time: 15.22509 seconds<br />
FastMath.asin() time: 0.18033 seconds<br />
FastMath.asin() worst error: 0.00390<br />
== Arccosine Test ==<br />
Math.asin() time: 14.74417 seconds<br />
FastMath.acos() time: 0.16350 seconds<br />
FastMath.acos() worst error: 0.00390<br />
== Arctangent Test ==<br />
Math.atan() time: 2.98773 seconds<br />
FastMath.atan() time: 0.53018 seconds<br />
FastMath.atan() worst error: 0.00001<br />
new FastMath.atan() time: 0.36471 seconds<br />
new FastMath.atan() worst error: 0.01014<br />
== Arctangent2 Test ==<br />
Math.atan2() time: 4.55493 seconds<br />
FastMath.atan2() time: 0.71803 seconds<br />
FastMath.atan2() worst error: 0.00391<br />
new FastMath.atan2() time: 0.54249 seconds<br />
new FastMath.atan2() worst error: 0.01015<br />
</pre><br />
It seem that JAVA atan is really fast and sin/cos without table lookup is pretty slow. New atan refer to new Starrynte's one above. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:57, 12 April 2009 (UTC)<br />
<br />
<br />
I'm not using FastTrig on my bots anymore because I didn't really see it saving me ticks, but the tests results kept making me curious why it seems so much faster the LUT compared to the native calls and still I see no gain on practice. So I started reading some Java specs and found out that it uses the HW sin/cos when it can, but it uses a relatively expensive algorithm to be more accurate sometimes.<br />
* If the parameter value is less than PI/5 it seems to use HW always.<br />
* Between PI/5 and PI/4 is hard to know.<br />
* For bigger ones it uses a not so fast algorithm, but if the parameter is always less than PI in magnitude it still not so slow.<br />
<br />
I recommend trying the tests with angle parameters in the range [-PI, PI] (which are anyway the most relevant in Robocode) and see how much faster Math becomes, not faster than FastTrig, but the gap closes a '''lot'''. --[[User:Zyx|zyx]] 09:44, 12 April 2009 (UTC)<br />
<br />
Original FastTrig don't save you any ticks, like you mentioned, but newer one might. Because inverse trig function is a lot faster! Here a result:<br />
<pre><br />
Initializing FastMath...<br />
FastMath init time: 0.26595 seconds<br />
<br />
== Sine Test ==<br />
Math.sin() time: 2.38096 seconds<br />
FastMath.sin() time: 0.76675 seconds<br />
FastMath.sin() worst error: 0.00044<br />
FastMath.sin() without table time: 0.98345 seconds<br />
FastMath.sin() worst error: 0.00109<br />
== Cosine Test ==<br />
Math.cos() time: 2.29882 seconds<br />
FastMath.cos() time: 0.76020 seconds<br />
FastMath.cos() worst error: 0.00044<br />
FastMath.cos() without table time: 1.04117 seconds<br />
FastMath.cos() worst error: 0.00109<br />
== Tangent Test ==<br />
Math.tan() time: 5.53648 seconds<br />
FastMath.tan() time: 0.79689 seconds<br />
FastMath.tan() max error: 16331239355788294.00000<br />
== Arcsine Test ==<br />
Math.asin() time: 15.34787 seconds<br />
FastMath.asin() time: 0.20251 seconds<br />
FastMath.asin() worst error: 0.00383<br />
== Arccosine Test ==<br />
Math.asin() time: 14.63279 seconds<br />
FastMath.acos() time: 0.18518 seconds<br />
FastMath.acos() worst error: 0.00383<br />
== Arctangent Test ==<br />
Math.atan() time: 3.07183 seconds<br />
FastMath.atan() time: 0.87246 seconds<br />
FastMath.atan() worst error: 0.00388<br />
new FastMath.atan() time: 0.77300 seconds<br />
new FastMath.atan() worst error: 0.01015<br />
== Arctangent2 Test ==<br />
Math.atan2() time: 5.08507 seconds<br />
FastMath.atan2() time: 1.13635 seconds<br />
FastMath.atan2() worst error: 6.28318<br />
new FastMath.atan2() time: 0.98630 seconds<br />
new FastMath.atan2() worst error: 1.57080<br />
</pre><br />
Here, sin/cos/tan limit to [-PI,PI], asin and acos limit to [-1,1], atan limit to [-8000,8000] and atan2 limit to [-5000,5000] on both parameter. But this test run ten million calculation (NOTE: I can't do any more, heap size here is 1024 because I use same angle for every function so 7 of double[10000000])<br />
<br />
Don't mind tan error, it always get this error for value PI.<br />
<br />
Error increase with atan/atan2 probably cause by negative value, since old one never test with negative.<br />
<br />
From my point of view with new result, use everything but atan/atan2 since large error factor. If you don't want to use sin/cos then use asin/acos. Current error percentage is ~0.122%, in acceptable rate. It is ~76 times faster! but sin/cos only at ~2.875 times. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:44, 12 April 2009 (UTC)<br />
<br />
* I've fixed the atan2 to work correctly with Robocode co-ordinates. I also switched the second modulus in sin/cos/tan to be a bitwise & instead, as the value is always positive here, so they should be slightly faster now. (Do a diff to see all the changes I made.) I'm using it in my test bot with no problems. I think for it to be relevant to Robocode, sin/cos should be tested (-PI,TWO_PI] (because often absolute angles are used, not just relative), tan tested (-HALF_PI,HALF_PI). BTW, I'm not sure if you've covered this in school, round bracket ( or ) means not inclusive, square bracket [ or ] means inclusive. --[[User:Skilgannon|Skilgannon]] 13:18, 12 April 2009 (UTC)<br />
<br />
:* What do you mean inclusive? I not really good at English (I'm 13) Here a new result base on your change.<br />
<pre><br />
Initializing FastMath...<br />
FastMath init time: 0.26234 seconds<br />
<br />
== Sine Test ==<br />
Math.sin() time: 2.72282 seconds<br />
FastMath.sin() time: 0.46620 seconds<br />
FastMath.sin() worst error: 0.00038<br />
FastMath.sin() without table time: 1.09060 seconds<br />
FastMath.sin() worst error: 0.00109<br />
== Cosine Test ==<br />
Math.cos() time: 2.59886 seconds<br />
FastMath.cos() time: 0.45760 seconds<br />
FastMath.cos() worst error: 0.00038<br />
FastMath.cos() without table time: 1.03119 seconds<br />
FastMath.cos() worst error: 0.00109<br />
== Tangent Test ==<br />
Math.tan() time: 4.24820 seconds<br />
FastMath.tan() time: 0.80408 seconds<br />
FastMath.tan() max error: 16331239362674482.00000<br />
== Arcsine Test ==<br />
Math.asin() time: 15.49524 seconds<br />
FastMath.asin() time: 0.20813 seconds<br />
FastMath.asin() worst error: 0.00386<br />
== Arccosine Test ==<br />
Math.asin() time: 14.95285 seconds<br />
FastMath.acos() time: 0.22340 seconds<br />
FastMath.acos() worst error: 0.00386<br />
== Arctangent Test ==<br />
Math.atan() time: 3.06622 seconds<br />
FastMath.atan() time: 0.85496 seconds<br />
FastMath.atan() worst error: 0.00093<br />
new FastMath.atan() time: 0.67158 seconds<br />
new FastMath.atan() worst error: 0.01015<br />
== Arctangent2 Test ==<br />
Math.atan2() time: 4.96311 seconds<br />
FastMath.atan2() time: 1.10923 seconds<br />
FastMath.atan2() worst error: 0.00391<br />
new FastMath.atan2() time: 0.96854 seconds<br />
new FastMath.atan2() worst error: 1.57080<br />
</pre><br />
:: faster a little for sin/cos and correct error for atan/atan2. [[Starrynte]], please check your new atan2 implementation, as it result in error at about 90 degrees! I do add my main() to class above for anyone can run test (but without new atan/atan2 and sin/cos without table lookup. WARNING: Require -Xmx1024M) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:44, 12 April 2009 (UTC)<br />
::* OK, just understand what do you mean inclusive. Actually, I do test with inclusive, but the result will not since I never see Math.random() return 0 or 1 ;) Rednaxela, please consider merge this to your page. It is going really better and better for inverse trig. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:50, 12 April 2009 (UTC)<br />
::* (Yet another) new atan2 found, slightly faster than the current atan2, yet (according to my tests) 50-100% more accurate depending on the parameters. See above for the code. I also moved the recreate to the main page (while waiting for [[User:Rednaxela|Rednaxela]] to either merge the two or approve of it), as the wiki is warning me about the size of the page. Too lazy to test atan2/atan using now-established ways, if someone would be kind enough to test the new atan2/atan methods... --[[User:Starrynte|Starrynte]] 03:27, 14 April 2009 (UTC)<br />
<br />
Three new sine/cosine approximation methods, all without array:<br />
1. <syntaxhighlight><br />
Sine: return (x%=(Math.PI*2)) * (0.98864467697616454 + x * x * (-0.16057654076500594 + x * x * (0.007410226601174971 + x * x * (-.00013957972749774987 + x * x * .00000098419665532389341))));<br />
Cosine: return (x=(x + HALF_PI) % (Math.PI*2)) * (0.98864467697616454 + x * x * (-0.16057654076500594 + x * x * (0.007410226601174971 + x * x * (-.00013957972749774987 + x * x * .00000098419665532389341))));</syntaxhighlight><br />
2. <syntaxhighlight><br />
Sine: x * (0.98441649960736333 + x * x * (-0.15346258175416733 + x * x * (0.005465389576719881)));<br />
Cosine: ((x>=HALF_PI ? x - HALF_PI:x + HALF_PI) * (0.98441649960736333 + x * x * (-0.15346258175416733 + x * x * (0.005465389576719881)));</syntaxhighlight><br />
3. <syntaxhighlight><br />
Sine: return x * (0.98864467697616454 + x * x * (-0.16057654076500594 + x * x * (0.007410226601174971 + x * x * (-.00013957972749774987 + x * x * .00000098419665532389341))));<br />
Cosine: return (x>=THREE_OVER_TWO_PI ? x - HALF_PI:x + HALF_PI) * (0.98864467697616454 + x * x * (-0.16057654076500594 + x * x * (0.007410226601174971 + x * x * (-.00013957972749774987 + x * x * .00000098419665532389341))));</syntaxhighlight><br />
1. is a general purpose one that could be used for all values (15% slower than array, max error 0.00638)<br />
2. can be used when the value is known to be between PI and -PI (not nested)<br />
3. can be used when the value is known to be between TWO_PI and -TWO_PI (not tested)<br />
--[[User:Starrynte|Starrynte]] 01:01, 26 April 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Positive/Optimal_Velocity&diff=16926User talk:Positive/Optimal Velocity2010-07-01T08:42:58Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Your version passes all of my tests (so far) except that it doesn't take into account the maximum velocity set by the bot. Nice catch on the updateMovement() routine, that should get fixed too (my tests assume that behaviour already). --[[User:Darkcanuck|Darkcanuck]] 20:21, 15 July 2009 (UTC)<br />
<br />
: Great! Please replace 8.0 in the getNewVelocity function with currentCommands.getMaxVelocity(), and it should work I believe (I temporarily set it to 8.0, because I am not using the currentCommands class). :) --[[User:Positive|Positive]] 20:26, 15 July 2009 (UTC)<br />
<br />
:: ok, that fixed it. Nice work! --[[User:Darkcanuck|Darkcanuck]] 20:33, 15 July 2009 (UTC)<br />
<br />
I just noticed that this does allow some free acceleration, although it's capped at 1. Replacing this with the time-based calc in Voidious' second version should work. --[[User:Darkcanuck|Darkcanuck]] 20:41, 15 July 2009 (UTC)<br />
<br />
: I did, unfortunately, find one small problem with the code: decelTime(Double.POSITIVE_INFINITY). It takes a lot of time to process. So i guess at arguments around > 1000 it could simply return Rules.MAXVELOCITY (or a more elegant solution). Personally, I think the free acceleration provides no ''problem'', and people not liking that particular change was the start of the discussion. --[[User:Positive|Positive]] 20:52, 15 July 2009 (UTC)<br />
<br />
:: Yeah, I was going to suggest that we add an "if (distance > SOME_MAX_DISTANCE)", just accelerate freely, for sake of execution speed. That would be 20 if you assume max velocity is 8, but Fnl might prefer to have it calculated based on a MAX_VELOCITY constant...<br />
:: The free acceleration is really a separate issue from the optimal velocity. Originally, you could go from -0.1 to 1.9, so even capping velocity at 1.0 would be a change. I sort of feel like if we're going to change it, we should do it the way Fnl envisioned, which is how I had it in that "Version 2". But that's an easy change, whatever is decided.<br />
:: Oh, and nice work. =) This solution definitely feels right.<br />
:: --[[User:Voidious|Voidious]] 21:02, 15 July 2009 (UTC)<br />
<br />
::: You're welcome. :) Hmm, I guess you are right. Fnl's change is more logical. I remember when I started with studying the movement rules I had expected something more like what he suggested. However, staying able to easily move at integer (whole) speeds is nice too. (I guess I'm a little biased, because Portia uses integer speed lookup tables). By the way, if it can't be >=20, I'm thinking something like "static private final double MAX_CALC_DISTANCE = Rules.MAXVELOCITY + Rules.MAXVELOCITY/Rules.DECELERATION * Rules.MAXVELOCITY/2;". --[[User:Positive|Positive]] 21:44, 15 July 2009 (UTC)<br />
<br />
== Hijack =) ==<br />
<br />
I don't mean to hijack your work, but here's what I feel is a much simpler version of both your and Voidious's ideas =) Or at least, I find it easier to read:<br />
<syntaxhighlight><br />
private static double getNewVelocity(double velocity, double distance) {<br />
<br />
if (distance < 0) <br />
return -getNewVelocity(-velocity, -distance);<br />
// If the distance is negative, then change it to be positive<br />
// and change the sign of the input velocity and the result<br />
<br />
final double goalVel;<br />
if(distance == Double.POSITIVE_INFINITY)<br />
goalVel = currentCommands.getMaxVelocity();<br />
else <br />
goalVel = Math.min(getMaxVelocity(distance),<br />
currentCommands.getMaxVelocity());<br />
<br />
if(velocity >= 0)<br />
return Math.max(velocity - Rules.DECELERATION,<br />
Math.min(goalVel, velocity + Rules.ACCELERATION));<br />
//else<br />
return Math.max(velocity - Rules.ACCELERATION,<br />
Math.min(goalVel, velocity + Rules.DECELERATION));<br />
}<br />
final static double getMaxVelocity(double distance)<br />
{<br />
final double decelTime = Math.max(1,Math.ceil(<br />
//sum of 0... decelTime, solving for decelTime using quadratic formula<br />
(Math.sqrt((4*2/Rules.DECELERATION)*distance + 1) - 1)/2));<br />
<br />
final double decelDist = (decelTime / 2.0) * (decelTime-1) // sum of 0..(decelTime-1)<br />
* Rules.DECELERATION;<br />
<br />
return ((decelTime - 1) * Rules.DECELERATION) +<br />
((distance - decelDist) / decelTime);<br />
}<br />
</syntaxhighlight><br />
--[[User:Skilgannon|Skilgannon]] 11:20, 16 July 2009 (UTC)<br />
<br />
Very nice. Your formula replacing the decelTime function is voodoo to me right now, but I've thrown enough numbers at it that I trust it works. =) I'd like to test this (I don't trust my own logic that it's equivalent :-P), then switch to this code, and also implement the new decel-through-zero rules. Also, I added one set of parens in there for clarity, hope you don't mind. --[[User:Voidious|Voidious]] 13:47, 16 July 2009 (UTC)<br />
<br />
Nice simplification. It passes all my tests, except for a new one I just added: starting vel=0, distance=+INF (returns NaN). --[[User:Darkcanuck|Darkcanuck]] 14:36, 16 July 2009 (UTC)<br />
<br />
Ok, I fixed the infinity case, although I hate adding more if statements. As an explanation for the voodoo in there read on: =)<br />
<pre><br />
From the old decelTime method: distance <= (square(x) + x) / 2) * Rules.DECELERATION<br />
lets solve for the case where they're equal, ie.<br />
distance = (square(x) + x) / 2) * Rules.DECELERATION<br />
distance/Rules.DECELERATION*2 = x*x + x<br />
0 = x^2 + x - distance/Rules.DECELERATION*2<br />
which is in the form 0 = ax^2 + bx + c<br />
so we can use the quadratic formula x = (-b +-sqrt(b^2 - 4*a*c))/(2*a)<br />
which gives us:<br />
x = (-1 +-sqrt(1 - 4*(1)*(-distance/Rules.DECELERATION*2)))/2<br />
because we need a positive answer (time) we need the + of the +-sqrt<br />
so, simplified: x = (sqrt(4*2/Rules.DECELERATION*distance + 1) - 1)/2<br />
and then take the ceil, because any partial tick used means a whole tick got used.<br />
</pre><br />
And I really need to start packing for my holiday to Mozambique... --[[User:Skilgannon|Skilgannon]] 15:09, 16 July 2009 (UTC)<br />
<br />
Thanks for the explanation, it's clear now. Enjoy your holiday. =) --[[User:Voidious|Voidious]] 15:17, 16 July 2009 (UTC)<br />
<br />
Okay, I finally analyzed your code. Great work! Although your version is not the same as the one I posted. Your version's getNewVelocity(-0.1,1000000000) == 1.9 while the old one == 1.0. So considering Fnl used your version, the alpha-2 version is exactly like the 1.6.1.4 version except for the "bugs". :)<br />
<br />
Here's the modified function that makes them equal (for if it's decided we want that):<br />
<br />
<syntaxhighlight> private static double getNewVelocity(double velocity, double distance) {<br />
<br />
if (distance < 0) <br />
return -getNewVelocity(-velocity, -distance);<br />
// If the distance is negative, then change it to be positive<br />
// and change the sign of the input velocity and the result<br />
<br />
final double goalVel;<br />
if(distance == Double.POSITIVE_INFINITY)<br />
goalVel = currentCommands.getMaxVelocity();<br />
else <br />
goalVel = Math.min(getMaxVelocity(distance),<br />
currentCommands.getMaxVelocity());<br />
<br />
if(velocity >= 0)<br />
return Math.max(velocity - Rules.DECELERATION,<br />
Math.min(goalVel, velocity + Rules.ACCELERATION));<br />
//else<br />
// changed here:<br />
return Math.min(Rules.ACCELERATION,<br />
Math.min(goalVel, velocity + Rules.DECELERATION));<br />
// we don't need a Math.max, because the goalVel can never<br />
// be below zero (because distance is always positive)<br />
}</syntaxhighlight><br />
--[[User:Positive|Positive]] 01:00, 19 July 2009 (UTC)<br />
<br />
Oh my! I didn't realize "getNewVelocity(-0.1,1000000000) == 1.9" about the version in Alpha2 before... to me that seems like a really really bad thing, because of this scenario:<br />
<syntaxhighlight><br />
getNewVelocity(-1.0,1000000000) == 1.0<br />
getNewVelocity(-0.5,1000000000) == 1.5<br />
getNewVelocity(-0.1,1000000000) == 1.9<br />
getNewVelocity(0.0,1000000000) == 1.0<br />
getNewVelocity(0.5,1000000000) == 1.5<br />
getNewVelocity(0.9,1000000000) == 1.9<br />
</syntaxhighlight><br />
The sudden jump in output between -0.1 and 0.0 doesn't make any intuitive sense at all I think. It really should be limited to 1.0 like in the old code, unless more accurate handling is done (as in Alpha3) --[[User:Rednaxela|Rednaxela]] 05:03, 20 July 2009 (UTC)<br />
<br />
Actually, Alpha2-style is also how the old code does it. You can go from -0.1 to 1.9 in Robocode 1.6.1.4. Positive, I noticed Skilgannon changed that, but I think the old way and Fnl's new way were the two main choices up for consideration. --[[User:Voidious|Voidious]] 05:12, 20 July 2009 (UTC)<br />
<br />
Ugh... I'm really really against the old way then, since it then makes it notably advantageous for a bot to optimize it's movement to do things like -2.0, -0.0000001, +1.9999999, instead of -2.0, 0.0, +1.0 as would be logical... It seems like a ridiculious quirk to have to optimize to... --[[User:Rednaxela|Rednaxela]] 05:56, 20 July 2009 (UTC)<br />
<br />
Well, I agree with Rednaxela that the way of the old code is obviously somewhat bugged (why be able to go from -0.00000000001 to 2.0, but from 0.0000000001 only to 1.0?). Capping it at 1.0 makes sure it can't really be exploited, and thus does not force programmers to make strange "never go to 0, only go to 0.000000000001" functions to exploit this. I believe many bots nowadays almost only travel in integer speeds, so capping shouldn't affect them much. In contrast the new idea rules will affect most robots (somewhat), and disallow them to stay at integer speeds while decelling through 0 from 1.0. My thought is that although the new time-based calculation is much more correct, capping keeps the game simpler. So I think it should also be considerd as choice. --[[User:Positive|Positive]] 06:07, 20 July 2009 (UTC)<br />
<br />
Just my 2 cents... My feeling is that if we're going to change it, we should change it to the completely correct (split-tick by Fnl) version. Capping at 1 is a kind of middle ground, but it is still "incorrect", and it still introduces a strange optimization quirk: from velocity 2, it's always better to decelerate to 1 than to 0, since you can still get to -1 but you can also get back up to 2. I agree its impact would be much less on surfers, but if it doesn't fix the problem that Fnl set out to fix in the first place, I'm just not sure we'd want to change it at all. --[[User:Voidious|Voidious]] 12:58, 20 July 2009 (UTC)<br />
<br />
== Buggy Alphas? ==<br />
<br />
Hmm, are you sure? Darkcanuck ran a lot of tests on all the alphas and didn't find this bug, right? Anyway, if there are bugs in the alphas, I guess I'd vote to have more and re-run tests on the matchups that showed score differences. If all the differences went away, it might convince me to vote Alpha3. But that would cause more delay in 1.7.1.4, too... --[[User:Voidious|Voidious]] 22:13, 7 August 2009 (UTC)<br />
<br />
Okay Voidious, since you did most of the test anyway for the Alphas and seems to be fine with it, I will create 3 new alphas to replace the old ones. I guess that Darkcanuck did not check the getDistanceRemaining() like I did recently, and hence discovered the bug. --[[User:FlemmingLarsen|Fnl]] 22:17, 7 August 2009 (UTC)<br />
<br />
Cool, sounds good. If this does eliminate a lot of the score differences, I would probably change my vote to Alpha3. That would really be ideal... but we'll see what happens, I guess. Thanks for your patience and diligence with this, Fnl! --[[User:Voidious|Voidious]] 22:25, 7 August 2009 (UTC)<br />
<br />
Ok, I think I see the source of some of the confusion. I tested all the routines proposed on the wiki (which may not be exactly the same as in the alphas) based on the idea that if distanceRemaining=0, then the bot is trying to stay at its current location so it may need to reverse if its velocity is non-zero. However, the API docs for <code>setAhead()</code> state that if the distance passed is zero, then the bot should decelerate to a stop -- none of our routines take this into account. But this doesn't mean that if distanceRemaining=0 then the bot should just decelerate, since there are cases (say velocity was 8 and we called setAhead(2)) where we need to correct for potential overshoots. So really what's needed is to add a "stopping" flag that's set when setAhead(0) is called -- this would be separate from distanceRemaining and would force the bot to slow to a stop (and ''then'' set distanceRemaining=0). --[[User:Darkcanuck|Darkcanuck]] 05:19, 8 August 2009 (UTC)<br />
<br />
Hmm... you're right about what the API says, though to me anyway, what the API says seems odd. It means that setAhead(-0.00001) and setAhead(0.00001) mean nearly the same thing, yet setAhead(0.00000) can mean something very different than either of the other cases. This is indeed what the API docs specify, but that does seem... quite odd, at least in my mind. --[[User:Rednaxela|Rednaxela]] 05:23, 8 August 2009 (UTC)<br />
<br />
: I agree, it was weird when I read it and I would much prefer the "hold this position" interpretation. But this whole thing started out trying to get the engine to follow its own published rules... :P --[[User:Darkcanuck|Darkcanuck]] 05:25, 8 August 2009 (UTC)<br />
<br />
: I am really sorry about the fuzz. I found the problem, as I thought I might as well put Positive's updated updateMovement() method into the SVN, and then decide on which getNextVelocity() to use for it later. However, running the test units showed that the velocity was correct, but not the remaining distance when we are at a velocity > 2 and then call setAhead(0) when there is still some remaining distance. Here it will take 12 pixels for the robot to brake, and it will end at a remaining distance = -12 compared to when we called the setAhead(0). This behaviour is the correct one compared to 1.6.1.3 (I did not invent the original rule). So when I ran the test units yesterday only changing the updateMovement(), a few test units failed due to the remaining distance that ended at a distance remaining = 0 instead of -12. I am no sure how big the impact is on our tests and the RoboRumble, but it truely is a bug introduced in the old alphas (2, 3, 4), and hence our results from the tests might be wrong. I guess they are. --[[User:FlemmingLarsen|Fnl]] 05:45, 8 August 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Pedersen/Ugluk&diff=16925User talk:Pedersen/Ugluk2010-07-01T08:42:52Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>I enjoy your enthusiasm. <removed obsolete comments> If you want a good indication of Ugluk's melee strength, you might want to start with some classic well-rounded competitors: gg.[[Wolverine]], intruder.[[PrairieWolf]], emp.Yngwie and tzu.[[TheArtOfWar]] come to mind. Cheers. --[[Corbos]]<br />
<br />
I was running [[Ugluk]] 0.4.0 against [[Stampede2]] 1.1.0 and I noticed that when [[Ugluk]] is entered second into the battle, it doesn't fire at all for the first 2-3 rounds. This happens consistently, but only against [[Stampede2]](as far as i know). I ran [[Ugluk]] against several other bots with the same setup but could not recreate the results. Anyway, just letting you know about a potential bug. <br />
EDIT: I ran a few more tests, it looks like it has something to do with the fact that [[Stampede2]] only moves when fired at. --[[wcsv]]<br />
<br />
I noticed some odd reluctance to fire as well, and eventually I tracked it down to a line that basically says if the expected hit percentage is too low, don't take the shot. After commenting out that line Ugluk was firing once again. Last night I uncommented the same code and Ugluk is still firing, but at a better hit rate. I recently added energy management statistics and overhauled the internal movement prediction engine, but at some point I dropped from second place against the Freya line of bots (Freya in 1st) to dead last. I am trapped in a cycle of playing with movement combinations and other settings. Also known as polishing a turd. -- [[ Martin Alan Pedersen ]]<br />
<br />
I found the bug causing Ugluk not to fire against a non-moving target. Three factors went into it. I was dividing a long by a double of the same value when I had a 100% virtual bullet success rate, which evidently was the root of the issue. Also against a sitting duck there are only two guns that I have that won't hit 100% of the time; tangental oscillation and mirror guns. In 0.4.0 those guns were disabled to reduce computation time. If they hadn't, one would have fired at some point and made you move, which would have snowballed into all guns being fully operational (and rather over-confident). I've a few more bugs to ferret out before I release 0.5 though. -- [[ Martin Alan Pedersen ]]<br />
<br />
While refreshing my memory of the virtual bullet engine, recently refactored to better compliment the wave system I'll use for guess factor targeting, I noticed a nasty redundancy that I thought has been cleaned up in an earlier fix. The short of it is that my targeting statistics and wave surfing data were garbage. With a quick repair I turned Ugluk's performance around and made him the star performer I knew he should be. While 0.4.3 was trailing about 100 ranking points compared to 0.4.0, 0.4.4 is leaps ahead. --[[Martin Alan Pedersen]]<br />
<br />
Found another bug, this time in my linear and circular mean targeting methods. Maybe they won't suck so much now. I overhauled my firepower selection mechanism to shoot at the best product of hit percentage and damage. Should make for higher powered shots (but not much higher) in the opening ticks of melee battles where things are packed together, and higher velocity shots as things thin out. Testing it now against the bvh.* crew. I've also earmarked my present virtual bullet system as 'virtual', and shots actually fired as 'actual'. My virtual bullets will feed my regular battery, which will fire actual bullets which will feed my fired bullet stats, which will feed my guess-factor gun (which will also be part of the virtual gun array). After a little while the guess factor gun may become favored over the other guns and take over. Then your bot will be a smouldering heap of rubble. --[[Martin Alan Pedersen]]<br />
<br />
It was nice to see Ugluk taking first place in melee battles in the Rumble for a change, though I'd seen many 2nd place finishes before. 2nd place is 1st place for losers. --[[Martin Alan Pedersen]]<br />
<br />
''[[Freya]] - Diety or no, I shall eventually crush you under my heel. Thus far you have eluded me, but there are only so many blindspots to hide in. As the veils of my ignorance are lifted, your destiny may be more clearly seen.''<br />
<br />Not before the [http://www.pantheon.org/articles/g/gotterdammerung.html "Gotterdammerung"] if i have it my way. So i will take up the challenge. I guess i have at least 20 'blindspots' left in melee to hide. ;) --[[Loki]]<br />
<br />
I haven't been actively coding lately, having purchased a new machine that took about 4 days to get running. I'm also low on ideas of how to improve Ugluk's performance. I made a significant leap with Ugluk's movement but the guess-factor-like gun has not been the gun of choice against any opponents thus far. I think my next step is to make the bin divisions parameter driven so that I can have multiple guns and eventually dynamically segment (or implement some other catch-phrase). -- [[Martin Alan Pedersen]]<br />
<br />
Well, I made an innocuous adjustment in melee and it went awry, but my dueling tweaks were an astounding success (v0.6.1). -- [[Martin Alan Pedersen]]<br />
<br />
Melee is hard to grasp, small ''improvements'' tend to let you loose 10 places. One-on-one is a lot easier to improve. By the way, what do you mean with 'Domination'. -- [[GrubbmGait]]<br />
<br />
Well, each rumble has a different number of opponents, so my getting 38th in melee looks a lot better than 123rd in duels, though they are about the same in terms of what percentage of the competition I am doing better than, which is my 'domination' figgure. My best melee bot (so far) can beat out 75% of the melee rumble entries, and my best one on one bot can beat out 69% of the opponents. When I hit 100%, it means I've finally beaten [[Ascendant]] (or whomever beat me to it). So.. it is just my way of putting Ugluk's ranking into prespective. -- [[Martin Alan Pedersen]]<br />
<br />
Ugluk 0.6.6 simply does nothing in most matches on my system... So every result comes back with Ugluk losing 6,000-something to 0 (which I think just discounts the match completely because of the zero). No errors printed to the console or anything. I'm using Java 1.5 to run Robocode, FYI. (I actually just noticed a match vs TheBrainPi where it didn't get 0, but that was the first I noticed that wasn't.) -- [[Voidious]]<br />
<br />
Part of that is me being mean. He won't even try if the battle is not 35 rounds long. It hampers exhaustive tests against him, while still allowing him to compete in the rumbles. Evidently I failed to test my recent modifications to the kill switch implementation. Doh. Ah well. It was pretty funny to barely beat SittingDuck. -- [[Martin Alan Pedersen]]<br />
<br />
Hm.. I removed 3 guns that I didn't think we all that necessary .. and it turns out I was wrong... good thing I make regular backups of my code. -- [[Martin Alan Pedersen]]<br />
<br />
Re: "me being mean..."<br />
Martin, if you ever do make it to #1 in these rankings, I'm going to dub you "the Bill Gates of Robocode". :) -- [[Voidious]]<br />
<br />
A small price to pay.<br>I fixed some errors and added the mostly useless pattern matcher. -- [[Martin Alan Pedersen]]<br />
<br />
"Momentum = 1.9273471707492718E-13" .. I'd say that's pretty stable. -- Martin<br />
<br />
Congratulations for breaching the 1700-barrier, next goal 1800?? or maybe 1700 in melee?? -- [[GrubbmGait]]<br />
<br />
Thanks. I'm looking to get in the top 20% of melee, which would be ~1666. Not sure how it's gonna happen though. I still only rarely beat Freya 0.31 in my test melee battles. -- Martin<br />
<br />
Martin, i allways get a NullPointerException in "setPerformanceStatisticsTracking" with Ugluk 0.7.2 (in melee). But as it is currently ranked 45 in melee, it has to do with my set-up (Java 1.5.0) and not with Ugluk. Any ideas? --[[Loki]]<br />
<br />
Heh .. just me being a jerk again, though I wasn't being as clean about it. I've fixed the code so Ugluk will just sit there doing nothing and not throw the exception. Ugluk won't participate in battles that aren't 35 rounds long! He's sneaky that way. -- Martin<br />
* mmmm, so except for a fighting-strategy you also have included a strategy to hinder me developing new ideas and test them... ;) Well, now i understand why in my normal testing (50 times a 35-round battle) i got normal scores for Ugluk, but when i ran some 1000-round battles today with Robocode to watch my new movement i saw a rather unconvincing 'sitting duck'. --[[Loki]]<br />
** well, in terms of testing against someone you will be competing with in the Rumble, a 1000 round battle gives you tainted information. My guns have more data to work with and will be firing more accurately, as will yours (though I've found yours are better than mine in 1000 round battles), so the scores may be more stable but don't reflect scores of Rumble battles. I set my battles-per-bot to 1200 so I'll fight all my opponents three times (on average) before I mark down a 'final' rating. Three fights leaves a lot of wiggle room.<br><br />
I guess the Roborumble isn't everything though. I should be flattered that you want to secure dominance over Ugluk. Then again, I've got the same ideas about your bots... -- Martin<br />
<br />
I refactored my bearing offset gun segmentation to represent the segments as objects instead of a multidimensional array. This was a brain draining undertaking, but it should help the cleanliness of trying out new segments. I'm submitting v0.7.3 as a baseline for the changes, and v0.7.4 will likely have new segments that have promise. -- Martin<br />
<br />
Hey, welcome back from your brief absence. By the way, I'm honored that you find my bots to be a worthy challenge. --[[wcsv]]<br />
<br />
I remember getting Stampede2 from the repository when I was just getting started with Robocode and I didn't realize how strong it was because I was running melee battles. When I decided to work on duels I did some 25 round tests against Stampede2 and Chomsky. Once in a while I'd get one or two wins against Chomsky, but Stampede2 shut me out every time. I can beat Stampede 1.3.3 now, but your other two bots are leaving welts on my hindside. ( I can also nearly beat Chomsky 1.5 but Chalk is out of my league for now. ) - Martin<br />
<br />
Ya know, I had a dream last night where I saw some kind of sign post labeled "Ugluk"... And I thought to myself, in the dream, "Oh, that's weird! That's the same name as Martin's tank." Maybe it's time to spend less time on this wiki... ;) -- [[Voidious]]<br />
<br />
Added a screenshot from World of Warcraft. Now you can dream of Ugluk himself. -- Martin<br />
<br />
<pre>Fighting battle 21 ... pedersen.Ugluk 0.7.5,kawigi.sbf.FloodHT 0.9.2<br />
RESULT = pedersen.Ugluk 0.7.5 wins 2623 to 2518</pre><br />
<br />
Cool. I grabbed this version and ran a few battles with it. I'm pretty impressed; 0.7.5 seems to be much better than previous versions in duels. FloodHT is a really strong bot, keep up the good work! --[[wcsv]]<br />
<br />
Thanks. I introduced two new segments to my bearing offset gun with 0.7.4 but nothing happened. With 0.7.5 I added some decay to the movement stats (introduced with Butterfly 2.0) and a new wave surfing movement that waits until the last moment to go to the bearing offset, rather than going immediately and waiting for the wave. Evidently it works. I also did some tuning against the lowest ranked bots in the rumble to squeeze the most points I could out of them, but I doubt that was a significant portion of the boost to Ugluk's rating. -- Martin<br />
<br />
Top 100 with over 500 battles! Congratulations! --[[wcsv]]<br />
<br />
Welcome to the Robocode[[High School]] by entering the top-100! You sneaked up on me while I was busy with melee, no hard feelings for that, and I intend to improve GrypRepetyf shortly so be warned. You can easily compare two versions of [[Ugluk]] to see the impact of your changes. Click http://rumble.fervir.com/rumble/RatingDetailsComparison?game=roborumble&name1=pedersen.Ugluk%200.7.5&name2=pedersen.Ugluk%200.7.4 to see the difference between 0.7.5 and 0.7.4. -- [[GrubbmGait]]<br />
<br />
That link (modified) will come in handy soon. I just placed two 'new' version of Ugluk in the Rumble. Ugluk v0.7.5a has some additional tuning against below-average bots. Ugluk v0.7.5x has all opponent-specific tuning turned off. It is 60% of the size of the tuned version. This comparison should tell me two things: How much my rating is improved / inflated by the tuning, and what tuning is obsolete due to advancements in the bot since I started. -- Martin<br />
<br />
So far the results are unsettling. The ratings are within 5 points of one another after over 300 battles each. I'll see if there is any information to glean from the comparison of 1200+ battles each, but so far it looks like I need to retest each of the opponents (unless I am already crushing them) with each advancement in movement or targeting. Ah well. -- Martin<br />
<br />
Ultimately, I don't know if a bot-specific approach is scalable. Better to work your ass off figuring out a generalized strategy. I noticed your 'profile' classes and wonder if it's worth it. Bot-specific logic is rigid. Seems like the holy grail is ultimate flexibility. --[[Corbos]]<br />
<br />
If by scalable you mean that as time marches on the bot can adapt .. well .. if I'm not paying attention I don't much care how well I am doing. Also advances in movements and targeting over time mean your bot is going to go by the wayside if you aren't developing it (eventually).<br><br />
My approach to the tuning takes manual repetition of running battles, adjusting, and running more battles. For each opponent. It is time intensive and the Rumble rating gap is telling me it ain't fricken worth the trouble. I am guessing that my primary boost came from the dynamic elimination of inferior movement techniques. The more adaptive Ugluk gets the less of a need for hard-coding.<br><br />
That said, I still plan to revisit pre-loaded enemy data when I implement a [[CribSheet|crib sheet]] or something like it that I can use to tune a statistical gun with x rounds of test data. -- Martin<br />
<br />
I'm sure the data is valuable. Still, hard-coding == bad ju-ju. ;) --[[Corbos]]<br />
<br />
Did some crazy wide-scale seat of the pants refactoring to allow my guns to target Ugluk. I also added a movement method intended to dodge all incomming virtual bullets fired with those guns. It is not very mature, but my score climbed back up to the enemy profile version, though profiles are presently not used. I will probably leave them disabled until I get a real statistical wave surfing movement, rather than just the two styles of random offset go-to's I have now. Right now it feels like I'm doing everything I can to put off my next overhaul of my statistical guns, though the recent changes are groundwork for it. -- Martin<br />
<br />
I've been making tweaks to my melee movement and nothing is having a tangible impact on my rating. It is quite frustrating. -- Martin<br />
<br />
I know the feeling, the one-on-one changes to Gruwel should not have impact on its melee-performance, but it dropped from 29 (0.2) to 40 and I never got it back on its level (yet). -- [[GrubbmGait]]<br />
<br />
I'm gonna be working on a redesign of my bearing offset gun for a few more days. I am designing it to allow the segmentation granularity to be adjustable as the population increases. At this point I do not know how I'm going to decide when to make that adjustment. I'll probably have to do some measurements akin to those discussed on the entropy page. -- Martin<br />
<br />
I've introduced some nifty stuff in terms of my bearing offset gun with v0.8.0. I am hoping it can tackle some of trickier movement algorithms out there, and maybe catch some napping surfers. Time will tell... -- Martin<br />
<br />
Whoah, some weird stuff going on with Ugluk's ranking... He's "at 1990", but underperforming by 10+ points against everyone in his list but 1. (That just doesn't make sense.) Any idea what's up? -- [[Voidious]]<br />
<br />
I'm more curious than anything, as I know it will stabilize. Maybe the first match was vs FlamingKombat, and skyrocketed the ranking immediately? -- [[Voidious]]<br />
<br />
First two matches were Shiva and micro.Freya, uploaded with a 2012 rating, both 20 points in the red. I dunno how the rating thing makes the original ratings, but it's pretty nuts in the beginning. -- Martin<br />
<br />
Weird indeed! I thought it started you at 1600 and adjusted from there? *shrug* -- [[Voidious]]<br />
<br />
New bots should start with 1600, updated bots should start with the rating of its previous version. Alas there is some flaw somewhere, so Ugluk started with the rating of the old Pugilist or Dookious or so. If the momentum is high ( > 15) positive or negative, the rating has not stabilized yet. If you have a momentum of -300, your next battle will let your rating drop by 3 points! -- [[GrubbmGait]]<br />
<br />
By the way, twice throughout the night, Ugluk crashed with an "Out of Memory" error, and I had to restart my RR@Home client. -- [[Voidious]]<br />
<br />
I also saw this error last night, but I couldn't get it to happen again so I ignored it. --[[wcsv]]<br />
<br />
Hm.. sorry about that. He's started logging more wave data but in tests he didn't start having heap errors until around 200 battles. I have my batch files allow 512 megs instead of 256 so maybe that's why I haven't seen it crash any of my Roborumble machines. I'll see what I can do about managing the memory better .. -Martin<br />
<br />
It turns out I was logging all waves instead of just the non-virtual ones, so that's about 100x as many as I was expecting. 0.8.1 will address this problem (after some more tuning). -- Martin<br />
<br />
Hmm, sorry to nitpick, but... Isn't it a max of 16 ticks between bullets at maximum fire rate? =) -- [[Voidious]]<br />
<br />
A while ago I reworked my virtual bullets and waves so that all bullets (virtual or not) are just a firing angle attached to a wave. This is really smooth for non-virtual waves because the firing solution that is selected for the shot becomes the wave and then all targeting systems are repolled with an exact bullet velocity constraint, each targeting system returns one (or no) firing angle that it would use, and all of those angles (and a reference to the source targeting system) are attached to the wave.<br />
With virtual bullets each targeting system can have tens of firing solutions each round, none of which are coordinated with one another (sharing a wave). Typically I've got 9 targeting systems, so let's say each produces 25 firing solutions for 16 ticks. That's 3600 waves with one firing angle attached. One of those is selected (in tick 16) as the primary and flagged as non-virtual. So really I've reduced my storage to 1/3600th, not 1/100th, but I didn't feel like doing the math at the time. It's an area I could tidy up a bit, but I don't think it will affect my rating. -- Martin<br />
<br />
Ah, I see what you mean now. Yeah, I use a similar integration of Waves and VirtualGuns, except I've only got 2 guns each with 1 firing solution attached to each wave ;) -- [[Voidious]]<br />
<br />
Finally.. I win!<br />
http://home.comcast.net/~kokyunage/robocode/asif.jpg<br />
<br />
Well, I screwed something up with 0.8.2. I removed the breakdown of hit percentages by bullet flight time and started playing with rolling averages. Oh, and I revamped the targeting engine. And altered the functionality of two guns. Hmm.. well, good thing I have make regular backups... -- Martin<br />
<br />
With 0.8.2 I revamped the targeting engine, affected the stats feeding my two Mean guns, did some tweaking to my latest movement, and eliminated all virtual wave creation / processing. (I still have waves based on actual shots taken.) It cost me 8 points, but I lost them really really fast. I'm sure the point loss is a combination of the tweaked guns and movement, complicated by hard-coded enemy profiles. The main reason for the rating plummet with 0.8.2 was that I'd eliminated the [[BulletTravelTime|timeToTarget]] range aspect of my statistics, lumping them all together. It was a bad move, and one I had to manually restore from a backup.<br><br />
I'm presently tuning a [[MinimumRiskMovement|new movement]] for melee and I need to debug / improve the implementation of my top secret (until it works) organically segmented bearing offset gun (which paid an unsatisfying 10 rating points upon introduction). -- Martin<br />
<br />
Have you done something special to upload only single results in melee, I have always and still am uploading the double results. This means I generate 18 results per bot per battle. I assume you are running meleebattles today, as Ugluk is the last updated meleebot. -- [[GrubbmGait]]<br />
<br />
Yeah whatever version I have of the RoboRumble@Home is doing what I suggested a while back .. only reporting battles of the present bot and the bots it has beaten, so the first bot reports 9, second 8, and so on. #10 doesn't report anything. I do not know if it is something I downloaded or if I made the change in the source code myself. I can zip up the compiled version (I think I sebsequently doinked the source code with further tweaks) and make it available if you like.<br><br />
On an unrelated note, my scores really took a nose dive even though I tested a lot against GrubbmGrb to get some kinks out of my gun (and enhance it). I did fine against GrubbmGrb in the Rumble, but something went awry elsewhere. I suspect I've messed up my hit statistics, making it favor my new gun always, when simple targeters work better against others. -- Martin<br />
<br />
Evidently Ugluk has gone Zoolander .. he cannot fire left. He can aim left, but won't fire. Shouldn't be too hard to track down .. though it has taken me hours of other testing to notice it. -- Martin<br><br />
Follow-up: I once again fell victim to the comparison of two angles when one is always positive (turret heading) and one is relative to another heading. My position.getBearing( position ) function returns a value [-pi,pi]. Bah. -- Martin<br />
<br />
While Ugluk's rating is not stellar, and is a few points shy of his highest, he is presently (v0.8.5) doing it all with 1 gun and 3 movement options. His melee movements are different, but the same single gun (which isn't working out for melee). There are also no enemy profiles active. I'm suprised by the relative success so far. -- Martin<br />
<br />
That's really cool; nice work. As I've continued to do Robocode, I've found that the [[KISS]] principle really can improve performance significantly in addition to its other benefits (cleaner code, easier testing, more consistent performance). I think sometimes a more complex solution ends up getting in the way of your simpler solutions as much as it is helping to augment them in other areas. -- [[Voidious]]<br />
<br />
Ugluk has been floundering somewhat lately, so I am going to focus on getting him to a satisfactory level of achievement in duels, then leave duels behind for a while and focus on the highly disturbing game of the free-for-all. -- Martin<br />
<br />
I expect v0.8.8 to have a low initial rating but sharp improvement over time, depending on how many different machines are processing him. If I were running all of the battles from one machine I'm pretty sure he'd reach 1800. Then again, recent changes to Ugluk have been disappointing (aside from losing really really fast now). -- Martin<br />
<br />
What kind of stuff are you saving? I was under the impression that data-saving never yielded much more than about 10 points onto a rating. -- [[Voidious|Curious Voidious]]<br />
<br />
Well, when I was looking at data storage I was always looking at storing targeting information. Yet I realized when I was doing my tuning that the real gains in score ratio came from finding the movements that my opponents are weak against. So at present I'm just storing a list of identifiers for movements that suck against an opponent. Over time I eliminate underperforming movements, making Ugluk harder to hit, which buys more time to return fire, which increases my bullet damage and decreases theirs. The next release of Ugluk will begin with the persisted data of the former version, so the initial performance should get better over time. Basically I am doing similar performance tuning in an automated fashion. Rather than taking about 20 minutes a bot to test, code, and retest profiles, I can run the Rumble (or League, but I ran into the file i/o bug) to get similar results. Eventually I'll limit the gun selection through the same process, but for now I just went with my latest pimp sauce gun. All the discussion of virtual guns jinxed mine, and I haven't managed to figgure out what is making the stats go haywire. -- Martin<br />
<br />
Right on, I'll be interested to see how it turns out. I'm pretty sure you can use the "canoncaches=false" argument in your RoboLeague.bat to avoid the file i/o problem, if it's that security one that you're talking about. -- [[Voidious]]<br />
<br />
Unfortunately I've seen entries dissappearing out of the log, so something is going on to make Ugluk lose data. It needs some more testing. -- Martin<br />
<br />
I've added some fault tolerance and reworked the file reading portion of my code (I'll update the subsection later). I spent a few hours ferreting out the bugs in the process, and I think this version should be pretty solid. Time will tell. I'm predicting this basic bot (with bug corrections if they are found) will be my 1800 mark breaker. I am going to have a few hard-coded profiles that I will turn on (all are presently off) before I 'go gold'. Ram bots take some special mojo to stay clear of, but I have a working formula. [[GrubbmGait|GrubbmGait's]] [[GrubbmThree]] still gives me a good fight though. -- [[Martin Alan Pedersen]]<br />
<br />
As there are only three adequate [[RamBots]] around, they would not harm your ranking that much. I believe that if your close-range fighting is ok, this should be able to handle rambots also. If you can score 55% against rambots, I would not put any effort in it. There are more important issues to handle if you want to reach your goal. Every now and then using the [[KISS]]-principle can let you focus on the real problems instead of the unimportant details. See you soon on my side of the 1800 mark! -- [[GrubbmGait]]<br />
<br />
CassiusClay does a couple of things when its facing a rammer. Like evading steeply. And never evaluating the stop position in the WaveSurfing. And shortening the BlindMansStick in the WallSmoothing. Depening on movement system the counter measures will vary I guess. But one thing that's pretty general is to detect when you are facing a rammer. I keep track of the rolling average of the enemy bot's ApproachingVelocity. Like so:<br />
<syntaxhighlight><br />
enemyApproachVelocity = PUtils.rollingAvg(enemyApproachVelocity, enemyVelocity * -Math.cos(e.getHeadingRadians() - enemyAbsoluteBearing), Math.min(scans, 5000));<br />
</syntaxhighlight><br />
And I decide it is a rammer if this average goas above 4.5.<br />
<br />
Of course, Grub is right about it not being a problem one should generally bother with. For me it is that I am quite emotional about my robots and I hate seeing them get abused. =)<br />
<br />
-- [[PEZ]]<br />
<br />
I have viewed a few battles in the past and CC has a very elegant way of evading rambots. CC (and Ali) are the only bots that score 70+% against GrubbmThree, but now I know how to counteract! I will set the max velocity to 4 and start ramming then! ;-) -- [[GrubbmGait]]<br />
<br />
Hehe, please do. =) -- [[PEZ]]<br />
<br />
Won't work for me - I keep track of the ratio of ticks that you are heading right at me vs not right at me to detect a rammer ;) And I just fire power 3 if you are a rammer, and that's enough to get Dookious over 60%. -- [[Voidious]]<br />
<br />
Ooooh, now I get it! =) I should just not comment on anything until I've eaten lunch... -- [[Voidious]]<br />
<br />
My virtual guns array is really performing poorly. As I have not found any outright bugs in it yet, coupled with the observation that the loss of hit percentages by bullet flight time really hurt the bot, I suspect that my removal of all virtual waves is to blame. It really sped up Ugluk to no longer create and process them, but they provided stats by range to fall back on when the real bullets had not fired at that range yet. At present I am relying on a bearing offset gun to kill all my (unprofiled) enemies, so I'm not killing nearly as fast as I could be. I think I can re-introduce a different implementation of virtual bullets / waves that I can turn off after the first round, if not sooner. -- Martin<br />
<br />
After several releases Ugluk is finally pushing his rating past 1750 again. I've added weapon selection to the tuning system, which means Ugluk will get gradually faster, processing only 3 targeting systems instead of 10. v0.9.0 saw the return of virtual bullets, redesigned and no longer using the wave system (which was overdesigned since they don't share waves). I also abandoned rolling averages in my virtual gun hit stats, though it seems like it makes sense. Then again if you want to ride a wave you have to be ahead of it, not chasing it. My approach to movement, using a variety of crappy systems rather than one good one, relies on three tuning systems; hard-coding (fixed), learning (between battles), and performance (mid battle). My guns have the same tuning methods, but movement performance has a more drammatic impact on rating than gun performance. -- Martin<br />
<br />
I don't know if you noticed (now you do), but Ugluk has 4 more wins than GrubbmGrb in the PL. You are going in the right direction, but still have 50 points to catch up on. -- [[GrubbmGait]]<br />
*I'm bumped down to only one spot above GrubbmGrb. I have managed to beat all of your bots again, which I hope you take more as a sign of respect than an insult. I've nearly got all of Loki's as well but Friga was only fought once and I only managed 47%. I've got another ace waiting up my sleeve for the next Ugluk, which may take me that much closer to 1800. I don't know if it will help me in the PL. For some reason I don't really pay much attention to the PL ranking, even though it appeals to my 'player vs. player' online gaming background. (In PvP it's not about style, it's about who is left standing.)<br />
<br />
I'm not sure rolling stats makes sense in targeting. It would only make sense against MultiMode and AdaptiveMovement like WaveSurfing. And that's quite few bots. And to actually make a difference you need really fast rolling stats. If you have VirtualGuns then it's better to have one gun just remembering the last sample and one that accumulates the stats without rolling. Aiming for the middle ground just lowers your performance in both ends I think. -- [[PEZ]]<br />
<br />
I've been working on a bullet-avoiding-but-otherwise-random movement mechanism. It has gone through some evolutions, but still has some unfinished features and bugs to work out. I also maintain a list of people for which ramming (and firing) gets me a better relative score. It is not a dynamic decision. -- Martin<br />
<br />
Fixed some long standing bugs with this cut. Also worked out some (but not all) kinks in my new bullet-avoiding-but-otherwise-random movement. I may do a release that uses the movement exclusively, along with my not-fully-segmented-because-I'm-still-working-on-collecting-the-necessary-data bearing offset gun. -- Martin<br />
<br />
I managed to boost Ugluk's gun performance by a hair under 50% from a few versions ago. I don't know if it is the bug fixes or the most recent (unreleased) segmentation. Hopefully it is the segmentation .. because the bug fixes don't seem to help the roborumble rating much. -- Martin<br />
<br />
Nice job on your gun work there - that is no small jump you made! Especially against the surfers. -- [[Voidious]]<br />
<br />
Thanks. Turns out I also bumped up my wave surfing challenge scores, but only by a little over 25%. I'm expanding my debugging code to figgure out where the bugs are, though it could come down to a simple difference of targeting algorithms... -- Martin<br />
<br />
I'm getting "file not found" for this version of Ugluk, and I think I may have for the last version, too... -- [[Voidious]]<br />
<br />
Judging by my rating it looks like I broke something too. -- Martin<br />
<br />
Well, it was finally time to revamp my physics engine, which I've done, and now I have 76 JUnit tests backing them up. Next I need to track down an error with my radar, so I'll probably reinforce those systems with JUnit tests as well. Eventually I'll get tests set up for each of the targeting methods so I'll have more confidence making changes in that area. The testing is a bit of overkill but I've fairly frustrated with the performance of my targeting methods and ensuring that they are behaving as intended. My attempts to emulate the Robocode client environment have not gotten me anywhere. -- Martin<br />
<br />
Can you publish your unit tests? I am always planning to make a bed of unit tests for CassiusClay, but I never know how to go about it. If you can't publish it then maybe you could give your thoughts and advice on the matter on the [[UnitTesting]] page or some such. -- [[PEZ]]<br />
<br />
I can't download Ugluk, what's happen? -- [[DemetriX]]<br />
<br />
The main problem with learning about opponents through saving data is that the data is spread out among all of the machines running the robot. From time to time I run Ugluk from only one machine (in this case from work over the weekend) and this is why you can't get to the .jar file. It isn't really there. The .jar file is in my work machine's roborumble/robots directory though, so it doesn't need to look for it. The alternative is to make about 5 versions of Ugluk to collect the same data, creating a lot of unnecessary processing work for everyone running the rumble. -- Martin<br />
<br />
Ugluk v0.10.1 features the return of the fully segmented bearing offset gun and some bug fixes. v0.10.2 rams some specific bots rather than being a good sport. So far the score difference is negligible. Yet, it's still worth it. =) -- Martin<br />
<br />
A comparison between these two bots shows quite a lot of variance, even though the only difference is that there are maybe 9 opponents that .2 rams that .1 does not. <a href="http://rumble.fervir.com/rumble/RatingDetailsComparison?game=roborumble&name1=pedersen.Ugluk%200.10.1&name2=pedersen.Ugluk%200.10.2">Comparison link.</a> Perhaps it is time to get RoboLeague working with file i/o so I can have a more controlled test bed, with a consistent number of battles fought per opponent, and always facing all opponents. I can appreciate the effory it took to create RoboLeague, yet it's a pain in the ass to set up battles, especially when my setup has it picking up teams and roborumble class files as potential bots. -- Martin<br />
<br />
I rarely select the bots through RoboLeague itself - I manually create .xml files a lot with RoboLeague. For instance, I have "dooki086_mc2k6_base.xml", an MC2K6 template for my current dev version, and then I just make a copy of it and name it "dooki086_mc2k6_20060306_001.xml" to run a set of seasons with a certain build. And I do the same for whatever is my current testbed. I use RoboLeague a heck of a lot in my development, and my whole process would be a lot different without it! (It's pretty easy to edit the XML files, except that it's usually all on one line.) -- [[Voidious]]<br />
<br />
A while back I considered having a cross between partial linear targeting and my bearing offset gun. My partial linear gun defaults to 70% of present velocity, and for some opponents it is my best gun. For some it is the best gun at a different fraction of velocity. It would great if it turned out to be a formidable gun against many folks, if only I could teach it how to calibrate itself. If I can figgure out a practical means of determining after the fact what percentage range would have hit my opponent and track it like bearing offsets, I'll have what I want. I don't know how well it will do, but it's one more option in the battery. -- Martin <br />
<br />
The actual code wouldn't be much different than your standard GuessFactor gun - you would just make GF1 = linear aim for each wave instead of GF1 = max escape angle. Then GF0.7 would be 70% of linear aim, GF0 would still be head on, and so on. I think the idea of using linear aim as the "reference angle", instead of direct aim, in a GuessFactor gun might have some merit, too. (Like GF0 = linear aim. I think I've seen a mention of that somewhere else on the wiki.) -- [[Voidious]]<br />
<br />
You basically just described the idea behind [[Stampede]]'s gun, Voidious. --[[wcsv]]<br />
<br />
Oh yeah? Which idea, GF1 = linear aim, or GF0 = linear aim? -- [[Voidious]]<br />
<br />
It uses GF1 = linear aim, GF0.5 = 50% linear aim etc. It uses virtual bullets though, so I could probably improve on it by converting it to use waves. --[[wcsv]]<br />
<br />
100% linear aim would have to assume the target hits the gas this turn, or you wouldn't be able to hit people who accelerate from 4.0 to 8.0, for example. I could do it with virtual bullets for a discreet set of bins. I was hoping to have a wave-like means of determining what the linear projection percentages were that would have worked after the fact. It's probably a lot simpler than I am making it out to be, but I keep getting too distracted by other things to focus on it. -- Martin<br />
<br />
Well, if you assume a maximum velocity, you're pretty close to how "traditional" GuessFactorTargeting already defines GF1, which is just the maximum angle they could possibly get to before your bullet intercepts them. (Assuming they accelerate to 8.0 doesn't seem like "LinearTargeting" to me, it seems like "GF1", but it's really just a label anyway.) -- [[Voidious]]<br />
<br />
I don't really use guess factors, so I'm not the expert, but it seemed to me that those represented a fraction of movement tangental to the firing position. I'm looking at the target maintaining heading, going forward or reverse. The problem with not normalizing to the maximum velocity is that your percentages can easily exceed +/- 100. If they are stopped and hit the gas you've got an infinite ratio. It would be nice to scale it off of whatever the present velocity is, perhaps with a cap (like 800%). That might be better handled by segmentation. I dunno. I just want to get a prototype working. I've been sketching it out and I think I can make it work. I just need to check if I remember the Law of Sines correctly. -- Martin<br />
<br />
You're right that it wouldn't quite be a normal GuessFactor, but it'd be pretty close, especially in duels where perpindicular movement is the norm. Good points about zero velocity, though, and you are probably looking for a gun useful in melee battles, too (throwing perpendicular-ness out the window). In any case, good luck, I look forward to seeing how it turns out (and then hearing the explanation, maybe =)). -- [[Voidious]]<br />
<br />
I've tried several times now to get a profiler working with Eclipse, and evidently I need a lot of hand holding with it because I've tried 4 tools and none of them have worked. They keep throwing errors about missing files or otherwise calling me a schmuck. So.. I've decided to do the 'brute force' method of creating a stop watch mechanism for timing subsections of my tank. I decided to use a JRE 1.5.0 introduced System.nanoTime() to get more accuracy than the millisecond alternative. A cross section of my tank's operation looks like so:<br />
<pre><br />
Stopwatch combatantOperate: 87.910341747 seconds<br />
Stopwatch combatantOperateGun: 4.756166431 seconds<br />
Stopwatch combatantOperateChassis: 29.445992399 seconds<br />
Stopwatch combatantOperateTurret: 53.434751403 seconds<br />
Stopwatch combatantOperateScanner: 0.96735465 seconds<br />
</pre><br />
Indicating that my targeting is the main culprit of my speed issues, but movement is not far behind. I'll add similar timer support to the base classes to get a per-implementation profile. -- Martin<br />
<br />
Once again I've mangled my rating by removing range segmentation on my hit statistics. It's pretty crude but obviously effective. Still, I'm not happy with it, and I am going to try implementing segmentation like I have in my bearing offset gun. -- Martin<br />
<br />
Well, I've tinkered with quite a few things lately, and done a few overhauls. I'm happy with the new segmentation of hit statistics. It worked out pretty smoothly. -- Martin<br />
<br />
Ugluk v0.10.5 is purely an opponent tuning change compared to v0.10.4. All existing profiles are on, with many new ram opponents, including all rambots. I compared Ugluk v0.10.4 to Banzai v0.5, but that version of Banzai does not have the new segmented targeting statistics. I do not know how the new statistics will help or hinder Banzai... -- Martin<br />
<br />
For some reason ramming wasn't as effective for Ugluk as for Banzi, using the same code. But I'll have to track it down later since I've already reworked yet another section, dealing with waves. - Martin<br />
<br />
It's very early to speculate, but Ugluk v0.10.7 has been climbing steadily and after 40 battles is at 1774 with 108 momentum. In addition to fixing an issue with Ugluk's ram mode, I re-implemented an old feature in a new way, which I suspect is more to blame for the promising rating .. <br><br />
Ugluk v0.10.7 peaked at 1789 before his momentum finally reversed, after 90 battles. I expect it will flatten out somewhere between 1780 and 1800. -- Martin<br />
<br />
Good to see that you finally entered the top-75. Next is to beat the 1800 (top-50) barrier! -- [[GrubbmGait]]<br />
<br />
Ugluk was really struggling to make any progress. Part of it was that I'd remove stuff that didn't work well but I wouldn't replace it. I'm still missing some 'features' that were slow, but the reduced functionality allowed me to focus on better performance of the systems that mattered. Right now I'm trying to squeese the rest of the rating points (to 1800) out of performance tuning. My attempt to ram rammers to minimize my losses didn't work out well enough, so I'll be fiddling with anti-rammer stuff as well. -- Martin<br />
<br />
I'm working on the new gun and I've hit a slight snag, though I think I know a way around it. Here are some diagrams I threw together:<br />
<br />
http://home.comcast.net/~kokyunage/robocode/diagram1.jpg<br />
<br />
The target begins at known position [1] and has a known direction of travel (factoring in negative velocity). Ugluk has a bead on it (bearing offset 0). It travels to position [2], and the hit arc is projected through the original direction of travel line. Points A and B are scaled to the percentage of maximum velocity that would have taken the vehicle to those points, giving you your range, and you can drop the interval into bins. As you collect more data you get a smoother picture of where the target tends to be on that scale. Walls would tend to be at 100%, but also has some lower range values due to stopping at corners.<br />
<br />
http://home.comcast.net/~kokyunage/robocode/diagram2.jpg<br />
<br />
Above is one of the problems with this technique. The points of intersection are behind the firing position because the direction of travel has changed drastically. You may have noticed that point [A] is further from position [1] than point [B], so we can detect this situation and may be able to accomodate and even use the data for future firing solutions.<br />
<br />
<br>-- Martin<br />
<br />
Man, it's scary to think how that gun would react to [[Tron]]'s wiggling... -- [[Voidious]]<br />
<br />
It's gone through a few revamps already and still isn't working as well as my Linear and Partial Linear (fixed percent) guns. I think I'll have to add some graphics to debug it. It looks like I'm storing and returning legitimate percentages (of straight linear), so I'm either not projecting correctly or my partial linear gun is using max velocity. I forgot to bring in the code to work today so it will have to wait. -- Martin<br />
<br />
I've backed out some code changes, including the gun I was working on (which was ineffective). I am also working on using virtual waves again, but only when they prove more effective (such as against opponents that don't take their enemy's firing into account). -- Martin<br />
<br />
Ugluk finally penetrates the 1800 barrier. -- Martin<br />
<br />
Congratulations, you're getting closer and closer to v1.0, only three bots left to beat. As for melee, your current version has a better 'domination' than your best sofar. Due to the late flood of (sub)topmeleebots, the ratings are dropping and the former top-20 bots (like PulsarMax, [[Troodon]], [[Ares]]) have a hard time to stay in the top-30. I'll try to put some more effort in my WaveSurfing, just to stay ahead of you in OneOnOne. -- [[GrubbmGait]]<br />
<br />
My client can't download the newest version of your robot. -- [[Kinsen]]<br />
<br />
Yeah, sorry Kinsen. I am 'teaching' Ugluk what movement and targeting sytems don't work against rumble opponents. It's best if I only allow one machine to process the battles, otherwise I just have to keep making new bots because of the 1200 battle limit. If many people are processing battles I'm still only learning on one machine, where I'll grab the results. I'd do this with RoboLeague but I've never figgured out how to get the cannon caches thing disabled with it. So for now 0.13.1 and one or two more versions will just be available to my machine. Then he'll be public again.<br><br />
One thing I've observed this morning is Ugluk has challenged bayen.Squirrel and stelo.WangRobot about 30 times each but keeps scoring 100%, so the score is invalid. I wish they'd him me just once. -- Martin<br><br />
edit: and Grubbm, your wave surfing intimidates me. I will have to achieve my stated goals for v1.0 before you have time to polish it.<br />
* I know my surfing is quite impressive, that is the result when the best parts of BasicSurfer and my own bots are put together ;-) -- [[GrubbmGait]]<br />
** I haven't actually seen your surfing in action yet. I just know you have a highly competitive bot without it. I expect when you add in some guess-factor style targeting you are going to make me cry. -- Martin<br />
<br />
By the way, I have a line in my roboleague/launcher.properties file that says: ''user.cmdline=-Dsun.io.useCanonCaches\=false -Xmx512M'' ... [[Florent]] tipped me off to it, and I have used RoboLeague to collect data like that (for that [[Dookious]] version testing pre-loaded data). -- [[Voidious]]<br />
<br />
I have spent quite a bit of time developing a object-based bearing offset gun with dynamic resegmentation. As more data became available, the segments would determine if it was time to increase the 'buckets' by 1, and reprocess all previous scenarios and resulting enemy positions. At first there are maybe 9 total buckets, accounting for cominations of positive-only and positive and negative segments. After growing sufficiently, there may be hundreds of buckets. The premise was that initially you have very little data and you want to be able to take an educated guess as soon as possible. What I'm finding out though is that slicing your data finely isn't really making your guesses more educated. At least not in a 35 round battle.<br><br />
I also moved my virtual gun statistics to use the same dynamic segmentation.<br><br />
I think I'm going to make the gun a lot simpler, cut way down on the segments, and add in some randomness in situations where the odds of picking the right angle are slim to begin with. -- Martin<br />
<br />
Definitely agreed that more segments is not always good, and finding the sweet spot can be tough. I've been wondering for a while - why would you use bearings instead of GuessFactors in your statistical guns? To me, GuessFactors seem like an evolution of bearing offsets, and I see no advantage in using the latter. (GF1 at bullet power = 3 is a much different angle than at bullet power = .1, but they will both hit the same type of movement, generally.) -- [[Voidious]]<br />
<br />
Gut feeling. And it's easier. And I don't have a good mechanism for wall smoothing, so I cannot predict how an opponent will behave in that situation. And I'm presently not using rolling averages.<br><br />
For post 0.13 I've gutted a good chuck of the code, including inferior guns, segmentation, and my dynamicaly recalibrating bearing offset gun. I've a fresh simpler gun with fixed segments, and only 4 of them so far, with 625 elements, each holding a bearing offset bin array. I'm going to toy around with implementing (and debugging) various segments and try them out. To support this effort I'll also need a means for collecting bin hits across hundreds of battles to see if there are any consistent patterns for each segment. That should give a relative worth of considering that aspect of an opponent's situation in the gun. I think I'll revisit the [[Entropy]] discussion next.. -- Martin<br />
<br />
I didn't intend to hide my posting of 3 bots at once, but after 4 failed attempts to save the participants page, I started fiddling and it worked as a minor edit. /shrug<br><br />
This selection of Ugluk bots all have preloaded profiles disabled, 5 movement options, and one gun, with the same segmentations. The way the bearing offset is determined is the only difference.<br />
<ul><br />
<li>v.1a - the bin with the dominant visit count is selected.<br />
<li>v.1b - a random bin is picked, but bins with higher visit counts have proportionately higher chance of being selected.<br />
<li>v.1c - a shallow rolling average is used to track previous successful bearing offsets.<br />
</ul><br />
-- Martin<br />
<br />
I'm not sure where the "rule" might be written, but [[RoboRumble/ParticipantsChat]] has a bit of talk of only having one version of a tank in the rumble at a time. Not that I'm one to talk, with my daily [[Komarious]] releases, but it was kinda uncool to see "Ugluk...a vs Ugluk...c" come up as the first match in my RR@H client. -- [[Voidious]]<br />
<br />
You are right that you are not one to talk. It isn't very cool, but since I entered them at 10:30 at night and had 3 cpu's cranking the rumble throughout the night, it didn't impact much. And now there are three cpu's cranking through the daily Voidious release... -- Martin<br />
<br />
Indeed, it didn't cause much of a clog, so no harm no foul... but if there is a "rule" about not having multiple versions in at once, I think it should be followed. I do post releases often, but between them I also run lots and lots of tests, instead of letting the RR be my testing grounds. In other news, with my three clients as well as yours, this version of [[Komarious]] might stabilize faster than any bot I've ever seen in the rumble. -- [[Voidious]]<br />
<br />
Komarious is a pretty fast bot. I give it two hours. -- Martin<br />
<br />
I just noticed that my MC2K6 rating againt the Circular Targeting bot (C) is second only to Engineer. Linear Targeting (B) is still very high. I dunno why I am getting nailed by the head-on bot so much. Ah well. -- Martin<br />
<br />
Indeed an impressive score against botC, but I still stay the best non-surfer in the MC2K6. Btw, I released my first WaveSurfer with GF-gun, I propose that it does not count for v1.0 of Ugluk. -- [[GrubbmGait]]<br />
<br />
The very first undertaking with Ugluk (v0.0.1) was a wall collision avoidance algorithm. His movement was fairly simple (mostly straight with a little sine wave added to throw off targeting) but he stopped short of running into walls. Sometime later I revamped the movement engine to use vectors, and I have used wall repellant vectors ever since. I also added robot repellant fields and some others I toyed with. Subsequent movement methods have all boiled down to a suggested movement vector, and the sum of all vectors was where Ugluk wanted to go. With the wall repellant fields in place, I ditched the costly early wall collision avoidance algorithm.<br><br />
It has worked fairly well for a long time. One thing I didn't have though, which became very apparent when I introduced a grid go-to system, was that I didn't have a way to determine the fastest way to get from point A to B for any initial heading. For example, if Ugluk was heading north at a velocity of 8.0 and wanted to arrive 40.0 units to the east, Ugluk would bank right and go in a circle until the point ended up behind him, at which time he'd hit reverse and try backing into the position. He's rock his way to the destination as long as it took.<br><br />
Well, no more. I finally figgured out how to find the shortest path to my destination, and I'm pretty proud of it. I also take into account the location of walls that I may run into along the way, and avoid them fairly well - but not well enough yet. I still need to work out some kinks in that department. My most recent test had about 1.5 wall hits per round. I need to check the speed of those hits to see if they are really relevant. If I am hitting at less than 2.0 velocity then it doesn't really matter. Edit: about 80% of the hits are at 1.0 velocity. Must be a simple algorithm issue. -- [[Martin Alan Pedersen|Martin]]<br />
<br />
I've worked out the kinks in the 'least time from point a to b' movement, complete with wall avoidance and my own version of smoothing. My score isn't stellar, and not my highest, but Ugluk is damned fast and getting it done with very few tools. I'll be reviewing the poorly performing movement styles of the past (i.e every one I've made) and trying to make them work as I envisioned. -- Martin<br />
<br />
Got some decent wave surfing results finally. Hopefully this transfers to the Roborumble... -- Martin<br />
*While the wave surfing challenge scores were much improved, the other challenges saw sharp declines. Consequently, the rating didn't climb much overall. -- Martin<br />
<br />
I figgured I'd add some eye candy related to my movement engine overhaul. The first two screens are related, the third is from a different round. After the first wave options get more limited. I haven't begun to tackle multiple wave surfing yet. Yet..<br />
<br />
http://home.comcast.net/~kokyunage/robocode/ugluksg001.jpg<br />
http://home.comcast.net/~kokyunage/robocode/ugluksg002.jpg<br />
http://home.comcast.net/~kokyunage/robocode/ugluksg003.jpg<br />
<br />
The green box is the destination I am trying to reach. The orange box is my present direction of travel's intercept with the wall. The green wavy lines are my 'optimal' tangental paths of travel. Given my wall avoidance I probably need to make more than one pass after determining that my ending direction of travel is rather different than the tangent. The grey lines denote the original dead center bearing as well as the present maximum clockwise and counterclockwise rotations (as calculated by the tangental path prediction). The rings are my wave representation (as previously described on the RobocodeSG page). -- Martin<br />
<br />
Nice eye candy. Debugging graphics are enabled in Phoenix too, you can turn them to draw projected clockwise / ccw motion, enemy waves, values of various surfing components, and other goodies. =) --[[David Alves]]<br />
<br />
With regards to the WSC scores / RoboRumble correlation, I would add that I think the score vs BotA (HeadOnTargeting) is by far the most important one. ([[Komarious]] gets relatively bad scores against BotB and BotC, but still gets a lot of rating points out of her WaveSurfing.) Nice graphics, too, they really do help a lot in the WaveSuffering process. -- [[Voidious]]<br />
<br />
Ugluk v0.14.6 kicked Grishnak's ass 2:1 in my first (and so far only) test of 35 rounds. It lost to GrubbmGrb and GrypRepetyf but not nearly as badly as it has been. I expect some decent results (as always). -- Martin<br />
<br />
Nice graphics, I should try to visualize some more than just the wave. It seems that 0.14.6 is your strongest Ugluk sofar, being relatively better against the high-end and midrange bots, well at least better than GrubbmGrb does. That bot is not exceptionally strong with about 100 losses, but will ruthlessly exploit any weak spot in movement and/or targeting. Examining the details, it almost looks like a combination of [[Grishnakh]] and [[Ugluk]] is able to get into the top-50. -- [[GrubbmGait]]<br />
<br />
At present Ugluk only has one gun, which was a few hours of re-writing my bearing offset gun nearly from scratch to be far simpler. It is still my most effective gun in terms of the targeting challenges (which is odd since I haven't even begun to toy with the segmentation) but I don't have any simpler targeters backing it up. The simple targeters tend to kill the simple bots far more quickly. It is possible that re-introducing some simple targeting methods will nudge me into the top 50, but right now there's still some nagging movement behavior that I'd like to iron out. For example, my Grid movement should never get hit by head on targeting, especially against a stationary bot. Yet sometimes it just crashes right through the middle of one. I need to figgure out just what is happening. Once I get that nailed down, I'll add some guns that reflect the LT and CT wave surfing challenge bot targeting algorithms, and I <i>will</i> produce a bot that gets 100% score in the wave surfing challenge (even if it is just a novelty bot). While coding to distract me from staring at the Roborumble client churning my results, I added a pre-turn-30 movement style that gets me out of pinned positions, and that should help my wave surfing challenge scores across the board. -- Martin<br />
Edit: And yes, Ugluk v0.14.6 is my best bot to date. Somehow I keep treading water in terms of "domination", though my rating is increasing. People are turning out strong bots lately. -- Martin<br />
<br />
Recently all of my bot design has been focused on movement. Some of the design is similar, but there has been a lot of overhaul and rewriting of the core system. A while back I made a grid walking movement that had some flaws and was terribly slow, so I shelved it. I recently got it working fairly well and then got it working really fast. And through it I've managed to track down some annoying issues. There are still some more to go though. Ultimately I expect the Grid movement style to get 100% across the board in the wave surf challenge, even though it isn't doing any learning like other wave surfers do. -- Martin<br />
<br />
Well, in playing with the collision detection I have managed to disable the registration of hits against my opponents, causing my gun to act as a head-on targeting gun, hence the dismal scores of 0.14.7's brief stint. I'll fix it tonight... -- Martin<br />
<br />
I got the gun somewhat functional, but there's some strange behavior going on. For example, I'm determining all the points at which the wave (circle) intersects the target hit box (square) which should be 0 or 2-4 times. (A wave could intersect the firing tank's hit box at as many as 8 points.) I am getting some results of 1 intersect point, which should be extremely rare. Anyway .. more work to be done. I was making general changes to the bullet / wave collision detection system and focused on testing movement so I didn't notice the gun failure. -- Martin<br />
<br />
I was getting some nice test results with my gun modification and the work day was nearly done so I packaged it. A nice 10 point boost. I have some more gun tricks to refine that should push Ugluk even further along the path to glory. I'll run some targeting challenge tests tomorrow. -- Martin<br />
<br />
Ugluk took a performance hit with 0.15.2, but his targeting challenge scores are getting a nice boost. As I get higher on the targeting challenge list it is more and more evident that my movement really needs improvement. My initial attempt at learning wave surfing was less than satisfactory and has been disabled. I need to tune it some more so that it looks like it is really surfing. As always, there is more work to be done... -- Martin<br />
<br />
It seems that 0.15.7 is the 'Release-Candidate' for v1.0, if you can improve that 49.9% score against [[Mjolnir]]! And you are threatening my position }:-\ -- [[GrubbmGait]]<br />
* I was expecting some goodness, but I expect that every release =/ I ended up defeating Mjolnir enough in the secong battle to bring the average to 52.2%. I ran Ugluk overnight and didn't see any battles until this morning. He's in 57th place, right behind GrubbmGrb at 56th. No PL ranking yet. It's going to be a good morning. And yes, I think I shall release this bot as Ugluk v1.0, over a year in the making.<br />
* Congrats! =) -- [[Voidious]]<br />
*Thanks. Upon reflection while driving into work, there is wave surfing movement style that I've been developing but just haven't gotten to work right yet. If I switch to melee now (per my stated goals of about 8 months ago) it will collect dust, since wave surfing has little business in melee (until it comes down to 1v1). That and how could I accept being right behind <nowiki>GrubbmGrb</nowiki>? Freya maybe my melee white whale, but GrubbmGrb is surely my standard for duelling excellence. Ugluk v1.0 should be a reality within a week or two though...<br />
<br />
I have been having a problem with graphical debugging. I was building lists of line segments to draw, but by the time they are drawn they are one turn late. So with a few tweaks this morning I made the onPaint method process my robot's turn (and if it wasn't called for that turn the normal run() cycle will process it, and execute the instructions). Snag #2 is that onPaint is called before any events are processed. So now I am remodelling the event handlers so that I grab them off the queue manually at the beginning of the round and process them all before making any decisions. This will have the side effect of improving the handling of [[OnDeath|onDeath]] and onWin events.<br />
<br />
With my new movement I have nearly nailed my goal in the wave surfing challenge. But .. about 4 rounds in 500 I get killed. I dunno what the situation is that causes it, and watching for something that occurs once every 125 rounds on average is not really practical. I guess I'll just have to store some notes about my starting position, the opponent's first scan position, and what my energy was at the end of the round. On the whole though I've really made some progress in getting out of tight situations at the beginning of matches, allowing for more flexibility as the round progresses. Still some work to be done though, it seems. -- Martin<br />
<br />
Ugluk v0.15.8 does not contain the wave surfing movement that I have been developing. I am trying to get the grid walking nearer to perfect. I should probably add segmentation to it, which will be a single line change. -- Martin<br />
*The RoboRumble sure is a frustrating proving ground. Down 18 points. I think I may know some of the issue though. 0.15.9 will be along shortly...<br />
<br />
Ugluk v1.0 released. Already I've found an error with the 2K6 challenge mode .. I misspelled the (rather large) Cassius Clay version numbers. I don't think anyone will be doing that testing for me so it's fairly moot. -- Martin<br />
<br />
I'm getting serious about tuning my gun now. The trouble is I have 4 styles of gun and 3 segmentations. (Really there are 4, but two are the same type of measurement). So in order to get a baseline for tuning I need to test all guns with no segmentations and each segmentation individually, for 16 total runs. I am using the Fast Learning style test, so 5250 rounds per test, ~2.7 hours. It's gonna take a few days. It is really long overdue though. I rewrote the base gun to be very simple a while ago (compared to my dynamically re-segmenting one) and took an educated guess at some practical segmentations and number of them, with no attempt to verify that they made sense. The gun has performed pretty well, but it is unlikely that it won't benefit from some tuning. -- Martin<br />
<br />
After achieving my goals for v1.0, I am now forcing myself to get back on the melee horse. I modified my Grid movement (really it isn't a grid any longer, but several rings of potential positions) to be a [[MinimumRisk|minimum risk]] system. It is good for getting out of the middle and keeping distance from other bots, but one drawback I am observing is that I will often get on a wall between two other bots and start moving back and forth along the wall. I soak up a lot of damage from that. I tried making a few tweaks to my melee radar but now I am back to the original. I've toyed with targeting a bit and guess-factor style targeting just really doesn't do well. I think there are three major factors. The lesser is that your radar has to spin more to collect updates of everyone in the battle, and it will cause you to miss wave collision data. Next is that as the battle field becomes less cluttered your opponent's movement styles change. But the biggest problem is that you've got to learn how 9 opponents move, and there's simply not enough time to learn it. I've had the most success with dead-on targeting. No learning involved. As a test bed I am using bots from the 9 top authors. I can usually place in the top 3. That hasn't translated to dominant ratings in the rumble though. I've got a few more tricks to try though, and I imagine more will come to me. -- Martin<br />
<br />
I had the same problem, oscillating along the wall and getting targeted by the two bots in the closest corners. When I introduced perpendicularity proportional to danger (distance and targeting me) in [[Griezel]], I jumped from rank 30 to rank 10. Performing good against topbots is important, but performing good against a bunch of mediocre and 'not-so-good' bots is as important, maybe even more important. Pitch in [[Gruwel]] against 9 top-20 bots and it will end dead-last. Pitch in [[Gruwel]] against 9 (very)low-ranked bots (see SampleBotMeleeChallenge) and it will slaughter them faster than nearly everyone. Meleebattles will almost always consist of one or two topbots, some mediocre ones and a few bad bots, so being good against everybody does pay off. -- [[GrubbmGait]]<br />
<br />
I know I have a tendancy to repeat what the person before me said, but well I like to outline things, your bot has to beat most of the bots below it, and all the bots below it to gain the 1st rank position, or atleast more then the current 1st placer does. So your bot might beat all the top bots all the time, but if it beats the top 10 bots and nothing else, then it only beats 10 bots out of over 200 bots. Beating the top bots means nothing in a division based ranking system. --[[Chase-san]]<br />
<br />
Well, I think it is about time to develop a qualitative measurement of bearing offset profiles. I don't want to go into detail about the targeting system I've been developing, but I've decided that I need to dynamically choose segmentations, since tests in the Rumble have shown that different segmentations can have significant impact on individual opponents. Rather than choosing the best overall combination, it would be nifty to pick them on the fly. Certainly not a new concept, but one I think I can attain, for better or worse. -- Martin<br />
<br />
Not an easy task, but if you manage it, awesome (has anyone ever managed that?) --[[Chase-san]]<br />
<br />
[[Toad]] has working DynamicSegmentation and does fairly well, though it's kinda slow. Albert says [[Virus]] has some type of DynamicSegmentation, too. Definitely a tough task to get it working well at a reasonable speed, best of luck! -- [[Voidious]]<br />
<br />
Toad kicks royal butt in PL still. Maybe this is why, its tuned for every opponent to 'win'. --[[Chase-san]]<br />
<br />
<hr><br />
<br />
With traditional segmentation, various conditions are recorded when a shot is aimed, a wave is created, and as the wave crashes over the opponent more data is recorded to note what shot(s) would have hit the opponent. When a similar condition is encountered, the targeting can make an educated guess as to where the opponent is likely to be, and fire in that direction.<br />
<br />
The main issues with this approach are what data to record, and what granularity to use. The more data used and more finely grained slicing of the data, the more precise the measurement of likeness of condition, but with that you are less likely to find a matching condition, so the slower the gun is to learn and adapt.<br />
<br />
As far as I know all bots to date treat all combinations of data as unique conditions, and have storage bins specific to that combination, though there are also techniques of bin smoothing to blur the hard edges provided by segmentation.<br />
<br />
My latest approach is to treat data categories independently from one another. I record wave hits for the categories seperately, and when my gun requests a angle to shoot at (with a collection of targeting condition data), I grab the hit count bins from each data category and then layer them together as a composite, and find the best angle (i.e. most commonly hit angle).<br />
<br />
http://home.comcast.net/~kokyunage/robocode/layers.jpg<br />
<br />
In the debug screenshot above, you can see six bins lining the bottom. Above is a composite of some of those bins. If I don't think that a data category (e.g. distance to wall) profile has much to offer, I don't include it for that shot.<br />
<br />
A traditional segmentation array would not see the similarity between, for example, a bot circling you counterclockwise near a wall vs. far from a wall, because the wall distance would make it fall into an entirely different bin. With my approach, the counterclockwise circling is read from by both conditions, and recorded to twice. This means that each data category is learning more quickly.<br />
<br />
The hope is that giving each category an equal say in the final composite will still result in a reasonable prediction of future position.<br />
<br />
- Martin<br />
<br />
Well, any single buffer (multi-dimensional array) treats each combination as a unique situation, but many bots use multiple buffers and layer them like you do here. Usually, each buffer still has multiple segments, but I do have a couple with zero or one segment in parts of [[Dookious]]. I think this is a good idea (and like what [[PEZ]] was doing in [[CrowdTargeting]]), but I think you have so much data at hand with every-tick wave collection in a gun that it seems like you could afford more than one attribute in each buffer. -- [[Voidious]]<br />
<br />
http://home.comcast.net/~kokyunage/robocode/debug03.jpg<br />
<br />
There is a frustrating issue with bullet collisions. When a bullet collides with a tank, it shifts position. When watching battles, you can see it yourself. The explosion on the tank occurs near the point of impact, but not where the bullet seems to have struck the tank's exterior, or even along the segment. The bullet's location in the related events received match up with the explosion's center (seen as yellow rings above), but they are not along the bullet path (seen as gray lines above). I was trying to match up the position, heading, and velocity of the bullet with a known enemy firing position, but it wasn't matching up. Eventually I took another route to reach the same end, but it irks me that the event was useless. -- Martin<br />
<br />
First thing I would check is that your gun is actually firing where you think it is - are the bullets following your painted lines? -- [[Skilgannon]]<br />
* It's true that robocode does this. But knowing the bullet power and ''approximate'' impact location gives you enough information to eliminate all but the correct [[Wave]] / [[EnemyWave]] --[[Simonton]]<br />
*Correct. I actually use the bullet's getHeadingRadians method and apply that to all known inbound waves' firing positions to see which wave intersects my bot's position at the time of impact (after bullet movement, before tank movement). I could use the velocity of the bullet for an extra check, but I don't really need to. At this point the only bullets I can't match up to are the ones fired when the opponent hits a wall in the same turn, throwing off the energy drop. -- Martin<br />
* Thanks for bringing this up =). I would have assumed that this would be correct. This could be what's throwing off my otherwise pixel-perfect wavesurfing. I think I'll file a bug report =) -- [[Skilgannon]]<br />
** Well, if your bot would be hit at the yellow circle but not along the line segment, do you get hit? I think not (and don't see any examples above), but I can't say for certain. If it's just the reported spot that's off, it shouldn't affect your surfing much at all - for most bots, the two spots would resolve to the same GF bin anyway. -- [[Voidious]]<br />
*** Every pixel counts =). I found that out with DrussGT. 6 pixels off in my precise prediction was more than 40 points in the Rumble. And I've got 151 bins, so at a distance of 400 that's 2.11 pixels per bin (0.8*400/151). So a few pixels off will definitely change things. -- [[Skilgannon]]<br />
**** Something seemed wrong with that calculation. It's 4.22 pixels per bin, because the MEA is in <b>each</b> direction. =) -- [[Skilgannon]]<br />
<br />
Thank you for the report at <nowiki>SourceForge</nowiki>. So, if I fix this issue with Robocode, would this break anything with existing robots? --[[Fnl]]<br />
*Well, there is this to consider: If a bullet segment clips a corner off of a tank, or if the bullet segment starts within the tank and exists (because the tank moved into the bullet during the tank movement phase of the previous round, after bullet collisions are detected), the bullet's ending location will be outside of the tank's body. If that location is used for the explosion, it will look odd. Now that I am thinking about it, I've noticed that a bullet's lifespan lasts a few ticks after the collision, and its position follows the tank's, and I conclude that the reason for this is that the bullet's position is used throughout the course of the explosion graphics. Basically in order to correct the problem you would have to mark the bullet's initial point of impact on the robot, wether that is on the exterior (bullet begins outside and enters the hitbox) or interior (bullet begins inside and passes through hitbox). Because the hitbox doesn't rotate or even match the tank's graphics, it will still appear to be an interior hit. Its probably not really worth it to change this, but it should be documented on the Wiki and in the API that a bullet's position after colliding with a tank will not be exact. -- Martin <br />
* I would think it'd be fairly easy to use a different coordinate for the graphic than the one that gets reported via the RobotHitEvent, wouldn't it? But I do not know if changing what's reported via the event would affect some existing bot. -- [[Simonton]]<br />
* No, unfortunately it is not that easy as the Bullet class gets it's data dynamically from an internal BulletPeer class. But the problem is that the bullet is not a snapshot when it collides, i.e. a deep copy. I have changed this with a special test version of [http://robocode.sourceforge.net/files/temp/robocode-setup-1.4.5-01.jar Robocode 1.4.5 here]. Please try out this version to see if this fixes the problem at report back. :-) --[[Fnl]] <br />
*I'll look at it in the morning. I'm trying to get Tomcat, MySQL, and an old Java web app installed and running. I enjoy programming, but I sure hate setting up the environment. -- Martin<br />
* Is it possible to work around this (for accurately detecting enemy bullets) by projecting from the fireposition with the bullet's heading? The heading of the bullet isn't changed on impact, is it? -- [[Skilgannon]]<br />
* If you now the coordinate, heading, and velocity of the bullet, then I should be quite easy to figure out. When the bullet hits the tank, the only things that are changed for the explosion part is the x og y coordinates and the state of the bullet = "bullet_hit_robot", which means that the bullet is no longer active on the battle field. ;-) --[[Fnl]]<br />
* Ok, thanks. It should be as simple as Point2D.Double realLocation = project(wave.fireLocation,bulletHeading,wave.distanceTraveled); -- [[Skilgannon]]<br />
* Yes, exactly. ;-) --[[Fnl]]<br />
* [[Skilgannon]]: I take my words back! I found out that a deep copy would not do, as the Bullet would become a new object, which you cannot compare to your own bullets you fired, e.g. when you hit another robot for example. Thus, I have changed it, so the rendering x og y coordinates for the explosion part is independt from where the bullet did hit a robot or other bullet. I have now made a new version, which I have tested, and it seems to work now. But I should still like you to try it out. A new test/debug version can be found [http://robocode.sourceforge.net/files/temp/robocode-setup-1.4.5-02.jar Robocode 1.4.5 (02) here]. I tested it by putting all bullets received in bullet event as onHitByBullet() in a list, and then I paint all the bullets in this list using onPaint().<br />
<br />
Ugluk is presently undergoing a code transplant. I started a new project, rewrote the physics engine building blocks, and am slowly refurbishing the old Ugluk guts as they are moved to the new body. It is a fairly intimate refresher course in the bot. I'm also culling obsolete functionality (dependencies of features long abandoned) and changing some of the flow. I'm sure Ugluk will need some physical therapy following the procedure, but he should be a lot healthier at the end. -- Martin<br />
<br />
Cool! Welcome back. -- [[Voidious]]<br />
<br />
I've decided to deliberately introduce some imprecision to my targeting waves. I now treat an opponent as a sphere with radius ~25.5, rather than a 36x36 square. If at some point my bot is so awesome that switching back to a square is the only practical means of topping himself, hopefully I can retire and leave it at that. -- Martin</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Pedersen&diff=16924User talk:Pedersen2010-07-01T08:42:47Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Welcome :) this text could bee mine apart from grammatical mistakes i would have made.<br />
The only thing i read was the CircularTargeting Turtorial!! And i have no mini micro or macro Bot :D --[[Krabb]]<br />
<br />
I got a call from a former customer interested in reviving a project I had worked on, so I'll be busy reviewing where I left off and what I can do with the project for him. I'm also actually being tasked with real work lately at my day job. Consequently it will likely be a while before I find any time to make any tangible improvements to [[Ugluk]]. I'll still be checking in on the Wiki though several times a day, and I'm available on IM for random gabbing. -- Martin<br />
<br />
I have started using RobocodeSG and your testbots. This really is much easier than using RobocodeGL!! Would you mind publishing the code for painting the bullets and waves? --[[Loki]]<br />
<br />
Sure thing. I posted it under [[Ugluk/RobocodeSG]]. I'm sure you'll need to modify it to meet your implementation. I've got a lot of my physics stuff in it. -- Martin<br />
<br />
Thanks to my work on Roland v0.2 I found a glitch in my wave timing and the energy management of the test bots. I'll update them shortly. -- Martin<br />
<br />
The three test bots have been updated with more precise inbound wave tracking, including the addition of a box around the firing position. They will also no longer fire without the turret being aimed. -- Martin<br />
<br />
If I pick up the reins of [[Ugluk]] again, one of the first things I'll do is create an interface that hides all of the blocking calls (e.g. fire() ) so that they aren't used by mistake, and cast my [[AdvancedRobot]] using that interface. That should reduce the errors introduced by calling the simpler [[Robot]] methods. I was looking at the [[Radar]] thread and it reminded me of an issue where I was missing scans and getting my bullet projections out of sync because I was calling the wrong method while trying to place a bullet in the queue. -- Martin<br />
<br />
Grr. I'm having trouble finding out the maximum storage capacity allowed by the RobocodeFileWriter mechanism. -- Martin<br />
<br />
Ok. I've spent hours and hours, and some hours on top tracking this down. When a bullet makes contact with an opponent, it doesn't go straight in. For whatever reason, the final position is neither the normal angle nor normal distance from the previous position. What this means is that the bearing from a bullet's point of origin to its final position is not an exact match to its heading. And I'm not talking an issue with precision of doubles. The significance of this is that I was trying to match my onHitByBullet events with the wave that fired the bullet, and I couldn't do it based on the bullet's heading. There are other ways to determine it, with less confidence, but it sure was frustrating and shook my faith in the foundations of my wave infrastructure (which I have since found was flawless all along). Here is an example of some debugging output:<br />
<pre>[30] Firing shot from position: ( 185.0126, 245.5766 ) bearing: 0.3912<br />
A: ( 232.6758, 361.1327 )<br />
B: ( 237.2175, 371.7775 )<br />
Vector: 0.40327927217322446, 11.57313768145533<br />
Bullet: 0.39120829168722615, 12.5<br />
Bullet heading is not consistent.</pre><br />
<br />
-- Martin<br />
<br />
I don't have the source anymore - so this is a wild stab in the dark - but perhaps Robocode sets the (x, y) of the bullet to that of the enemy it hits upon collision? -- [[Simonton]]<br />
<br />
I've checked that, and it isn't it. It appears the bullet becomes stuck to the tank and moved with it once before you even get the event. I've translated the bullet back to the alleged point of impact (based on the opponent's change in position) and it's pretty close, but not dead on. I've decided to move on for now. I am able to associate the bullet with the originating wave with a good deal of confidence. It just irks me that there's no explanation for it yet. -- Martin<br />
<br />
Have you considered using setFireBullet() & storing a referance to the bullet object in the wave it represents? Then search your waves for the given bullet when one hits - 100% confidence. Or better yet, use a HashMap of bullet objects to waves. -- [[Simonton]]<br />
<br />
Phoenix uses a HashMap to look up bullets for its VirtualBullets system. Just do HashMap.put(bullet, gun) when you fire and you can get the gun back in onBulletHit and onBulletMissed to update the gun's scores. Highly recommended! =) --[[David Alves]]<br />
<br />
<i>"The significance of this is that I was trying to match my onHitByBullet events with the wave that fired the bullet"</i><br><br />
I am trying to determine the firing position of the bullet. I have all firing positions because I am already tracking waves created by my opponent. The problem lies in being absolutely sure that a bullet belongs to a wave. In order to be satisfied, I wanted to be able to take the bullet's point of impact and project it back along its heading (in reverse) to see if it runs through the center of any waves I have. (I am simplifying my logic for explanation.) It never matches. I've tried comparing the bearing from the wave to the tank's start and end positions, the bullet's position and the bullet's position translated back to where it hit the tank (since apparently they stick to the tank). None of them worked well enough. The closest (translated back) was still off by about 0.04 to 0.1 radians. That bugs me. I've taken a looser approach so I can move on, but there's something screwy going on. -- Martin<br />
<br />
That is strange, but you can just use a HashMap to associate bullets with waves. =P --[[David Alves]]<br />
<br />
Yes, but I think you are looking at bullets from the setFireBullet method. That is only available to the person firing the bullet, not the person being hit by it. -- Martin<br />
<br />
Oh, you're talking about enemy bullets? I match those to waves by bullet power and by how close the wave is to the position of impact. E.g. If I get hit by a bullet, I check what waves are closest to me and see if any of them have the same power as the one that hit. If so, I have a match. --[[David Alves]]<br />
<br />
That's what I ended up doing. It isn't as clean as matching on bullet heading and velocity (i.e. power), as I wanted to do. -- Martin<br />
<br />
Martin, please, do slightly easier with "some redundant versions". You have been deleted some not redundant versions. -- [[DemetriX]]<br />
*Can you give an example? If you want something put back in, you are welcome to put it back on the list. -- Martin<br />
* Was about to ask the same, all of Martin's removals seem valid to me... -- [[Voidious]]<br />
<br />
Today I wrote a Java utility to remove old versions of robot jars from the robots directory. For some reason I can't get it to run from the command line, but when I finally ran it from within Eclipse it was done in under 2 seconds and had moved 187 files to an archive folder. Most of these were various updates from myself, voidious, wcsv, chalk, davidalves, pez, demetrix, and others who have updated regularly over the past few months. It also caught some versions that are redundant in the rumble or across rumbles (e.g. different versions for melee vs. duels). I'll work on a new version that will pull a listing from a URL (i.e. participants list) and move everything not on that list to the archive, as well as moving the extracted jar files from the .robotcache directory. This would allow some easy hot swapping between the roborumble and meleerumble with the least overhead in terms of loading jar files. I don't know how soon I'll get around to finishing it and releasing it as a general use tool. -- Martin<br />
<br />
Nice tool, I still cleanup the robots directory by hand. Maybe I put together some Perl-script to automate it. The .robocache directory is automatically cleaned up everytime Robocode (or RR@Home) is (re)started. -- [[GrubbmGait]]<br />
* The client will clear out old cache entries, but it has to extract them over again if you are only moving the jar files around and not the extracted classes. I want to move both to minimize the extraction process. -- Martin<br />
** Therefor I have separate 'installations' for oneonone, melee, team and own development, but the tool would still be handy for me to cleanup the old and obsolete entries. -- [[GrubbmGait]]<br />
<br />
Yeah, very cool, I'd definitely make use it if / when you release it. I basically don't clean up my robots directories save every once in a great while, and they really do pile up... -- [[Voidious]]<br />
<br />
Ok, I wrote the tool. It basically moved everything in /robots (except the roborumble folder) and /.robotcache into an archive, grabs the participant list you feed it (roborumble or meleerumble .. team rumble won't work I think), and then moved all of the participants that you have back into the /robots and /.robotcache folders. I am sure it will have some quirks, such as if the file system prevents a file move for any reason. It's not written to be really robust. The file is here: <a href="http://home.comcast.net/~kokyunage/robocode/RumbleCacheTool.class">Rumble Cache Tool</a>. If you execute the class it gives you the following usage instructions:<br><br />
Welcome to the Rumble Cache Tool by Martin Alan Pedersen.<br><br />
This utility requires two parameters: the path to your rumble installation, and the URL to the participants listing.<br><br />
Usage example: java RumbleCacheTool c:\roborumble http://robowiki.net/cgi-bin/robowiki?RoboRumble/Participants<br><br />
-- Martin<br />
<br />
For example, serenity.serenityFire 1.27, that today was reverted to the rumble -- [[DemetriX]]<br />
*"serenity.serenityFire 1.28 test" is a newer version of "serenity.serenityFire 1.27", and they were both entered at the same time. I am not trying to offend anyone. I cleaned up about 12 listings that were clearly old versions of the same basic bot. There are a few others to be cleared up, but their owners are not around, I think. -- Martin<br />
<br />
You've just passed me in the RoboRumble contributors list. Now it's on :D [[User:Christopher.Hilla|Christopher.Hilla]] 21:19, 6 February 2010 (UTC)<br />
:: Heh. I noticed that too. I've got one CPU at work running over the weekend and on my wife's machine I've got each of her 4 CPU's running against its own copy of the RR. But she gets home in about 30 minutes so I may shut those 4 down soon. --[[User:Pedersen|Martin]] 22:30, 6 February 2010 (UTC)<br />
<br />
----<br />
<br />
<code><syntaxhighlight> Graphics2D console = (Graphics2D)this.getGraphics();<br />
console.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);<br />
console.scale( 1.0, -1.0 ); // flip the y axis<br />
console.translate( 0, -getHeight() );<br />
console.clearRect(0,0,201,getHeight());<br />
...<br />
sa2.paint( new Point2D.Double( 0, 0 ) );<br />
GraphicalDebugger.onPaint( console );</syntaxhighlight></code><br />
<br />
*I managed to get a Swing application going that will render the graphics I normally render within Robocode. I started with another Swing application I'd written for something else, commandeered an event handler, and added the above code. In my GraphicalDebugger class I store a Queue of Shape (and Color) objects to be painted, finally rendering them when I am given the Graphics2D object. In this case, I'm telling my VisitCountStats-type instance to render the test data relative to (0,0) each event (button click), after clearing space for it (it is 201 buffers wide) with the clearRect() method. The Scale and Translate operations are to account for the Robocode coordinates starting lower left and Swing starting at upper left. Users of RobocodeSG will remember flipping this themselves within their bots, and the checkbox in the bot console.--[[User:Pedersen|Martin]] 21:26, 10 February 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Nat/DrawingBot&diff=16923User talk:Nat/DrawingBot2010-07-01T08:42:38Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>== Complex Graphics Rendering ==<br />
<br />
Because my wave painter was very complicated (~200 java code), I always doing paint in <code>onPaint()</code>. If I need to paint data that aren't available globally, I'll make global variable(s) to store it. This isn't efficient I know, but it does save some skipped turns when I'm not painting (and I call nearly 10,000 trig operations for each wave in air, bot me and enemy if any)<br />
<br />
Later when I make single Wave class that I use in many developing robots, I extract all painting code to class call <code>WavePainter</code>. I still do all painting in <code>onPaint()</code>.<br />
<br />
Recently when I was about to release [[Samekh]], I switch the graphics system to the one similar to this (refer to [[User:Nat/DrawingBot]]) and [[User:Nfwu/Painter|Nfwu's]] mixed. I used to set <code>isPainting = false</code> and clear the renderables buffer in onScannedRobot() and set <code>isPainting = true</code> in <code>onPaint()</code>. This way I know if I need to calculate the graphics or not. That's when I realised something. I read somewhere:<br />
<br />
''&ldquo;Complex graphics can to done by extend the Renderable abstract class.&rdquo;''<br />
<br />
I then changed my <code>WavePainter</code> class to extends <code>Renderable</code>, create constructor, and I need not to check whanever I'm painting or not. If it isn't painting, then the <code>render(Graphics2D)</code> in my <code>WavePainter</code> won't be call. And if I put all calculation there I won't skipped turns due the calculation on the debug graphics.<br />
<br />
When I look at some other robot's source that I know also do complex calculation in graphical debugging (although not as complex as mine), such as [[DrussGT]] and [[Diamond]]. For DrussGT he does painting in <code>onPaint</code> directly. For Diamond, he does what I used to do. Not the same, but similar. He check the paint time to decide is the painting is on or not, which make code complicated.<br />
<br />
Pros of this method is the code is a lot cleaner. Some example of my waves:<br />
<syntaxhighlight><br />
public void onPaint(Grapgics2D g) {<br />
for (Wave wave : waves) {<br />
// 200+ lines of wave painting<br />
}<br />
}<br />
</syntaxhighlight><br />
vs.<br />
<syntaxhighlight><br />
public void updateWave() {<br />
// notice this is in updateWave, not in onPaint<br />
for (Wave wave : waves) {<br />
wave.update(enemyLocation);<br />
graphics.draw(new WaveRenderer(wave));<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
or in case of an arrow, which I first saw in Diamond, that I also use in my robots.<br />
<br />
Diamond's code:<br />
<syntaxhighlight><br />
if (paintStatus()) {<br />
DiaWave w = firingWaves.get(x);<br />
Point2D.Double angleHead = DiaUtils.project(myNextLocation, <br />
xFiringAngle, Math.min(400, <br />
w.targetDistance - 55));<br />
<br />
_renderables.add(RoboGraphic.drawLine(myNextLocation,<br />
angleHead, Color.red));<br />
_renderables.addAll(Arrays.asList(RoboGraphic.drawArrowHead(<br />
angleHead, 10, xFiringAngle, Color.red)));<br />
}<br />
</syntaxhighlight><br />
versus my code:<br />
<syntaxhighlight><br />
for (Point2D pt : fireLocations)<br />
graphics.draw(new Arrow(myPosition, pt, Color.red));<br />
</syntaxhighlight><br />
<br />
Of course, they aren't comparable since it is under definitely different structure, but as you see my arrow drawing code is in separate class that only calculate when it is painting without need of the <code>paintStatus()</code> thing. Before some of you argue that Diamond's has system that allow disable/enable of graphics layer, my approach can implement the same thing too (in fact, all of this are implemented in [[Samekh]], take a look at package <code>nat.gfx</code> if you like).<br />
<br />
Comments? --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 10:27, 11 October 2009 (UTC) <small>Diamond's code above is under [[RWPCL]]. My code above I hereby make them public domain, although nothing much in it. I think we should define explicit license for all code in this site, even some code that won't worth copy at all.</small></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Nat&diff=16922User talk:Nat2010-07-01T08:42:35Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{{Navbox small<br />
| title = Archived Talk<br />
| namespace = User<br />
| parent = Nat<br />
| page1 = Talk Archive 20090406<br />
| title1 = 2009/04/06<br />
| page2 = Talk Archive 20090620<br />
| title2 = 2009/06/20<br />
}}<br />
<br />
Let see if I get confirmation email. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:34, 23 July 2009 (UTC)<br />
<br />
: I think it ignores your own edits. So here you go. =) --[[User:Voidious|Voidious]] 14:37, 23 July 2009 (UTC)<br />
<br />
:: Thank you, it does ignore owner edits. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:40, 23 July 2009 (UTC)<br />
<br />
== Birthday 2009 ==<br />
<br />
Attention guys, today is a very special day! At least to me, because today (July 3) is my birthday! Mind giving me a little "Happy Birthday"? LOL &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:15, 3 July 2009 (UTC)<br />
<br />
Happy Birthday!--[[User:CrazyBassoonist|CrazyBassoonist]] 12:44, 3 July 2009 (UTC)<br />
<br />
Lol, happy birthday man! Hope it's a good one ;) --[[User:Spinnercat|Spinnercat]] 15:28, 3 July 2009 (UTC)<br />
<br />
Happy birthday =) --[[User:Skilgannon|Skilgannon]] 15:40, 3 July 2009 (UTC)<br />
<br />
Happy Birthday, Nat. Don't party too hard. =) --[[User:Voidious|Voidious]] 17:26, 3 July 2009 (UTC)<br />
<br />
Happy Birthday Nat, hope you have fun ;-) --[[User:Zyx|zyx]] 18:25, 3 July 2009 (UTC)<br />
<br />
<small><small style="line-height:1.1;white-space:pre;font-family:monospace;"><br />
{}<br />
||<br />
____||_____<br />
{} {~ ~ ~ ~ ~ ~} {}<br />
|| { ~ ~ ~ ~ ~ } ||<br />
__||__{___________}__||__<br />
{\/\/\/\/\/\/\/\/\/\/\/\/\}<br />
{} { H a p p y \} {}<br />
|| {\/\/\/\/\/\/\/\/\/\/\/\/\} ||<br />
__||_{_________________________}_||__<br />
{\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}<br />
{ }<br />
{ B i r t h d a y ! ! ! }<br />
{ }<br />
{/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/}<br />
{_____________________________________}<br />
</small></small>-- [[User:Synapse|<font style="font-size:0.8em;font-variant:small-caps;">Synapse</font>]] 21:17, 3 July 2009 (UTC)<br />
<br />
Haha, happy birthday Nat. Hope it's a good one! --[[User:Rednaxela|Rednaxela]] 23:50, 3 July 2009 (UTC)<br />
<br />
Thanks guy. Actually I don't have a party, nor cake (except the one above), nor presents =) I've got my present 3 months ago (new notebook that I'm currently sitting in front of) and I hate party! It take the time that I usually sit in front of my computer away. However, this isn't a good one. I've got a cold! Or at least I hope it only cold, not swine flu ;-) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 01:38, 4 July 2009 (UTC)<br />
<br />
== MicroBot Wave Surfing ==<br />
Anyone have 10TB of memory and hard disk to spare? I need that to perform my own microbot wave surfing. The large part of Wave Surfing is precise prediction, which nonetheless can't fit in micro. I wonder if I cached ''all'' the prediction and just access it at runtime. Now I roughly calculated. Let see, I restricted the location, absBearing, velocity and distance to all integer. Total possible location on the map is 764*564 = 430896 locations, multiply by 360 absBearing, ~950 distance, 17 velocity. Saves in short (2 bytes), contain x and y will result in around 764*564*360*950*17*2*2 = 10020917376000 B = 9786052125 KiB = ~9,556,692 MiB = ~9,333 GiB = ~9.114 TiB.<br />
<br />
Anyone have ideas how can I reduced those number? If I use 80*60 possible locations, 36 possible absBearing, 17 velocity and 19 possible distance, it still cost 43MB Note that this need to be preloaded into the robot, not calculating on-the-fly. <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 05:17, 20 June 2009 (UTC)<br />
<br />
I've done a fair amount of work with precalculated movement table things. I once got a precalculated movement table down to about 2MB, but that's still too big for ethical pre-loading, AND the optimizations it used took rather large codesize to turn into something usable in battle. I don't think you're going to be able make this realistically work Nat honestly. --[[User:Rednaxela|Rednaxela]] 05:27, 20 June 2009 (UTC)<br />
<br />
=( Well, thanks for the info. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 05:50, 20 June 2009 (UTC)<br />
<br />
I'll let you borrow my tables when I get around to adding micros to my list ;) --[[User:Miked0801|Miked0801]] 09:02, 20 June 2009 (UTC)<br />
<br />
: I'm not talking about the VCS table, I'm talking about movement table i.e. the table that allow you to know what is your position next tick if you are at (''x'',''y'') with a velocity of ''v'' and the enemy is at ''θ'' with a distance of ''d'' or something. It is the replacement of Precise Prediction used in minibot and megabot. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 09:25, 20 June 2009 (UTC)<br />
<br />
I haven't dealed with wavesurfing yet, but do you need precise prediction? Is there anything less complex that could replace it? Anyway, take a look at kb.WaveShark, it's supposed to be a wavesurfer. --[[User:Robar|HUNRobar]] 14:38, 20 June 2009 (UTC)<br />
<br />
LOL, it is kc.WaveShark. Actually it is that robot which inspire me about this. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:40, 20 June 2009 (UTC)<br />
<br />
Pugilist is an example of a wave surfing without precise prediction I think, that might be able to give some inspiration --[[User:Rednaxela|Rednaxela]] 15:53, 20 June 2009 (UTC)<br />
<br />
: Thanks. I have looked at it now, the prediction thing is still too large I think. But I'll give it a try... &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 16:09, 20 June 2009 (UTC)<br />
<br />
== Bi-hourly release ==<br />
<br />
Wonder is this is right thing to do or not. Because the number of clients running among this day, I can release my robot bi-hourly. But since I'm not running those clients, I not sure if this is right thing to do or not. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:42, 21 June 2009 (UTC)<br />
<br />
: if there are no other bots waiting, not a problem. But, my bot has been waiting for a bit to get to 2k battles in nanos. If you need this much info and are feeling guilty, use roboresearch for your tests. You'll get your answers just as quick without the guilt. --[[User:Miked0801|Miked0801]] 15:26, 21 June 2009 (UTC)<br />
<br />
:: Sorry. When I checked and see the "PAIRINGS COMPLETE" text, I decided that the ranking is completed. Actually I'm not needing it fast, just roughly seen where it place is enough for me to decided what to do with next version, and I usually take only 10 minutes to do it. I'll try to run it on RoboResarch next time. Thanks. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:39, 21 June 2009 (UTC)<br />
<br />
: I think the rule of thumb used to be maximum one release per day? There are quite a few bots in the nano & micro categories still below 2000 battles. If you're feeling guilty, run a client and help out... --[[User:Darkcanuck|Darkcanuck]] 17:28, 21 June 2009 (UTC)<br />
<br />
== Number of Edits ==<br />
<br />
Hmm... I wonder if the number of edits at [[Special:Preferences]] correct? Mine is currently 1,653 (at the time of writing, so perhaps this shall count as another one), but the [[Special:Statistics]] said that total edits is currently 9,954. I don't think I make an edit that much. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:36, 29 July 2009 (UTC)<br />
<br />
== <nowiki>{{Wikipedia}}</nowiki> template use ==<br />
<br />
Hey Nat, I really recommend you don't use the <nowiki>{{Wikipedia}}</nowiki> template on the [[Twin Duel]] and [[RoboRumble]] pages like that. The reason being, the text "Wikipedia has an article about: Twin Duel" is very much NOT true, as it's only a minor section. I don't think it's sensible to use this template for one-section-only links. See [[Talk:Anti-Gravity_Movement#Wikipedia_link]] --[[User:Rednaxela|Rednaxela]] 15:24, 12 August 2009 (UTC)<br />
<br />
I see. Thanks, perhaps new template with "Wikipedia has a section about: Twin Duel ... in page Robocode" is better =) I'll remove them. Thanks again. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:31, 12 August 2009 (UTC)<br />
<br />
== SDS + Zoom = ? ==<br />
<br />
For any who doesn't know what is SDS and [[Zoom Targeting]], I'll explain briefly. SDS (Symbolic Dynamic Segmentation) is a data management system that you will map the data to a string that represent a state of the data. When you need data, just match the current state with the state of each data. If they are no match or too few matches, just strip last character out and do the match again. Do this until you have enough matches you want.<br />
<br />
Zoom Targeting looks similar but indeed it isn't. It have fixed number of 'zoom' level, each level with different preciseness of the states. The deeper the zoom level, the more precise the state is. When you zoom in, it will act more like wave-based pattern matching. When you zoom out it will act more like statistical gun.<br />
<br />
Now I'm thinking of combine them together. Like SDS-based data storing and using Zoom Targeting algorithm to choose number of segmentation to use? Any ideas?<br />
<br />
Also, please help me think of a name. I'm considering of 'Statistical Zoom Data Management Algorithm' but it won't fit at all. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:32, 3 September 2009 (UTC)<br />
<br />
== OOP vs. Pluggable? ==<br />
<br />
Hmm... I want to know, do you guys prefer more OOP or more Pluggable? I mean, I'm development a very pluggable robot (I mean, they have very little shared class) and still OOP-ed (mean that it have clean structure). (While I must accept that current top robot, DrussGT is the most pluggable =)) I realised that my repeat my code a lot. Currently the core of my GF gun contains 6 files: EnemyMovementProfile (interface), GuessFactorGun, GunScanLog, GunScan, GunWave and GunStats (interface). My movement engine has almost exact file with almost exactly the same content (EnemyMovementProfile vs SelfMovementProfile; GuessFactorGun vs WaveSurfingmovement; Gun... vs Movement...). And I can merge a lot of it into single file (or using abstract class) easily. In this case, do you guys choose to use the very pluggable structure with less OOP or more OOP with less pluggability? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 10:54, 5 September 2009 (UTC)<br />
<br />
I think mixing movement and targeting classes is providing an opportunity for bugs to creep in, because there are many small differences. So for good programming practices try to keep them separate, but that doesn't mean that they shouldn't have many small subclasses. And DrussGT isn't that pluggable, for an example of pluggable look at [[Dookious]] or [[CassiusClay]], my next release will be working on that though =) --[[User:Skilgannon|Skilgannon]] 11:28, 5 September 2009 (UTC)<br />
<br />
: One thing I hate about Dookious is loads of utility class in the *.util package. With DrussGT, movement need DrussGT and BufferManager, while gun need DrussGunDC, PreciseUtil and PreciseWave. Dookious, err, have too many files too lazy to copy over =) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:34, 5 September 2009 (UTC)<br />
<br />
I don't really understand - why do you think OOP and pluggable are opposites? A good OOP design will also be pluggable. Dookious certainly tries to be both (and succeeds, I think). Coding style is a personal preference, but since you're asking =) ... My advice would be to use OOP design principles as best you can. OOP is an important thing for any aspiring programmer to understand, and Robocode is a great place to practice those concepts. Also, having code copied in multiple places is a Very Bad Thing, if you ask me (or just about any programmer)! And why not have movement and targeting share code when it makes sense? Of course, pay attention to subtle differences in targeting/movement, but a lot of stuff can be safely shared. --[[User:Voidious|Voidious]] 16:25, 5 September 2009 (UTC)<br />
<br />
I think I have difference definition of Pluggable =) Basically, I mean that Dookious isn't pluggable because I need to copy a whole util package too, which contains a lot of unnecessary classes. DrussGT is pluggable in my mind because I can copy it over without any unnecessary classes. OK, pluggable redefined... Thanks for your opinion. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 02:26, 6 September 2009 (UTC)<br />
<br />
What I believe you mean, is the scale from Monolithic, to Monolithic Modules, to Granular Modules, to Very Granular Modules. DrussGT would be in the general region of "Monolithic Modules", whereas Dookious would be closer to "Granular Modules", some others like most of my large ones might go into "Very Granular Modules", and things like nanobots are almost always in "Monolithic" of course. Anyway, I believe which is best depends on the complexity of the bot (no point in very granular modules when things are simple enough anyway), and personal preferences. It's quite easy for either too monolithic or too granular to make code hard to maintain/read, but ultimately what's right depends on the bot and the authod in question. --[[User:Rednaxela|Rednaxela]] 04:33, 6 September 2009 (UTC)<br />
<br />
Yes, thanks. It took me long enough to look into a dictionary (I have been googling for those terms for quite a time and found nothing) =) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:31, 6 September 2009 (UTC)<br />
<br />
== Trig Help! ==<br />
<br />
Anyone please help me with this: given the angle ''a1'' and ''a2'' and the distance ''d'', how can I calculate the distance ''r'' if the shape is a segment of a circle?<br />
<br />
http://nat.robothai.net/robocode/trig-help.png<br />
<br />
&raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 06:11, 20 September 2009 (UTC)<br />
<br />
: Is this the only info you have nat, or do you also know exactly where the origins of a1 and a2 lie on the circle? --[[User:Positive|Positive]] 09:23, 20 September 2009 (UTC)<br />
: Yes, this is all information I have. I'm not sure it can be calculated. In my melee gun development, I use very rough (but better than linear) approx. for interpolation, but if I can calculate this, it will be much more accurate. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 09:34, 20 September 2009 (UTC)<br />
:: [[File:NatMathTry.gif]]<br />
:: I think the answer is that the length, r, is Math.asin((d/a)/2)*2. Where d is the mentioned distance and a is the radius of the circle. You use the Math.asin function the calculate the angle z in radians. Multiplying the angle z by two gives the total length of r. Correct me if I'm wrong. :)<br />
::: Hmm... I think you are correct, only that I don't know the radius of the circle... Note that a1 and a2 is the angle from line d to the dotted line, not r, so... I'm not sure, but I think a1 is equal to a2? But it still doesn't help. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 10:22, 20 September 2009 (UTC)<br />
<br />
It might just be my internet connection, but I can't get your image to load. If you upload it to the wiki I might be able to help. --[[User:Skilgannon|Skilgannon]] 20:44, 20 September 2009 (UTC)<br />
<br />
: South Africa? I know some countries can't access this host (Netherlands, for one). Basically, the green lines/text, gray dotted line, and the curve r from Red's pic are mine. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 11:22, 21 September 2009 (UTC)<br />
<br />
I belive I've solved it Nat. Here's a picture with the solution, and some rough work overlayed on the original image :)<br />
<br />
[[File:Reds solution.png]]<br />
<br />
--[[User:Rednaxela|Rednaxela]] 22:17, 20 September 2009 (UTC)<br />
<br />
Thank you very much! But can you explain what is c please? I don't understand it. Thank you again. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 11:22, 21 September 2009 (UTC)<br />
<br />
c is circumference. He was just deriving the formula for arclength, which is radius*theta where theta is in radians. Also, b1 and b2 form an isosceles triangle with the radius, so b1 = b2 thus a1 = a2, so the formula can be simplified a bit =) --[[User:Skilgannon|Skilgannon]] 11:31, 21 September 2009 (UTC)<br />
<br />
Oh, thank you. *slap myself hard* How could I forget the formula for circumference? Hmm... I think I said somewhere about that a1 == a2 so the final answer will be <math>r = {{2a \times d}\over{\sqrt{2 - 2 \times cos(2a)}}}</math> where <math>a</math> is the angle. Will try this with the movement interpolater tonight =) &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 11:43, 21 September 2009 (UTC)<br />
<br />
== Movement Interpolater ==<br />
<br />
Well, I just uploaded my [[File:Nat.Interpolater 1.0.jar|more precise movement interpolater code]]. But there are still a few problems which I can't figure out what and how to fix it. First is when enemy change its direction, it mostly predict in something messy. Second is sometimes it don't get into fullAccl/Decel (look at the source code) mode. Thank you in advance. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 16:02, 22 September 2009 (UTC)<br />
<br />
Non-related to Robocode, but it would be fun if we can get [http://www.popsci.com/scitech/article/2009-09/augmented-google-earth-gets-real-time-people-cars-clouds&rurl=translate.google.com&usg=ALkJrhigmRT6z1mLdS3uM9tjPIJEOKYEwg this new technology] (especially the interpolation for an unobserved location) for Robot's movement interpolation. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 11:56, 1 October 2009 (UTC)<br />
<br />
== Twin Duel battle selection ==<br />
<br />
Hey Nat - I noticed you're running a lot of Twin Duel battles. I noticed that when everyone has enough battles, only four bots were getting battles from my clients, and it looks to be the same for you right now if you check the rankings. If you want to contribute battles evenly, I think you'll need to raise the BATTLESPERBOT to something higher. --[[User:Voidious|Voidious]] 14:56, 23 September 2009 (UTC)<br />
<br />
Yeah I noticed that too. It seems that I'm not able to finish my twin duel team shortly so I stop running it, for now. &raquo; [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] &raquo; 15:10, 23 September 2009 (UTC)<br />
<br />
== Fast Play-it forward algorithm ==<br />
<br />
Anyone know how to do fast Play-It Forward (like in Shadow?) I tried many ways, but still doesn't do as good as step-by-step method, which is so slow (my 13-dimension KdTree is slow enough) I tried to understand what ABC say at [[oldwiki:DCBot]] too, but fail. Any ideas? ABC? [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 23:49, 27 September 2009 (UTC)<br />
<br />
I'm not sure how Shadow does it, but the way I way I do it is along the lines of the following: 1) Estimate the bullet-travel-time based on current distance and bullet speed, 2) skip that much time forward in the log, 3) check if the wave has passed, isn't there yet, or is just right, and if it's not just right make a revised bullet-travel-time estimate and go back to step #2, otherwise continue, 4) Only now, check if the final point is within the battlefield. To my understanding, this is along the same lines of how Shadow does it, but I'm not certain. It's requires iterations, but is far far faster than traditional play-it-forward. Also, while it isn't as strict when checking paths don't go out of bounds, it that tiny loss in accuracy is well worth it for the speed it gives for things like melee. --[[User:Rednaxela|Rednaxela]] 00:42, 28 September 2009 (UTC)<br />
<br />
I think this is how ''old'' Shadow does, I think new one do something like convert the current vel/heading to the relative point. When aiming, just add series of relative points and rotate the result location or something, but I never successful implementing this. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 00:45, 28 September 2009 (UTC)<br />
<br />
I fail to see how what you describe could be any faster. What I do is just calculate relative point between the two points in the log, and rotate that, and add to current location. Storing it as a series of relative points in the log would make it slower so far as I can tell, since it doesn't remove any steps yet adds an extra step of doing the summation. --[[User:Rednaxela|Rednaxela]] 00:52, 28 September 2009 (UTC)<br />
<br />
No, it is like:<br />
<syntaxhighlight><br />
double bulletD = 0;<br />
int round = scan.round;<br />
double x = 0, y = 0;<br />
while (M.sqr(bulletD) < Point2D.distanceSq(x, y, last.distance, 0)) {<br />
bulletD += bulletV;<br />
x += scan.relativePoint.getX();<br />
y += scan.relativePoint.getY();<br />
scan = scan.next;<br />
if (scan == null || scan.round != round)<br />
return null;<br />
}<br />
Point2D newEnemyLocation = new Point2D.Double(x, y);<br />
newEnemyLocation = rotate(newEnemyLocation, last.heading);<br />
newEnemyLocation = new Point2D.Double(newEnemyLocation.getX()<br />
+ r._enemyLocation.getX(), newEnemyLocation.getY()<br />
+ r._enemyLocation.getY());<br />
if (!_fieldRect.contains(newEnemyLocation)) {<br />
return null;<br />
}<br />
</syntaxhighlight><br />
This is my not-really-working code, but I hope it can describe what I'm telling. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 00:55, 28 September 2009 (UTC)<br />
<br />
I don't see how that could work. The geometry of <code>distanceSq(x, y, last.distance, 0)</code> seems completely broken. That does give me an idea of what would work though: Instead of rotating the relative point every time, just rotate your firing point into the perspective of the old log. That would allow checking the distance between the future enemy location and the firing point very efficently. --[[User:Rednaxela|Rednaxela]] 01:06, 28 September 2009 (UTC)<br />
<br />
Well, because (x,y) start at zero, and the relative point is rotate((xDelta,yDelta),enemyHeading). Thus, my current position will be at (enemyDistance, 0) Note that last is the ''last scan in the log'', i.e., current scan. Or am I wrong here? [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 01:12, 28 September 2009 (UTC)<br />
<br />
I'm pretty sure the rotation should be the difference between the current enemyHeading and the enemyHeading at the start of the log sequence, thus no that wouldn't make sense much sense. What I proposed is similar to your code snipped though except: 1) the rotation is fixed as I note, and 2) your current location is your relative location, rotated to be from the rotation of the starting log entry --[[User:Rednaxela|Rednaxela]] 03:01, 28 September 2009 (UTC)<br />
<br />
<code>scan.relativePoint = getVector(scan.headingDelta, scan.velocity);</code> is how my relative point storage work. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 03:51, 28 September 2009 (UTC)<br />
<br />
Ahh, that makes more sense, and in that case, I see why your code doesn't really work: Adding the x and y values for the delta heading vectors like that together cannot yield a correct answer. Since it's delta heading vectors, when reconstructing a path, each vector needs to be rotated by the ones prior to it... and fixing that would make this method slowish again. --[[User:Rednaxela|Rednaxela]] 04:30, 28 September 2009 (UTC)<br />
<br />
Oh yeah... Thank you.<br />
<br />
Anyway, do you understand how this work:<br />
<br />
<tt><br />
Yes, but that description is a mix of DCBot's and Shadow's current method. In DCBot I used the "iterative search" to speed up the trig needed to convert the enemy's past position to the position it would be in the current situation. Doing that step by step is slow, like you mentioned. But then I remembered I could just convert my relative position to the enemy once at the beginning and then the play-back of the enemy movement becomes just additions of dx/dy. And the final firing angle conversion is just 1 addition. It's so simple! I don't know how I didn't come up with it earlier. Now that I think of it, I can probably compare squared distances and save a sqrt per step. About the rotated battlefield, I thought about that, but that would reintroduce the trig complexity and would probably end up slower than the original method. -- ABC<br />
</tt><br />
<br />
? [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 04:35, 28 September 2009 (UTC)<br />
<br />
Well "''convert my relative position to the enemy once at the beginning''" sounds '''exactly''' like what I proposed above, however I'm not sure what is meant by "''And the final firing angle conversion is just 1 addition''" since I still think that last step would involve trig... --[[User:Rednaxela|Rednaxela]] 05:02, 28 September 2009 (UTC)<br />
<br />
I got a working implementation of what ABC does. Take a look at [[oldwiki:DrussGT/HelpRequests]] for a coded version of this. (The problem I actually had was that I was recording heading in degrees, not radians). --[[User:Skilgannon|Skilgannon]] 05:49, 28 September 2009 (UTC)<br />
<br />
: Thank you! --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 06:29, 28 September 2009 (UTC)<br />
<br />
Ahah! Shadow'smethod is indeed exactly what I described with projecting the firing location into the perspective of the history. :) Now... what will make the '''fastest''' projection perhaps... will be combining that method with the fast-forward base on bullet-travel-time estimation :) --[[User:Rednaxela|Rednaxela]] 06:14, 28 September 2009 (UTC)<br />
<br />
: Well, I think in this case the overhead/re-calculation of the BFT estimation will make it slower than ABC's method. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 06:29, 28 September 2009 (UTC)<br />
<br />
Yep, I do exactly like Skilgannon's code. It's very fast, don't know if the iterative BFT search would make it faster, for long BFTs it probably would. --[[User:ABC|ABC]] 11:30, 28 September 2009 (UTC)<br />
<br />
How about jumping forward BFT ticks and then just doing the regular tick-by-tick simulation (either forwards or backwards) from there? I think that would probably be fastest. --[[User:Skilgannon|Skilgannon]] 14:33, 28 September 2009 (UTC)<br />
<br />
Actually, that's what [[Glacier]] currently does (except that it's horribly inefficent and doesn't do those nice optimizations to get the trig out of the loops). It's true that that hybrid may be slightly faster, but I'm thinking the difference would be marginal at best and that purely using BFT search iterations is just so much simpler. For sake of simplicity, I think I probably won't keep that hybrid search once I optimize my PIF. That is... unless I go crazy like I did with the kd-tree :) --[[User:Rednaxela|Rednaxela]] 15:09, 28 September 2009 (UTC)<br />
<br />
I wonder which is faster, this:<br />
<syntaxhighlight><br />
protected Point2D playItForward(Trace start, Trace current, Point2D fireLocation, Rectangle2D field, double bulletVelocity) {<br />
int currentRound = start.round;<br />
double distance = current.distance(fireLocation);<br />
double angle = M.getAngle(current, fireLocation);<br />
double deltaHeading = start.heading - current.heading;<br />
Point2D projectedMyLocation = M.project(start, angle + deltaHeading, distance);<br />
double bulletDistance = 0;<br />
int estimatedBFT = (int) M.ceil(distance / bulletVelocity);<br />
for (int i = 0; i < estimatedBFT; i++) {<br />
start = start.next;<br />
if (start == null || start.round != currentRound)<br />
return null;<br />
bulletDistance += bulletVelocity;<br />
}<br />
distance = start.distance(projectedMyLocation);<br />
int newBFT = (int) M.ceil(distance / bulletVelocity);<br />
distance *= distance;<br />
if (newBFT < estimatedBFT) {<br />
do {<br />
start = start.previous;<br />
bulletDistance -= bulletVelocity;<br />
distance = start.distanceSq(projectedMyLocation);<br />
} while (M.sqr(bulletDistance) > distance);<br />
start = start.next;<br />
bulletDistance += bulletVelocity;<br />
distance = start.distanceSq(projectedMyLocation);<br />
} else if (newBFT > estimatedBFT) {<br />
do {<br />
start = start.next;<br />
if (start == null || start.round != currentRound)<br />
return null;<br />
bulletDistance += bulletVelocity;<br />
distance = start.distanceSq(projectedMyLocation);<br />
} while (M.sqr(bulletDistance) < distance);<br />
}<br />
angle = M.getAngle(projectedMyLocation,start);<br />
distance = M.sqrt(distance);<br />
Point2D resultLocation = M.project(fireLocation, angle - deltaHeading, distance);<br />
if (!field.contains(resultLocation)) {<br />
return null;<br />
}<br />
return resultLocation;<br />
}<br />
</syntaxhighlight><br />
versus:<br />
<syntaxhighlight><br />
protected Point2D playItForwardNormal(Trace start, Trace current, Point2D fireLocation, Rectangle2D field, double bulletVelocity) {<br />
int currentRound = start.round;<br />
double distance = current.distance(fireLocation);<br />
double angle = M.getAngle(current, fireLocation);<br />
double deltaHeading = start.heading - current.heading;<br />
Point2D projectedMyLocation = M.project(start, angle + deltaHeading, distance);<br />
double bulletDistance = 0;<br />
do {<br />
start = start.next;<br />
if (start == null || start.round != currentRound)<br />
return null;<br />
bulletDistance += bulletVelocity;<br />
distance = start.distanceSq(projectedMyLocation);<br />
} while (M.sqr(bulletDistance) < distance);<br />
angle = M.getAngle(projectedMyLocation,start);<br />
distance = M.sqrt(distance);<br />
Point2D resultLocation = M.project(fireLocation, angle - deltaHeading, distance);<br />
if (!field.contains(resultLocation)) {<br />
return null;<br />
}<br />
return resultLocation;<br />
}<br />
</syntaxhighlight><br />
Both code work fine. The first code is Skilgannon's explanation that only do estimated MEA once, and then do play it forward/backward from there. The second one is Shadow's method. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 03:30, 30 September 2009 (UTC)<br />
<br />
And I wonder how the pure-BFT version I have in the dev version of Glacier compares as well:<br />
<br />
<syntaxhighlight><br />
private AbsolutePoint predictSituation(AbsolutePoint origin, double bulletSpeed, EnemyRobot robot, RobotHistory situation) {<br />
// Constants<br />
double rotation = situation.getVelocity().direction - robot.getVelocity().direction;<br />
if (robot.getHistory().getOrientation() != situation.getOrientation()) {<br />
rotation += Math.PI;<br />
}<br />
long timeTillFiring = (long) Math.ceil(robots.getSelf().getGunHeat()/rules.GUN_COOLING_RATE);<br />
RelativePoint relativeLocation = RelativePoint.fromPP(robot.getLocation(), origin);<br />
AbsolutePoint projPoint = situation.getLocation().project(relativeLocation.direction + rotation, relativeLocation.magnitude);<br />
<br />
// Non-constants<br />
long t = -robot.getDataAge() - timeTillFiring;<br />
RobotHistory cursor = situation;<br />
double dist = relativeLocation.magnitude;<br />
long bft = (long) Math.ceil(dist / bulletSpeed);<br />
long lastt = t;<br />
<br />
// Loop while the elapsed time is not the bullet flight time<br />
while (bft != t && !(bft == lastt && t > bft)) {<br />
lastt = t;<br />
if (bft < t) {<br />
// Reverse skip<br />
while (cursor.prev() != null && t > bft) {<br />
cursor = cursor.prev();<br />
t--; // t += cursor.getTime() - cursor.next().getTime();<br />
}<br />
}<br />
else {<br />
// Forward skip<br />
if (cursor.next() == null) {<br />
return null;<br />
}<br />
while (cursor.next() != null && t < bft) {<br />
cursor = cursor.next();<br />
t++; // t += cursor.getTime() - cursor.prev().getTime();<br />
}<br />
}<br />
<br />
// Recalculate bft<br />
dist = cursor.getLocation().distance(projPoint);<br />
bft = (long) Math.ceil(dist / bulletSpeed);<br />
}<br />
<br />
// Get the projected point<br />
double angle = projPoint.angleTo(cursor.getLocation());<br />
AbsolutePoint target = origin.project(angle - rotation, dist); <br />
<br />
// Check that the projected point is within map bounds<br />
if (target.x < 18 || target.x > rules.BATTLEFIELD_WIDTH-36 || target.y < 18 || target.y > rules.BATTLEFIELD_HEIGHT-36) {<br />
return null;<br />
}<br />
<br />
return target;<br />
}<br />
</syntaxhighlight><br />
--[[User:Rednaxela|Rednaxela]] 13:52, 30 September 2009 (UTC)<br />
<br />
I am having problem trying to plug your pure-BFT code into my (new) robot.<br />
<pre><br />
=========================<br />
Round 501 of 10000<br />
=========================<br />
0,000 Method 1 time: 3.5260242 seconds<br />
0,000 Method 2 time: 2.693026591 seconds<br />
</pre><br />
Method 1 is ABC's method, Method 2 is skipping the first BFT and do the rest like normal method. I battled it against Shadow, my bot use HawkOnFire movement so it might have some long-distance adventage. But 500 rounds contains at least 100,000 predictions. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 14:45, 30 September 2009 (UTC)<br />
<br />
I had to remove a couple features (timeTillFiring and 'orientation flip' support) that are important to my usage, but here's a port of my pure-BFT code to the framework that your code samples here use:<br />
<syntaxhighlight><br />
protected Point2D playItForward(Trace start, Trace current, Point2D fireLocation, Rectangle2D field, double bulletVelocity) {<br />
// Constants<br />
double rotation = start.heading - current.heading;<br />
double distance = current.distance(fireLocation);<br />
double angle = M.getAngle(current, fireLocation);<br />
Point2D projectedMyLocation = M.project(start, angle + rotation, distance);<br />
<br />
// Non-constants<br />
long t = -1;<br />
Trace cursor = start;<br />
long bft = (long) Math.ceil(distance / bulletVelocity);<br />
long lastt = t;<br />
<br />
// Loop while the elapsed time is not the bullet flight time<br />
while (bft != t && !(bft == lastt && t > bft)) {<br />
lastt = t;<br />
if (bft < t) {<br />
// Reverse skip<br />
while (cursor.previous != null && t > bft) {<br />
cursor = cursor.previous;<br />
t--;<br />
}<br />
}<br />
else {<br />
// Forward skip<br />
if (cursor.next == null) {<br />
return null;<br />
}<br />
while (cursor.next != null && t < bft) {<br />
cursor = cursor.next;<br />
t++;<br />
}<br />
}<br />
<br />
// Recalculate bft<br />
distance = start.distance(projectedMyLocation);<br />
bft = (long) Math.ceil(distance / bulletSpeed);<br />
}<br />
<br />
// Get the projected point<br />
angle = M.getAngle(projectedMyLocation,start);<br />
Point2D resultLocation = M.project(fireLocation, angle - rotation, distance);<br />
<br />
if (!field.contains(resultLocation)) {<br />
return null;<br />
}<br />
return resultLocation;<br />
}<br />
</syntaxhighlight><br />
I haven't tested it, but I'm pretty sure it's right :) --[[User:Rednaxela|Rednaxela]] 15:24, 30 September 2009 (UTC)<br />
<br />
I had a similar thingie in Portia. The difference was that I skipped forward distance/(bulletSpeed+8) turns, and simulated from there. :) I dropped it because I wasn't sure it was faster, and it added complexity to the code. --[[User:Positive|Positive]] 16:07, 30 September 2009 (UTC)<br />
<br />
<pre><br />
=========================<br />
Round 1000 of 10000<br />
=========================<br />
BFT-than-step-by-step time: 4.533518074 seconds<br />
Pure BFT time: 3.49650074 seconds<br />
</pre><br />
<br />
I'm not sure your method is correct or not (this is codebase in Samekh, but I move it to Pallas whitch is slightly different), that 1,000 rounds I ran with your code (I run both code, but I use the result from your method) I got 100%-0% with Shadow 3.83, but with my BFT-than-step-by-step get 88%-12$ against the same robot (this time it consume 7.x seconds) Anyway, I never realize how fast this method is until I ran this test, it can run at 7-8 rps! (versus Shadow, one of the fastest top bot =)) [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 10:42, 1 October 2009 (UTC)<br />
<br />
I'm not sure how it could be incorrect unless the error occured in porting between bots. It seems to work just fine in [[Glacier]] here. Anyway, I'll soon make a new Glacier release which puts this into action. --[[User:Rednaxela|Rednaxela]] 13:17, 1 October 2009 (UTC)<br />
<br />
Probably the porting, because I uses my own Point (similar to your AbsolutePoint) in Pallas and have extraTick parameter for the play-it-forward. But the result from the debugging graphics looks fine, though. [[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:21, 1 October 2009 (UTC)<br />
<br />
OK, I found the problem. In your ported code you move the cursor but you re-calc BFT using start. Well, but I found another issue with heading (it seems to be 90 degrees off). Dealing with it =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:29, 1 October 2009 (UTC)<br />
<br />
: Silly me... I forgot to change start to cursor in the final projection... It work fine now =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:32, 1 October 2009 (UTC)<br />
<br />
Not sure how the old benchmark time was that, because it seems now that normal Shadow's (ABC's step-by-step) is the fastest. Running 10,000 rounds melee match, will post the time when it finished. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:55, 1 October 2009 (UTC)<br />
<br />
<pre><br />
=========================<br />
Round 680 of 10000<br />
=========================<br />
0,211 Shadow's time: 6.586140695<br />
0,211 Hybrid time: 13.745157619<br />
0,211 Pure BFT time: 8.215406722<br />
SYSTEM: nat.Pallas has died<br />
</pre><br />
<br />
Normal way seems to be faster still... --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 14:31, 1 October 2009 (UTC)<br />
<br />
Huh... that seems strange to me... the "Shadow's time" version will always take at least as many iterations as the other versions... and the main iteration part is exactly the same in the hybrid version. Are you sure you're not testing against a field of rambots? --[[User:Rednaxela|Rednaxela]] 14:46, 1 October 2009 (UTC)<br />
<br />
Perhaps the overhead of 'if' statement in the BFT method. I'm quite sure I'm note testing it against field of rambots; I run it with Shadow, Tron, Shiz, HawkOnFire, DustBunny, Lib, Coriantumr, FloodHT and DoctorBob. I am quite surprise with the result too, so I have already double-checked I'm using right timer (variable) here. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 14:53, 1 October 2009 (UTC)<br />
<br />
I fail to see how Shadow's time could perform faster than the hybrid. The hybrid is essentially the same algorithm, but with probably 3/4 of the double math and double comparisons removed. Also, I think there would be a very different situation in 1v1, where bots move almost completely perpendicular. Perhaps try a version with Positive's method of skipping forward distance/(bulletSpeed+8) turns? --[[User:Skilgannon|Skilgannon]] 15:41, 1 October 2009 (UTC)<br />
<br />
Is it about the ordering? I call the hybrid method first, then Shadow's method, which I use as a result location, then pure BFT method. Will try Positive's method tomorrow, running RoboResearch now =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:48, 1 October 2009 (UTC)<br />
<br />
Perhaps make it so it takes turns calling each one first, eg with a switch and getTime()%3. That would remove any distortion. --[[User:Skilgannon|Skilgannon]] 17:43, 1 October 2009 (UTC)<br />
<br />
: That would raise another problem with enemy distance =) But tested with that and still get the same result, except that Hybrid is now faster than pure-BFT... It doesn't make any senses, really. Perhaps I should upload my testing robot and let you guys test too. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 04:28, 2 October 2009 (UTC)<br />
<br />
== Robot framework ==<br />
<br />
My head full of idea (that I don't want to reveal yet), I know how to implement it. But, I need a framework to base this on. I've been writing my framework for months, but it isn't finished yet. (after I release PallasHawk, I realize that the event delegater there is useless =() I have partial finished framework spread all over my robot Eclipse's workspace.<br />
<br />
Just for a note, I have been seeking for a robot framework. I have looked at PluggableRobot and Module. I don't like Module because the separation of Targeting (which aim) and Gun (which choose bullet power). For PluggableRobot, I don't like the design of its painting system. This left me choice of Red's RobotBase. I like Red's one, but I feel that it is incomplete for a 'robot framework' (of course, it is just a RobotBase). The idea of 'actors' are good but passing a group of Event at once is part I don't like. So I create the event delegater (like in PallasHawk) and realise that that makes my code in gun/movement too complicated. So I need the delegater that store all events in queue, and delegate events to each listener one-by-one (like if we have 2 scan robot event this tick, first listener receive both event first, then the second listener get the events and so on) Also, I make interface 'Movement', 'Gun' and 'Radar' so I can set the 'current' movement and gun and radar. The Robot Framework automatically pass the 'actor' to the current move/gun/radar. This is what the future Ceres Framework will be. OK, back to work... (this framework has been rewritten for at least 20 times already) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 08:13, 15 October 2009 (UTC)<br />
<br />
== Google Wave ==<br />
<br />
Just want to ask, who here have Google Wave ID? It is so lonely on the Google Wave, and my friends aren't interested in (even they are, it take a while for the invitation to be considered and delivered by Google) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 14:32, 26 October 2009 (UTC) (PS. my ID is http://services.nexodyne.com/email/customicon/o0LTknLL.IohHF03LXij1NstZWGutg%3D%3D/RpAUCaY%3D/bfffff/00bf00/000000/5/image.png)<br />
<br />
== I blame you! ==<br />
<br />
Here I was all fine and dandy, doing C++ code, writing embedded applications and working on writing 3D rendering systems. not the care in the world, robocode nowhere in my thoughts. Then you come along and ask me about Artificial Neural Networks! Then I proceeded to write Java implementation of Kohonen Maps. Then I wrote a Robot using that Java implementation in a gun. Then I write a small update to my roboflight idea (in java). Then I make that robot use 10 combined maps of different update speeds, combine them and use Kernel density estimation to find the best related data between them to find the best firing angle based on wave gf targeting. Then I proceeded to write a precise prediction algorithm to calculate the escape angle for robots to further improve targeting. Now here I am checking the wiki every day looking for relevant articles to comment upon and writing new ways to improve the score of my Kohonen map based targeting implementation. I blame you!!!! T_T --[[User:Chase-san|Chase]] 06:49, 14 November 2009 (UTC)<br />
<br />
Well, you should know how attractive Robocode is. Should I expected new robot from you in near future? Any, if you haven't do already please read http://bit.ly/gaffnn (I can't remember its wiki path, shortened url is much easier to remember) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 07:06, 14 November 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=Archived_talk:Kenran&diff=16921Archived talk:Kenran2010-07-01T08:42:27Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{| width="100%" style="background: white; " <br />
| valign="top" width="60%" style="border: 2px solid #000; padding: .5em 1em; -moz-border-radius: 1em; -webkit-border-radius: 1em" |<br />
'''Welcome!'''<br />
<br />
Hello, {{BASEPAGENAME}}, and welcome to [[RoboWiki]]! This place contains a wealth information about [[Robocode]], from [[Head-On Targeting|basic]] to [[Wave Surfing|more advanced]]. I hope you enjoy creating robots and being a robocoder!<br />
<br />
If you are posting a comment on this wiki, please [[wikipedia:Wikipedia:Signatures|sign]] your messages using four tildes (<nowiki>--~~~~</nowiki>); this will automatically insert your username and the date stamp. If you are not familiar with MediaWiki, these links might help you out:<br />
* [[wikipedia:How to edit|How to edit]] on [[wikipedia:|Wikipedia]], [[metawikipedia:Cheatsheet|Cheatsheet]] and [[metawikipedia:File:MediaWikiRefCard.pdf|Reference Card]] of MediaWiki on the [[metawikipedia:|Meta Wikipedia]].<br />
* [[RoboWiki:ReadMe|Readme]] page.<br />
If you need [[Help:Help|help]], check out the [[Robocode/FAQ|frequently asked questions]] or ask it on this page. Again, welcome!<br />
<br />
—— [[User:Rednaxela|Rednaxela]] 15:59, 28 November 2009 (UTC) <br />
|}<br />
<br />
Welcome to the wiki! :) --[[User:Rednaxela|Rednaxela]] 15:59, 28 November 2009 (UTC)<br />
<br />
Hello, and thank you. :-) --[[User:Kenran|Kenran]] 09:07, 29 November 2009 (UTC)<br />
<br />
== My first try at Pattern Matching ==<br />
<br />
So this my first attempt to write a simple pattern matching gun. As you can see, my in some sense my code is similar to that of [[PEZ]]'s LeachPMC, where I looked at to help me do it. (Thanks for that, PEZ :-)).<br />
<br />
But now I'm having some trouble and would be very happy if someone with Robocode and Java knowledge could overlook it and / or help me with it:<br />
* As you can see <code>aimed</code> is superfluous at the moment. I tried to make the bot faster by only calculating predictedPosition at moments where I actually want to shoot. But I can't seem to handle this: I wanted to do sth like <code>if (getGunHeat() > getGunCoolingRate()*3 && getRoundNum() != 0)</code>, then predict and set <code>aimed = true</code>, and finally fire if <code>aimed == true && getGunTurnRemaining() == 0.0</code> (and set <code>aimed = false</code> again). But that doesn't work, at a certain point it just stops firing at all then :-/<br />
* I don't understand why, e.g. versus Walls, it can't handle the movement in the edges: it seems to predict the right "position" but at the wrong time, so the bullets just impact before Walls is at that position. Any ideas why this could be the case? Maybe sth with my predictPosition algorithm.<br />
<br />
I hope, my code is not too sloppy, as I mentioned, I'm not a very good programmer. Anyway, great site, I wouldn't have been able to get any kind of targeting working without it :-)<br />
<br />
<syntaxhighlight>package kenran.mega;<br />
<br />
import robocode.*;<br />
import kenran.util.*;<br />
import java.awt.geom.Point2D;<br />
import java.util.ArrayList;<br />
<br />
public class Pantheist extends AdvancedRobot<br />
{<br />
private static final int PM_LENGTH = 7000;<br />
private static final int RECENT_PATTERN_LENGTH = 10;<br />
<br />
private static Point2D _enemyPosition = new Point2D.Double();<br />
private static Point2D _robotPosition = new Point2D.Double();<br />
private static double _enemyHeading = 0;<br />
private static double _enemyBearing;<br />
private static double _enemyVelocity;<br />
private static double _enemyDistance;<br />
private static double _deltaHeading;<br />
<br />
private static ArrayList _record = new ArrayList(PM_LENGTH);<br />
private static MovementDeque _recent = new MovementDeque();<br />
private static MovementDeque _iterator = new MovementDeque();<br />
private static int _recordSize = 0;<br />
private static boolean _recordIsFull = false;<br />
<br />
private static boolean aimed;<br />
<br />
<br />
public void run()<br />
{<br />
setAdjustGunForRobotTurn(true);<br />
setAdjustRadarForGunTurn(true);<br />
aimed = false;<br />
if (getRoundNum() == 0)<br />
for (int i = 0; i < RECENT_PATTERN_LENGTH; i++)<br />
_recent.add(0, 8.0);<br />
turnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
do<br />
{<br />
scan();<br />
} while (true);<br />
}<br />
<br />
<br />
public void onScannedRobot(ScannedRobotEvent e)<br />
{<br />
_robotPosition.setLocation(getX(), getY());<br />
_enemyDistance = e.getDistance();<br />
_deltaHeading = e.getHeadingRadians() - _enemyHeading;<br />
_enemyHeading = e.getHeadingRadians();<br />
_enemyBearing = getHeadingRadians() + e.getBearingRadians();<br />
_enemyVelocity = e.getVelocity();<br />
_enemyPosition.setLocation(Utils.project(_robotPosition, _enemyBearing, _enemyDistance));<br />
record(_deltaHeading, _enemyVelocity);<br />
_recent.add(_deltaHeading, _enemyVelocity);<br />
if (getRoundNum() != 0)<br />
{<br />
Point2D predictedPosition = new Point2D.Double();<br />
predictedPosition.setLocation(predictPosition(1.5));<br />
double angle = Utils.absoluteBearing(_robotPosition, predictedPosition);<br />
setTurnGunRightRadians(Utils.normalRelativeAngle(angle - getGunHeadingRadians()));<br />
aimed = true;<br />
}<br />
if (getRoundNum() != 0 && aimed)<br />
{<br />
setFire(1.5);<br />
aimed = false;<br />
}<br />
double radarTurn = _enemyBearing - getRadarHeadingRadians();<br />
setTurnRadarRightRadians(2.0*Utils.normalRelativeAngle(radarTurn));<br />
}<br />
<br />
<br />
private void record(double dh, double v)<br />
{<br />
_record.add(new MovementState(dh, v));<br />
if (_recordIsFull)<br />
_record.remove(0);<br />
else<br />
{<br />
_recordSize++;<br />
_recordIsFull = (_recordSize >= PM_LENGTH);<br />
}<br />
}<br />
<br />
<br />
private double compare(MovementDeque md1, MovementDeque md2)<br />
{<br />
double sum = 0;<br />
for (int i = 0; i < RECENT_PATTERN_LENGTH; i++)<br />
{<br />
sum += Math.abs(md1.get(i).getDeltaHeading()-md2.get(i).getDeltaHeading()) + Math.abs(md1.get(i).getVelocity()-md2.get(i).getVelocity());<br />
}<br />
return sum;<br />
}<br />
<br />
<br />
private int lastIndexOfMatchingSeries()<br />
{<br />
for (int i = 0; i < RECENT_PATTERN_LENGTH; i++)<br />
_iterator.add((MovementState)_record.get(i));<br />
double min = compare(_iterator, _recent);<br />
int minPos = RECENT_PATTERN_LENGTH - 1;<br />
int i = RECENT_PATTERN_LENGTH;<br />
do<br />
{<br />
MovementState ms = (MovementState)_record.get(i);<br />
_iterator.add(ms.getDeltaHeading(), ms.getVelocity());<br />
double comp = compare(_iterator, _recent);<br />
if (comp < min)<br />
{<br />
min = comp;<br />
minPos = i;<br />
}<br />
i++;<br />
} while (i < _recordSize - 50);<br />
return minPos;<br />
}<br />
<br />
<br />
private Point2D predictPosition(double power)<br />
{<br />
int index = lastIndexOfMatchingSeries();<br />
double px = _enemyPosition.getX();<br />
double py = _enemyPosition.getY();<br />
double heading = _enemyHeading;<br />
double bulletTravelTime = 0;<br />
double travelTime = 0;<br />
for (int i = index+1; i < _recordSize && travelTime <= bulletTravelTime; i++)<br />
{<br />
MovementState ms = (MovementState)_record.get(i);<br />
px += Math.sin(heading) * ms.getVelocity();<br />
py += Math.cos(heading) * ms.getVelocity();<br />
heading += ms.getDeltaHeading();<br />
bulletTravelTime = (int)Utils.bulletTravelTime(_robotPosition.distance(px, py), power);<br />
travelTime++;<br />
}<br />
return new Point2D.Double(px, py);<br />
}<br />
<br />
<br />
static class MovementDeque<br />
{<br />
private MovementState[] msArray = new MovementState[RECENT_PATTERN_LENGTH];<br />
<br />
MovementDeque() {}<br />
<br />
void add(double dh, double v)<br />
{<br />
for (int i = 0; i < RECENT_PATTERN_LENGTH-1; i++)<br />
msArray[i] = msArray[i+1];<br />
msArray[RECENT_PATTERN_LENGTH-1] = new MovementState(dh, v);<br />
}<br />
<br />
void add(MovementState ms)<br />
{<br />
add(ms.getDeltaHeading(), ms.getVelocity());<br />
}<br />
<br />
MovementState get(int i)<br />
{<br />
if (0 <= i && i < RECENT_PATTERN_LENGTH)<br />
return msArray[i];<br />
else<br />
return null;<br />
}<br />
}<br />
}</syntaxhighlight><br />
--[[User:Kenran|Kenran]] 15:48, 5 December 2009 (UTC)<br />
<br />
What is the propose of <code>getRoundNum() != 0</code>? That means it won't fire in the first round. If you remove all reference to the getRoundNum() == 0 or getRoundNum() !== 0, I think it will perform much better.<br />
<br />
Actually I would say, don't use the PMC robot as a codebase, as it is very optimized to the PMChallenge. Try to read the robot with normal PM, e.g. Waylander, before. If you can't figure out what is behind the shrunk code of Waylander, feel free to ask again. {{Unsigned|Nat}}</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Jdev/Questions&diff=16920User talk:Jdev/Questions2010-07-01T08:42:23Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>; RhinoScriptEngine - it's fair play or not?<br />
I find out today, that there're embed script engine may be used, to reduce codesize.<br />
Example:<br />
<syntaxhighlight><br />
package lxx.test.js;<br />
<br />
import robocode.AdvancedRobot;<br />
import com.sun.script.javascript.RhinoScriptEngine;<br />
<br />
import javax.script.ScriptException;<br />
import javax.script.ScriptContext;<br />
import javax.script.SimpleScriptContext;<br />
<br />
/**sure<br />
* User: jdev<br />
* Date: 11.11.2009<br />
*/<br />
public class JSTest extends AdvancedRobot {<br />
<br />
public void run() {<br />
RhinoScriptEngine rse = new RhinoScriptEngine();<br />
try {<br />
ScriptContext ctx = new SimpleScriptContext();<br />
rse.eval("var a = 100;", ctx);<br />
Double i = (Double) ctx.getAttribute("a");<br />
ahead(i);<br />
} catch (ScriptException e) {<br />
e.printStackTrace();<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
so i can rewrite most part of my code on js and only call it it nanobot. but i don't sure, that it is fair.<br />
What do you think about it?<br />
--[[User:Jdev|Jdev]] 16:37, 11 November 2009 (UTC)<br />
<br />
I think it was generally agreed that using interpreted languages to bypass the codesize utility isn't exactly fair, so although you can put your bot in the rumble to see where it would score, it would be better if you didn't leave it there, because based on the amount of code you have, it probably isn't a nanobot anyways. Look at [[White Whale]] and [[Talk:White Whale]] for more discussion on this =) It's quite cool that there is an included script engine in Java, I didn't even know about it =) --[[User:Skilgannon|Skilgannon]] 17:19, 11 November 2009 (UTC)<br />
<br />
Why i so honest?=)<br />
I glad, that i give something new in java=) there're also interpreters for php python, as i know. And i'm sure that there're also engines for other languages. --[[User:Jdev|Jdev]] 17:28, 11 November 2009 (UTC)<br />
<br />
Aside from what Skilgannon said... I'm very doubtful it can be used to reduce codesize actually for the following reason: I'm 95% certain that Robocode does ''not'' let robots access packages that are not part of the core java standard, in particular, I'm pretty certain you can't access the <code>com.sun</code> package from inside robots, maybe not even the <code>javax</code> package. Nice trythough, hah. --[[User:Rednaxela|Rednaxela]] 17:35, 11 November 2009 (UTC)<br />
<br />
I check it before publishing - it works=) --[[User:Jdev|Jdev]] 17:55, 11 November 2009 (UTC)<br />
<br />
I'm running [http://openjdk.java.net OpenJDK], which doesn't include Rhino. So I can't compile this bot, and any bot based on this would get 0 on my system =) --[[User:Skilgannon|Skilgannon]] 19:15, 11 November 2009 (UTC)<br />
<br />
Yes, you right=) I try to use<br />
<pre><br />
new ScriptEngineManager().getEngineByName("JavaScript")<br />
</pre><br />
, but "Preventing lxx.UltraMarine 1.0 from access (java.lang.RuntimePermission createClassLoader)" appears. So question is closed=) --[[User:Jdev|Jdev]] 19:29, 11 November 2009 (UTC)<br />
<br />
It's not possible to get around it by going the other way either:<br />
<syntaxhighlight><br />
package jk;<br />
<br />
import robocode.AdvancedRobot;<br />
<br />
import javax.script.*;<br />
import java.util.*;<br />
<br />
<br />
public class JSTest extends AdvancedRobot {<br />
<br />
public void run() {<br />
ScriptEngineManager manager = new ScriptEngineManager();<br />
List <ScriptEngineFactory> l = manager.getEngineFactories();<br />
ScriptEngine engine = null;<br />
for(ScriptEngineFactory sef:l){<br />
engine = sef.getScriptEngine();<br />
System.out.println("Engine found: " + sef.getEngineName());<br />
}<br />
<br />
<br />
try {<br />
Double i = (Double)engine.eval("var a = 100; return a;");<br />
ahead(i);<br />
} <br />
catch (ScriptException e) {<br />
e.printStackTrace();<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
throws<br />
<pre><br />
jk.JSTest: Exception: java.security.AccessControlException: Preventing jk.JSTest from access: (java.lang.RuntimePermission createClassLoader)<br />
java.security.AccessControlException: Preventing jk.JSTest from access: (java.lang.RuntimePermission createClassLoader)<br />
at robocode.security.RobocodeSecurityManager.checkPermission(Unknown Source)<br />
at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:611)<br />
at java.lang.ClassLoader.<init>(ClassLoader.java:242)<br />
at org.mozilla.javascript.DefiningClassLoader.<init>(DefiningClassLoader.java:54)<br />
at org.mozilla.javascript.ContextFactory.createClassLoader(ContextFactory.java:352)<br />
at org.mozilla.javascript.Context.createClassLoader(Context.java:2262)<br />
at org.mozilla.javascript.SecurityController.createLoader(SecurityController.java:143)<br />
at org.mozilla.javascript.optimizer.Codegen.defineClass(Codegen.java:142)<br />
at org.mozilla.javascript.optimizer.Codegen.createScriptObject(Codegen.java:101)<br />
at org.mozilla.javascript.Context.compileImpl(Context.java:2409)<br />
at org.mozilla.javascript.Context.compileString(Context.java:1359)<br />
at org.mozilla.javascript.Context.compileString(Context.java:1348)<br />
at org.mozilla.javascript.Context.evaluateString(Context.java:1101)<br />
at com.sun.script.javascript.RhinoTopLevel.<init>(RhinoTopLevel.java:72)<br />
at com.sun.script.javascript.RhinoScriptEngine.<init>(RhinoScriptEngine.java:92)<br />
at com.sun.script.javascript.RhinoScriptEngineFactory.getScriptEngine(RhinoScriptEngineFactory.java:74)<br />
at jk.JSTest.run(JSTest.java:21)<br />
at robocode.peer.RobotPeer.run(Unknown Source)<br />
at java.lang.Thread.run(Thread.java:636)<br />
</pre><br />
--[[User:Skilgannon|Skilgannon]] 19:59, 11 November 2009 (UTC)<br />
<br />
The improved security manager is partly my fault, as I awhile ago demonstrated hackbots which staticly accessed the internal classes in robocode. I also took the route of showing I could access parts of the JDK which allowed web access (which I later tested by downloading a file from my server), this in turn caused FNL to beef up the security manager, which for the most part is for the best, as running one of the built in script engines in your bot could allow it to run unsigned or hazardous code which could get around the security manager. --[[User:Chase-san|Chase]] 20:42, 11 November 2009 (UTC)<br />
<br />
<br />
----<br />
<br />
; What of fire situation attributes (like lateral velocity, distance, near wall etc.) you use for segmentation you data?<br />
I understand, that it may be "professional secret", but if any of top bot authors share this info - it will be cool=)<br />
Thank you=) --[[User:Jdev|Jdev]] 10:32, 19 February 2010 (UTC)<br />
<br />
Easy -- Lateral Velocity seems to be the most important. Distance and near wall can split the movement type in situations. Try to look at Top Bot source code =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 11:12, 19 February 2010 (UTC)<br />
<br />
It's important for me to don't see other bot's source code =) --[[User:Jdev|Jdev]] 11:30, 19 February 2010 (UTC)<br />
<br />
Then it is what I said, plus some experiment. This information is vary between different implementation. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 12:02, 19 February 2010 (UTC)<br />
<br />
Yep, lateral velocity, distance (I'd use "bullet flight time" instead), wall distance, and velocity change (accelerating/decelerating or time since velocity change) are the most important ones. Somewhere on the wiki is a table of what attributes/how many slices some top bots use (starting with Skilgannon/[[DrussGT]]), but I'm failing to find it with a quick Google search right now... --[[User:Voidious|Voidious]] 12:40, 19 February 2010 (UTC)<br />
<br />
: I think the tables you're referring to are here: http://old.robowiki.net/cgi-bin/robowiki?TargetingChallenge2K7/ResultsChat --[[User:Darkcanuck|Darkcanuck]] 14:47, 20 February 2010 (UTC)<br />
<br />
: Thanks! I swear I spent like 20 minutes Googling and wiki-searching for those. =) (I thought they were on the new wiki, too...) --[[User:Voidious|Voidious]] 15:23, 22 February 2010 (UTC)<br />
<br />
I'm considering the same issues right now as well. Right now LBB only segments on Distance - but it segments its movement as well as its gun. I'm currently investigating Lateral velocity and averaged velocity acceleration right now, combined with distance and the results are decent. I'm not yet sold though as my firepower management still needs improvement. Funny thing though, even distance by itself does ok against simpler bots. --[[User:Miked0801|Miked0801]] 17:48, 19 February 2010 (UTC)<br />
<br />
A quick little note about distance: In some experiments, I was finding that distance was ranking as very unimportant actually, however those experiments were in a 'Targeting Challenge' environment where only the enemy moves and distances stay relatively stable. As soon as I put it on a movement and into the rumble, I found that adding some more distance-related (bullet travel time), segmentation helped significantly. --[[User:Rednaxela|Rednaxela]] 18:45, 19 February 2010 (UTC)<br />
<br />
Thanks for all. Now I develop autosegmentet gun, which use currently about 40 fire situation attributes, and it seems (imaging, looking?) not bad.<br />
--[[User:Jdev|Jdev]] 11:57, 22 February 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Jdev&diff=16919User talk:Jdev2010-07-01T08:42:21Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{| width="100%" style="background: white; " <br />
| valign="top" width="60%" style="border: 2px solid #000; padding: .5em 1em; -moz-border-radius: 1em; -webkit-border-radius: 1em" |<br />
'''Welcome!'''<br />
<br />
Hello, Jdev, and welcome to [[RoboWiki]]! This place contain a wealth information about [[Robocode]], from [[Head-On Targeting|basic]] to [[Wave Surfing|more advanced]]. I hope you enjoy creating robots and being a robocoder!<br />
<br />
If you are posting a comment on this wiki, please [[wikipedia:Wikipedia:Signatures|sign]] your messages using four tildes (<nowiki>--~~~~</nowiki>); this will automatically insert your username and the date stamp. If you are not familiar with MediaWiki, these links might help you out:<br />
* [[wikipedia:How to edit|How to edit]] on [[wikipedia:|Wikipedia]], [[metawikipedia:Cheatsheet|Cheatsheet]] and [[metawikipedia:File:MediaWikiRefCard.pdf|Reference Card]] of MediaWiki on the [[metawikipedia:|Meta Wikipedia]].<br />
* [[RoboWiki:ReadMe|Readme]] page.<br />
If you need [[Help:Help|help]], check out the [[Robocode/FAQ|frequently asked questions]] or ask it on this page. Again, welcome!<br />
<br />
—— [[User:Nat|Nat]] 12:37, 22 July 2009 (UTC) <br />
|}<br />
<br />
<br />
Probably the funniest user page ever! It took me a while before I understand 'well come' as 'welcome'. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 06:25, 24 October 2009 (UTC)<br />
<br />
Thank you) i'll fix "welcome") --[[User:Jdev|Jdev]] 10:40, 24 October 2009 (UTC)<br />
<br />
It isn't usualy form of communication for me, which used here. <br />
Anybody, please, say me which rules there're, where and what i can find here, where i can write, etc. I don't want irritate anybody) --[[User:Jdev|Jdev]] 15:21, 24 October 2009 (UTC)<br />
<br />
The only rule is 'Pretty please be polite'. It can be found on [[RoboWiki:ReadMe|Readme]] page. You can do anything you want. I think all of us agree that 'common senses' is the second rule. If you do something wrong, then we'll fix it for you. I admit I have done a lot of wrong things on this before. Just learn from mistakes. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:30, 24 October 2009 (UTC)<br />
<br />
Thank you) --[[User:Jdev|Jdev]] 15:33, 24 October 2009 (UTC)<br />
<br />
Welcome from me too, cool user page! :) --[[User:Positive|Positive]] 21:14, 24 October 2009 (UTC)<br />
<br />
Thank you too) I glad, that robocode community is so newbie-frendly)--[[User:Jdev|Jdev]] 21:18, 24 October 2009 (UTC)<br />
<br />
Well, everybody started out as a newbie, some better than others. Without newbies, the community would slowly vanish. So, welcome, and I hope you turn out to become a veteran. ;-) --[[User:GrubbmGait|GrubbmGait]] 11:22, 25 October 2009 (UTC)<br />
<br />
In the fact i'm already veteran - i robocoder from 2005) just only this summer i leave my computer and go search happy online) --[[User:Jdev|Jdev]] 17:00, 25 October 2009 (UTC)<br />
<br />
May be there're mean to do code review for published listings? i think, that public code review (code review done by community) is the best way to make code perfect. --[[User:Jdev|Jdev]] 09:33, 28 October 2009 (UTC)<br />
<br />
I don't think there is a need of the a 'published listing' if you mean to create new one. Normally I (and I think several other too) randomly read robot's code, and if we spot any bugs, we are kind enough to report them, not to humiliate the author =) In case that you mean to review the existing listing, I think I have enough work already... --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:28, 28 October 2009 (UTC)<br />
<br />
Just i read today this code [[PluggableRobot/Source]] and, IMHO, there're some not good decision. Also i'm Warrior of Perfect code and try to fight for it evrywhere) <br />
But i understand main idea - make it by yourself, but be polite) --[[User:Jdev|Jdev]] 13:36, 28 October 2009 (UTC)<br />
<br />
I agree that PluggableRobot's source isn't very good -- and if I am correct it won't run under Robocode 1.6.1.4 which is use in RoboRumble (key line: <code>_g = bot.getGraphics();</code>) My (developing) robot is currently based on almost the same feature as PluggableRobot framework but with less and much (IMO) cleaner code. Another that may come into effect, is that someone can't read other people's code at all. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 13:59, 28 October 2009 (UTC)<br />
<br />
Sorry for the late response, but your user page is awesome. =) And welcome to the wiki. About the code review, I don't think many Robocoders are so formal about publishing/reviewing code. (You are certainly welcome to try to organize formal code reviews, but most of us are probably too hooked on our own bots to participate much. =)) I imagine Robert would welcome any feedback you have, though, so you could certainly post it on [[Talk:PluggableRobot|the talk page]]. He hasn't been around for a bit, but I don't think he's gone forever. And of course, if you want, you could base a new framework on PluggableRobot, since it's licensed under [[RWLPCL]]. --[[User:Voidious|Voidious]] 19:29, 28 October 2009 (UTC)<br />
<br />
It's okey and thank you) and thank you one more time)<br />
Ok, i think that soon i will publish my own framework, as alternative) --[[User:Jdev|Jdev]] 05:59, 29 October 2009 (UTC)<br />
<br />
I really wanted to ask, what is that ')' you wrote? If you are using smiley, it should be either :-) or :) or =) etc.<br />
<br />
One the point about the robot framework, I have looked into many different robots and I can't find any robot use any of existing frameworks ([[PluggableRobot]] and [[Module]]). Some ideas are borrowed, though... This is why I decided not to release my framework. (but I admit I really want to see your compare to mine) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 11:57, 29 October 2009 (UTC)<br />
<br />
1) why "it sgould be"? it's just shortest form of smile) as you can see, i use it very often, so it's not bad optimization of my typig<br />
2) hm... ok, then i will publish it's special for you) but it will be not very soon - now there're active phase of developing and i didn't refactor and code review yet --[[User:Jdev|Jdev]] 12:10, 29 October 2009 (UTC)<br />
<br />
Okay, I understand your point. But, maybe just me, when I see 'blah blah) blahblah) blah)' I would look before to find '('. But wonder, the '=' key is just two keys on the left of ')'.... Okay, I should s**t up about this. About the framework, if you want to see mine, just email me. (email on my use page) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 12:20, 29 October 2009 (UTC)<br />
<br />
Okay, I understand your point=)<br />
yes, it's interesting for me. but i think, that it will be honestly, if i also show you my framework some time. may be i will not publish my code, but just email it's for you=) --[[User:Jdev|Jdev]] 12:28, 29 October 2009 (UTC)<br />
<br />
Last year i implement and discard 15 different guns (simple guns, genetics programming guns, random guns, PM guns, statistical guns, log based guns) and today start implement new one. Who implement more guns?:) it's so hard to "build the best, destroy the rest"...:) --[[User:Jdev|Jdev]] 07:06, 17 March 2010 (UTC)<br />
<br />
Hmm... well, in my early times Robocoding I implemented, 1) Head-on targeting, 2) Linear targeting, 3) Circular Targeting, 4) A crude pattern matcher, 5) a 'single-tick' pattern matcher as it's often termed, and 6) A rough attempt at using a hopfield neural net for a pattern matcher. None of those are in use anymore. More recently I've done, 7) RougeDC's DC-GF gun, 8) RougeDC's auxiliary PM targeting, 9) Some brief 'cluster tree' experiment that was never fit for real use, 10) A sort of targeting system in Polylunar to detect situations where a certain angle of fire is guaranteed to hit (falling back to I think linear when that gave no guarantee), 11) Antialiased/Interpolated VCS GF gun (aka SaphireEdge), and 12) Glacier's DC-PIF targeting. I think that's a full history of the targeting systems I've done over the years, the first half mostly being simple ones that I never kept. --[[User:Rednaxela|Rednaxela]] 15:40, 17 March 2010 (UTC)<br />
<br />
<br />
Also I have an idea about select gun for shot from guns array. But it was failed in my implementation and maybe anybody else will be more successive. Idea: you know, that gun has 10% hit rate, it's about one hit per ten shots. so, if gun wasn't hit in more than 10 shots, each miss will increment probability of hit with next shot, so you should select the gun, which have lowest hit rate in last time. i try to implement it, but i get little decrement of performance, while in theory it looks very good. --[[User:Jdev|Jdev]] 20:44, 17 March 2010 (UTC)<br />
<br />
I have thought about ways to account for the fluctuating nature of hit rates, but I think your idea is flawed. It sounds like [[wikipedia:Gambler's fallacy|Gambler's fallacy]]. I agree that VGs probably switch away from the better gun because of fluctuating hit rates all too often, but trying to adjust for that is not an easy task... --[[User:Voidious|Voidious]] 21:12, 17 March 2010 (UTC)<br />
<br />
Yes, against typical random movement, this is exactly the "[[wikipedia:Gambler's fallacy|Gambler's fallacy]]" which is why it doesn't work. One note is that this is ''not'' technically the gambler's fallacy against bots with non-'perceptual' movement, but except but against active flatteners or surfers probably has no chance of helping. Against active flatteners and surfers, I suspect there that attack the issues against them more directly instead of just happening to switch guns when the surfer doesn't expect it. ----<br />
<br />
I'm not complectly agree. For example you have HOT and Circular guns. One will hit enemy in corners, while another in else situations. so if you hit by one gun some times, it's time to switch gun. But may be there're too much trivial example. Any way, i think that it's better to share an idea) --[[User:Jdev|Jdev]] 07:53, 18 March 2010 (UTC)<br />
<br />
If you're talking about against random movers, that IS the gambler's fallacy. If you're talking about bots with varied but non-random (or poorly randomized) movement, then yes it could work out in some scenarios but not because of why you said. If you flip a coin, and by luck get 'heads' 5 times in a row, your chance of getting 'tails' next is still 50/50, no higher. --[[User:Rednaxela|Rednaxela]] 12:19, 18 March 2010 (UTC)<br />
<br />
<br />
ok, let's it will be so - i'm not sure in it so much, to disput about it) --[[User:Jdev|Jdev]] 12:53, 18 March 2010 (UTC)<br />
<br />
<br />
----<br />
<br />
hi to all. i have a bug in my radar code and cannot fix it.<br />
Code:<br />
<syntaxhighlight><br />
LXXPoint enemyPos = lastUpdated.getPosition();<br />
double radarTurnDirection = signum(Utils.normalRelativeAngle((angleTo(enemyPos) - getRadarHeadingRadians())));<br />
if (Utils.isNear(radarTurnDirection, 0)) {<br />
radarTurnDirection = 1;<br />
}<br />
System.out.println("===========================");<br />
System.out.println("[DEBUG]: radar turn direction = " + radarTurnDirection);<br />
System.out.println("[DEBUG]: Angle to enemyPos = " + toDegrees(angleTo(enemyPos)));<br />
System.out.println("[DEBUG]: radar heading = " + toDegrees(getRadarHeadingRadians()));<br />
double radarTurnAngle = Utils.normalRelativeAngle((angleTo(enemyPos) + (Rules.RADAR_TURN_RATE_RADIANS / 2) * radarTurnDirection) -<br />
getRadarHeadingRadians());<br />
System.out.println("[DEBUG]: radarTurnAngle = " + toDegrees(radarTurnAngle));<br />
if (abs(radarTurnAngle) > Rules.RADAR_TURN_RATE_RADIANS) {<br />
radarTurnAngle = Rules.RADAR_TURN_RATE_RADIANS * radarTurnDirection * 0.99;<br />
System.out.println("[DEBUG]: radarTurnAngle = " + toDegrees(radarTurnAngle));<br />
}<br />
setTurnRadarRightRadians(radarTurnAngle);<br />
<br />
lastRadarTurnDirection = (int) radarTurnDirection;<br />
</syntaxhighlight><br />
<br />
log:<br />
<pre><br />
<br />
===========================<br />
radar turn direction = -1.0<br />
Angle to p = 237.94483339133959<br />
radar heading = 260.4730460891953<br />
angle = -45.02821269785571<br />
angle = -44.550000000000004 - turn radar on 44 degrees<br />
===========================<br />
radar turn direction = 1.0<br />
Angle to p = 237.95354219349272<br />
radar heading = 235.44087274677435 - but in fact 260.47304608919535 - 235.44087274677435 = 25 degrees<br />
angle = 25.012669446718338<br />
</pre><br />
<br />
it seems like bug in robocode, but i think, if it was so, then this bug was already fixed.<br />
<br />
Most part of time, this code works fine, but in rare and unknown envorinment it's produce log like upper.<br />
<br />
Any suggestions?:)<br />
--[[User:Jdev|Jdev]] 15:55, 8 June 2010 (UTC)<br />
<br />
Just update --[[User:Jdev|Jdev]] 16:49, 17 June 2010 (UTC)<br />
----<br />
<br />
Hm, sorry I didn't look at this close enough before but I think I see the problem. Robocode is behaving correctly, however one must realize that Rules.RADAR_TURN_RATE_RADIANS is the maxiumum radar turning rate ''relative'' to the gun turret, and the max gun turret rotation is relative to the body rotation. Even if you use setAdjustGunForRobotTurn(true) and setAdjustRadarForGunTurn(true), the maximum turn still depends on how much the gun and body are moving. One quick note, is to my knowledge very few bots take advantage of this. One of the few being my melee bot [[Glacier]], which uses gun turning when not firing in order to boost how wide a radar arc it can make. --[[User:Rednaxela|Rednaxela]] 19:30, 17 June 2010 (UTC)<br />
<br />
Thank you very much! It's the answer. I read it in javadocs, but because my english skill dont understood it correctly:) --[[User:Jdev|Jdev]] 19:51, 17 June 2010 (UTC)<br />
<br />
----<br />
<br />
Just collaboration:<br />
Method Rules.getTurnRateRadians(velocity) return correct values (real possible turn rates), only if the velocity is in interval [0, 8] and it returns incorrect values for arguments like -16, -8, -2, 10, 15 etc.<br />
<br />
So be careful and don't repeat my mistakes) --[[User:Jdev|Jdev]] 19:01, 22 June 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Jlm0924&diff=16918User talk:Jlm09242010-07-01T08:42:19Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>== DemonicRage v2.0 ==<br />
I spent alot of time lately working on Demonics movement. In the process I lost the source to some older versions like 1.4 while tring to re-invent the wheel. but I'm happy with the out come, and think it has alot of potiental. I noticed after posting that it got booted from a rumble match while fighting with shadow and sandBox for skipping turns. I will have to fix. --[[User:Jlm0924|Jlm0924]] 06:12, 8 September 2009 (UTC)<br />
<br />
v2.0b, is funtionally the same, the disabled wave surfing / tracking processing was commented out to try and speed it up a bit.. if you notice skipped turns I'd appreiciate the heads up.. (Dame slow bot :) I guess I should do everyOne a favour and learn kd trees. Any 'simple' code examples of them implemented to start learning from ??<br />
<br />
[http://donar.umiacs.umd.edu/quadtree/index.html This] has a nice applet on k-d tree and quadtree. Try looking at Bucket PR k-d tree as it is faster than original kd-tree, also it has been used by this community =) Simple implementation... [[Diamond/Code|Voidious' kd-tree]] probably most readable 'simple' kd-tree code on this wiki but the [[oldwiki:KdTree/BucketPRKdTree|Simonton's tree]] is probably more easier to understand, but with confusing code style. This tree was where I (and probably Voidious) used to learn from. Don't try Rednaxela's kd-tree if you are looking at anything simple =) PS. Could you please at least write about yourself and your robot? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 12:59, 8 September 2009 (UT--[[User:Voidious|Voidious]] 19:56, 8 September 2009 (UTC)C)<br />
<br />
Those applets are nice, but what I found most helpful when I was first learning was [http://www.cs.cmu.edu/~awm/animations/kdtree/ this]. Also, pfft, [http://www.robowiki.net/w/index.php?title=User:Rednaxela/kD-Tree&oldid=11074 this older revision] of my tree is in my opinion the very most readable one out there Nat. PS, I agre with Nat, it would be nice if you make a page for your bot some time :) --[[User:Rednaxela|Rednaxela]] 13:22, 8 September 2009 (UTC)<br />
<br />
For what it's worth, the only thing I used for reference was the [[wikipedia:kd-tree|Wikipedia entry]]. =) Keep in mind that the tree won't magically solve your skipped turn issues. In fact, optimizing a brute force method might give better performance. Where the trees excel are in guns in longer 1v1 matches - you only get ~5,000 gun scans of each enemy in a 35-round Melee match (unless you start creating lots of extra gun waves, like I did recently...), and far less on the [[Wave Surfing]] side. Then again, Rednaxela's tree is ''really'' fast. Anyway, good luck. And yes, tell us about [[DemonicRage]], already. =) --[[User:Voidious|Voidious]] 13:40, 8 September 2009 (UTC)<br />
<br />
: My tests seemed to show most trees beating or doing just as well as your brute force one code when it was real data in use. Randomized data points lean heavily in favour of the brute force method actually. Still though, indeed the fewer scans of the melee case make the brute force approach not so bad really. :) --[[User:Rednaxela|Rednaxela]] 14:03, 8 September 2009 (UTC)<br />
<br />
I've annoyed at least one ex gf with my antiSocial robocoding obsession.. :) How do you create a page for a bot? --[[User:Jlm0924|Jlm0924]] 19:50, 8 September 2009 (UTC)<br />
<br />
: There are several ways, but the simplest: click on that red link I put in my last comment; search for the page title you want, then click "create this page"; or just go to robowiki.net?Page_Name (with _ for spaces in the url) and click "edit this page". You can look at other bot pages for examples on how to lay stuff out. --[[User:Voidious|Voidious]] 19:56, 8 September 2009 (UTC)<br />
<br />
thx Void, --[[User:Jlm0924|Jlm0924]] 00:24, 9 September 2009 (UTC)<br />
<br />
== DemonOnFire ==<br />
<br />
If anyOne could temperarily post the source to HawkOnFire ( here is good) I would appreciate it . The repository seems to currently be down..-[[User:Jlm0924|Jlm0924]] 15:19, 24 November 2009 (UTC)<br />
<br />
: [[File:Rz.HawkOnFire_0.1P.jar]] Here you go. --[[User:Positive|Positive]] 15:51, 24 November 2009 (UTC)<br />
<br />
: (edit conflict) Well, I know Positive has posted it, but as I have already prepared it: http://pastebin.ca/1685597 --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:59, 24 November 2009 (UTC)<br />
<br />
: Thanks Guys !! -[[User:Jlm0924|Jlm0924]] 16:12, 24 November 2009 (UTC)<br />
<br />
: DemonicRage 2.2d with HawkOnFires' targeting (maintains DRs movement and radar only) is availible, just waiting for Repository to be up to post.<br />
:I ran a few 100 round battles with 3 HawkOnFires, 2 Portia126fHoF, 2 DemonicRage2.2dHoF, 1 portia 126d, 1 DemonicRage2.2d, and 1 aleph. Portia126fHoF consistently beat HawkOnFire DR2.2dHoF and even aleph ! :) <br />
: DR2.2HoF beat the HawkOnFire<br />
:While Portia's score/survival is much higher than dr's...To my Surprise; The scores seem to indicate that DR's gun is on par with portias' :O I'll have to make a DemonHawk :P and see :)-[[User:Jlm0924|Jlm0924]] 19:03, 24 November 2009 (UTC)<br />
: Well, one thing that may be worth noting, is I think that the gun is Portia's weak point by a notable margin. I don't have time to release something like GlacierHoF right now, but this weekend I might be able to do that. --[[User:Rednaxela|Rednaxela]] 00:06, 25 November 2009 (UTC)<br />
:: Yes that's true. Portia's gun is still relatively weak. I've tried to improve it a lot, but no luck so far. At least its 5% better APSwise that HOT. :) --[[User:Positive|Positive]] 00:19, 25 November 2009 (UTC)<br />
<br />
<br />
== Repository ==<br />
<br />
Still down ... anyOne know why?? It's not just my end I hope :) -[[User:Jlm0924|Jlm0924]] 00:23, 28 November 2009 (UTC)<br />
<br />
: I think everyone has had troubles with it. I suggest you open a google site to store your bots, that works for me. :) --[[User:Positive|Positive]] 21:10, 28 November 2009 (UTC)<br />
<br />
== rumble server error?==<br />
<br />
I noticed I have two bot's in the rumble that haven't been removed yet.. The server message is: 'the feature is temporary disabled.'<br />
is this on purpose, or is there an error somewhere? -[[User:Jlm0924|Jlm0924]]<br />
<br />
Probably because of the massive melee rescoring happening in the rumble (to clear out a huge number of bad scores) right now that will take a long while... Also, it's probably a bad idea to make any new melee releases during this time period I'd think, since their results won't be reliable and the system is already very stressed... --[[User:Rednaxela|Rednaxela]] 00:26, 7 December 2009 (UTC)<br />
<br />
ok, cool -[[User:Jlm0924|Jlm0924]] 00:51, 7 December 2009 (UTC)<br />
<br />
Surprisingly the stress is lower than I expected and the melee rankings appear to be recovering. But right now only my client is doing removals so that's why you're getting that message. And remember that bots can only be removed until at least 4hrs after their last battle, and they will normally keep getting battles until they reach full pairings. --[[User:Darkcanuck|Darkcanuck]] 07:32, 7 December 2009 (UTC)<br />
<br />
== Those colored bars ==<br />
I've been meaning to ask: What are the blue , red, yellow colored bars on a bots tab represent ?? :) the lasted change in robocode also say it display's the memory a bot uses in the main title bar.. where ?? Thx :) -[[User:Jlm0924|Jlm0924]]<br />
<br />
In the titlebar of the program, saying something like "Robocode: Turn 7, Round 1 of 1000 (paused), Used mem: 23 of 493MB" About the bars, the green/yellow/red one represents the relative health of the bots, and the blue one represents the relative score for the round. --[[User:Rednaxela|Rednaxela]] 19:54, 11 January 2010 (UTC)<br />
<br />
:Thx Red, The new mem feature isn't there for me, I'll try a fresh install.<br />
<br />
== Rednaxela's kd Tree ==<br />
<br />
Hey Rednaxel, I've been trying to implement your tree. Was hoping for some guidance. I started by looking into Glacier and ported in your " utils.newTree.kdTree". I insert data into the tree with <br />
:::: scanned.kdTree.addPoint( loc , scanData); <br />
:then later-on I retrieve 100 similar like so <br />
:::: closestMatchingScanData.addAll(e.kdTree.nearestNeighbor( loc , 100, true)); " <br />
:which seems to work fine so far... I then later try to use the "scanData" that was inserted into the tree (within a loop) like so.<br />
:::: KdTree.Entry entry = closestMatchingScanData.get(i); <br />
:::: ScanData sd = (ScanData)entry.value; <br />
:There is the problem. The "ScanData sd" has a linked list that I would use to then Play-It-Forward. Am I wrong in thinking how the tree returns the data? or just a bad casting/code? Thanks for any help .. -[[User:Jlm0924|Jlm0924]]<br />
<br />
<br />
What is your problem? Your code looks fine. Just remember that the <code>nearestNeighbor</code> return in ''reverse'' order, so the entry with least distance come last. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 12:12, 26 January 2010 (UTC)<br />
<br />
The code looks fine to me, except that casting isn't necessary since it uses generics. Use KdTree.Entry<ScanData> and remove that cast basically. --[[User:Rednaxela|Rednaxela]] 13:42, 26 January 2010 (UTC)<br />
<br />
== DemonicRage performance in Robocode 1.7 ==<br />
<br />
On my localhost rumble server I'm using for testing Robocode 1.7 for issues, I've found that DemonicRage (both 2.5d and 2.5da) are under-performing by a huge margin in Robocode 1.7. As in: Near 100th place instead of being in the top 10. When I test it, I can't see anything obviously wrong (exceptions, skipped turns, etc) like happens with other bots that break in Robocode 1.7. To make things more puzzling still, it seems to score well when I put it in battle with a field of 9x HawkOnFire, so not sure. It may be related to [http://sourceforge.net/tracker/?func=detail&aid=2976754&group_id=37202&atid=419486 this] issue (which I don't quite understand the full implications of) but I don't know. --[[User:Rednaxela|Rednaxela]] 03:52, 26 March 2010 (UTC)<br />
<br />
I'm not at home right now (thou I did just roll back demonic to version 2.4 in the rumble before reading this) but I am very sure I use 1.7.1 for testing at home. I have not tried the new beta. Demonic 2.5x has been pushing the cpu limit with the dc gun that targets-all & PIF, without the speed of your kdtree yet. It is probably skipping turns. It doesn't yet limit the scans size, so It should start skipping at 40-50 rounds or so. (or with more bots.) Also... someone mentioned awhile back that robocode was not completely clearing static variables (mem) between battles... That is still true for me. I assumed that was never fixed in 1.7.1. and haven't checked lately to make sure it's not demonic. my java is limited to (buggy) bots :) but let me know if I can help.....-[[User:Jlm0924|Jlm0924]] 08:57, 26 March 2010 (UTC)<br />
<br />
As a quick note, DemonicRage 2.4a is not subject to the issues in Robocode 1.7 that DemonicRage 2.5 was. I'm currently suspecting it was the same cause as what was affecting Garm and DeltaSquad with that bug report I linked. --[[User:Rednaxela|Rednaxela]] 05:03, 28 March 2010 (UTC)<br />
<br />
== Robocode 1.7.6 Bug Report ==<br />
Can someOne with a sourceforge login report a bug ? When you use draw rectangles the second X,Y's are reversed.. The actualy rectangle is ok, only the draw is wrong.<br />
eg: This rectangle will display tall and skinney -[[User:Jlm0924|Jlm0924]] 02:38, 11 May 2010 (UTC)<br />
<syntaxhighlight><br />
<br />
Rectangle2D.Double r = new Rectangle2D.Double(0,0,100,10);<br />
Graphics2D g = getGraphics();<br />
g.setColor(Color.white);<br />
g.draw(r);<br />
<br />
<br />
<br />
</syntaxhighlight><br />
<br />
<br />
Actually Robocode is known to have problem with Graphics2D.draw/fill(Shape). There is problem with Arc2D.Double too, actually. I'll report this anyway. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 03:06, 11 May 2010 (UTC)<br />
<br />
I have now fixed this problem. There sure was a bug with Rectangle2D and Arc2D. I have made a version of Robocode containing this fix, which you could try out to see if the bug has been fixed properly. Download it from [http://robocode.sourceforge.net/files/robocode-1.7.2.0-Beta-3-setup-20100516.jar here]. --[[User:FlemmingLarsen|Fnl]] 20:48, 16 May 2010 (UTC)<br />
:sweet, thx guys -[[User:Jlm0924|Jlm0924]] 15:03, 17 May 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:J_Litewski&diff=16917User talk:J Litewski2010-07-01T08:42:16Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{| width="100%" style="background: white; " <br />
| valign="top" width="60%" style="border: 2px solid #000; padding: .5em 1em; -moz-border-radius: 1em; -webkit-border-radius: 1em" |<br />
'''Welcome!'''<br />
<br />
Hello, J Litewski, and welcome to RoboWiki! This place contain a wealth information about [[Robocode]], from [[Head-On Targeting|basic]] to more [[Wave Surfing|advanced]]. I hope you enjoy creating a robot and being a robocoder!<br />
<br />
If you are posting a comment on this wiki, please [[wikipedia:Wikipedia:Signatures|sign]] your messages using four tildes (<nowiki>--~~~~</nowiki>); this will automatically insert your username and the date. If you are not familiar with MediaWiki, these links might help you out:<br />
* [[wikipedia:How to edit|How to edit]] on [[wikipedia:|Wikipedia]], [[metawikipedia:Cheatsheet|Cheatsheet]] and [[metawikipedia:File:MediaWikiRefCard.pdf|Reference Card]] of MediaWiki on the [[metawikipedia:|Meta Wiki]].<br />
* [[RoboWiki:ReadMe|Readme]] page.<br />
If you need [[Help:Help|help]], check out the [[Robocode/FAQ|frequently asked questions]] or ask it on this page. Again, welcome!<br />
<br />
—— [[User:Nat|Nat]] 23:26, 14 May 2009 (UTC) <br />
|}<br />
<br />
Hey, welcome! Good luck with your bots, and feel free to post any questions you have. Also, by the way, info about you should technically go on [[User:J Litewski|your user page]], while this page would be for posting questions / comments to you (or about your page, I guess). --[[User:Voidious|Voidious]] 17:47, 14 May 2009 (UTC)<br />
<br />
Hi! Write more about yourself to your userpage, I'd be interested in it. And don't afraid of submitting your bots to RoboRumble. :) (it's very motivating and educational)--[[User:Robar|HUNRobar]] 18:02, 14 May 2009 (UTC)<br />
<br />
== Wiki issues ==<br />
<br />
Hi! Please mark an edit as minor edit when you just correct grammar or adding links. And please write edit summary when edit, it help other robocoder to know what is changed briefly. Mroe information about this can be found on Wikipedia. Thanks! &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 06:35, 18 May 2009 (UTC)<br />
<br />
Hi Litewski. In your recent contributions to [[Bin Smoothing]] page and some other pages, you use [[:Category:CamelCase redirect|CamelCase]] words in some links text, such as [[GuessFactorTargeting]], which is, by the standard of this new wiki, deprecated. The correct name with proper spaces is defined. The old CamelCase page still work as a redirect page, but it is better to link to the exact page instead of redirect page.<br />
<br />
Another issue: Standard heading level of the wiki is start at 2, threfore you should use level 2 heading <nowiki>(== Heading ==)</nowiki> instead of level 1 heading, which is use by page title itself. In some od your contributions to the page [[GITS]] and its subpages, you have the level 1 heading which have the same text as page title, which is not needed and make the table of content look funny. Thank you! &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 03:00, 9 June 2009 (UTC)<br />
<br />
:sorry for the problems, still kinda new to this. --[[User:J Litewski|Jacob Litewski]] 03:12, 9 June 2009 (UTC)<br />
<br />
:: No problem. The main rule of wiki(pedia) is "Be bold". =) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 03:50, 9 June 2009 (UTC)<br />
<br />
== Handle ==<br />
<br />
Hay, why "HACKhalo2"? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:40, 21 May 2009 (UTC)<br />
<br />
"HACKhalo2" is my XBL handle way back when I had Xbox Live. I just used it from then on because I liked it. It's also because I use to hack Halo on the PC and create custom CD's that booted like the original. --[[User:J Litewski|HACKhalo2]] 16:41, 21 May 2009 (UTC)<br />
<br />
== Talk about GravityWave ==<br />
<br />
As some of you guys know, GravityWave, my newest Sandbox for [[GITS]], is a combination of Wave Surfing and Anti-Gravity Movements. It focuses mainly on Wave Surfing, using [[User:Voidious|Voidious']] [[BasicSurfer]] as a base and building off of that. It'll use a modified Anti-Grav Movement for enhanced wall smoothing and enemy avoidance. Anyways, I need help working on some of GravityWave's features, since I'm new to this advanced stuff. Here is some things that I would like to add in sooner or later (with more to come):<br />
* Segmentation (always a plus)<br />
* Better Algorithms<br />
* Enemy GunHeat Class (to weed out non-bullet waves) (finished)<br />
* And more stuff I can't think of<br />
I did tweak the base a little bit (changed the radar, added in some more debug graphics, minor things), but other than that, nothing to drastic yet. So, go wild with your comments! --[[User:J Litewski|Jacob Litewski]] 03:05, 5 June 2009 (UTC)<br />
<br />
Gunheat code (rapid-cooked now, hasn't test yet)<br />
<syntaxhighlight><br />
class GunheatTracker {<br />
private double gunHeat;<br />
private final double coolingRate;<br />
<br />
public GunheatTracker(AdvancedRobot r) {<br />
gunHeat = r.getGunHeat(); // initialize gunheat to 3<br />
coolingRate = r.getGunCoolingRate();<br />
}<br />
<br />
public double eachTick() {<br />
gunHeat -= coolingRate;<br />
gunHeat = Math.max(gunHeat, 0);<br />
}<br />
<br />
public double enemyFire(double power) {<br />
if (!isFirable()) <br />
throws new IllegelStateException();<br />
gunHeat += 1d + power / 5d; // according to Robocode rules.<br />
}<br />
<br />
public boolean isFirable() {<br />
return gunHeat <= 0.000001;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
You must detect energy drop yourself. I will write more when I come home. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 09:37, 5 June 2009 (UTC)<br />
<br />
OK, at home now. I don't think you need to detect enemy gunheat unless you are in melee (which need a lot of other components to make the class above work), or want the extra 2 ticks (as in [[DrussGT]] and [[RougeDC]]) to surf. Otherwise, it is much more easier to detect the thing by energy drop (you will need to do that if you want the class above work too) and adjusted the energy on the events (onHitRobot, onHitByBullet and onBulletHit). Anyway, this only work for one-on-one, in melee, you need to interpolate (a lot), do some statistical recording to predict the whole battle (two months work, don't seem to make much progress). &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:33, 5 June 2009 (UTC)<br />
<br />
Well, I just want a simplistic GunHeat class to weed out non-bullet waves that GravityWave seems to surf, mostly into bullets. It's more or less ''if enemy fired with x power, don't calculate waves for x ticks'' type thing. --[[User:J Litewski|Jacob Litewski]] 15:55, 5 June 2009 (UTC)<br />
<br />
I built an Utilities class that uses a very simplistic method to track of stuff. Currently, with the help of some quick hacks, it helps weed out non-bullet waves. I'm running a 500 round test now to see if it improved anything. --[[User:J Litewski|Jacob Litewski]] 00:54, 6 June 2009 (UTC)<br />
<br />
== 2D Segmentation Smoother ==<br />
<br />
Ok, this woke me up out of the deepest sleep I had in years. I was trying to figure out the best way to log hits with [[GravityWave]]'s new segmented array. I thought the original logHit function was doing it's job. Well, it hit me, it saw storing the data like a 1D array, not like a 2D segmented array. For instance, data on <code>test[8][8]</code> (which is a 9x9 array) is laid out like this:<br />
<pre><br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
</pre><br />
When it was storing the data, it would store it like this (if hit on the 2D GuessFactor of 0 (5x5)):<br />
<pre><br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 1 2 3 4 3 2 1 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
</pre><br />
Instead, it should be storing it like this:<br />
<pre><br />
0 0 0 0 0 0 0 0 0<br />
0 0 0 0 1 0 0 0 0<br />
0 0 0 1 2 1 0 0 0<br />
0 0 1 2 3 2 1 0 0<br />
0 1 2 3 4 3 2 1 0<br />
0 0 1 2 3 2 1 0 0<br />
0 0 0 1 2 1 0 0 0<br />
0 0 0 0 1 0 0 0 0<br />
0 0 0 0 0 0 0 0 0<br />
</pre><br />
Note that it will not be this dramatic of a spike. But if this works the way I think it will, it will be a 2D BIN Smoother, or 2D Segmentation Smoother as I call it, since it does smooth the BINS biased on where the hit took placed on the Segment. This should make it easier to go from one segment to the next without to much fuss (like I have been having) and optimize the danger checker. Here is the code:<br />
<syntaxhighlight><br />
public void logHit(EnemyWave ew, Point2D.Double targetLocation, int segment) {<br />
int index = getFactorIndex(ew, targetLocation);<br />
<br />
//New 2D Segmentation smoother<br />
for (int x = 0; x < 13; x++) {<br />
for(int y = 0; y < BINS; y++) {<br />
_surfStats2[x][y] += (Math.pow(segment - x, 2) + 1) / (Math.pow(index - y, 2) + 1);<br />
}<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
Tell me what you think please :) --[[User:J Litewski|Jacob Litewski]] 03:56, 12 June 2009 (UTC)<br />
<br />
It's been done by a few people before and isn't a bad idea. However, the two things that should be kept in mind: '''1)''' You generally want less smoothing across segments than across bits but doesn't hurt to experiment, and '''2)''' This will get SLOW when/if you start having upwards of 5 different segmention axis like many/most high ranking bots have. Additionally, here's another thing you can try:<br />
<br />
if you're writing and you're halfway between segments, write half in each like this:<br />
<pre><br />
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0<br />
0.0 0.5 1.0 1.5 2.0 1.5 1.0 0.5 0.0<br />
0.0 0.5 1.0 1.5 2.0 1.5 1.0 0.5 0.0<br />
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0<br />
</pre><br />
and if you're closer to one side than another, weight your insertion towards that side. Then when reading, you do a similar thing, like if you're halfway between segments looking like<br />
<pre><br />
0.0 0.0 0.0 0.5 1.0 1.5 2.0 1.5 1.0<br />
1.0 1.5 2.0 1.5 1.0 0.5 0.0 0.5 0.0<br />
</pre><br />
you will shoot by taking the highest point of<br />
<pre><br />
1.0 1.5 2.0 2.0 2.0 2.0 2.0 1.5 1.0<br />
</pre><br />
Which is a technique that massively boosts score in [[Rednaxela/SaphireEdge]]... though... nobody other than me has implemented it to my knowledge... as it does get a little complicated when you get into a large number of segment dimensions... :) --[[User:Rednaxela|Rednaxela]] 04:13, 12 June 2009 (UTC)<br />
<br />
I haven't even thought of shooting yet... heh<br />
Anyways, after testing it, I noticed my score drop massively. so I looked into the fight and saw my problem: I didn't have 'levels' of arrays for bullet power. So, I'm testing my new(er) Leveled 2D Segmentation Smoothing, Leveled with 4 levels biased off of bullet power and segmented with a 2D array biased off of distance and BINS respectively ( or [power][distance][BINS]). Hopefully this will work better and learn faster. --[[User:J Litewski|Jacob Litewski]] 04:29, 12 June 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Hubris&diff=16916User talk:Hubris2010-07-01T08:42:15Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Hey Martin (I assume?), I get a permission error when I try to download Hubris. ("Sorry, you are not authorized to view this page.") I know sometimes you've posted bots that you only wanted running from your clients, so I thought nothing of it at first, but now that I see it's gotten no battles, I thought I should let you know... Nice to see you posting a new version, good luck, --[[User:Voidious|Voidious]] 14:05, 7 May 2009 (UTC)<br />
<br />
Hm that's odd. I'll have to provide it from another location I guess. Yeah it's me .. the 'email me my password' feature failed so I made a new account. --[[User:Hubris|Hubris]]<br />
*It should work now. The dumb file management interface for Comcast has a public / private flag that defaults to private. New since the last time I've uploaded anything to Comcast.<br />
<br />
He he, I start to wonder why many old robocoders start to remember the Robocode again. I'm going to post the {{[[Template:Welcome|Welcome]]}} to you but luckily I see the package name first (which make me know it is you). Maybe asking [[User:Voidious|Voidious]] to recover your password is posible? (@[[User:Voidious|Voidious]], script is at maintenance/changepassword.php) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:03, 7 May 2009 (UTC)<br />
*Now that I've gotten into work, where the password is remembered, I am reminded by its length what it is, so no need to get the email thingy working on my account. As far as what makes me remember Robocode, I have kept my source code on a USB drive since .. well since my first, a 256meg deal that I just retired in favor of a 4gig. The old one worked just fine but I grabbed the bigger one for a web site relocation that I ended up not doing, but I digress. Lots of stuff I still mean to program, and lots that I mean to program more elegantly. For example, I had a 'find the points of intersection of two circles' that worked but was really large and probably slow. I replaced it with a few lines of code that gives me what I really wanted, the angular distance.<br />
<br />
<syntaxhighlight>public BearingOffsetRange getRangeOfIntersection( Circle other ) {<br />
BearingOffsetRange bearingOffsetRange = null;<br />
double d = this.getDistance( other ).distance();<br />
double r2 = other.radius();<br />
if( d != 0.0 && Constraints.isInRange( d - r2, this.r, d + r2 ) ) {<br />
double x = ( this.rSquared - r2 * r2 + d * d ) / ( d + d );<br />
double y = Math.sqrt( this.rSquared - x * x );<br />
double theta = Math.atan( y / x );<br />
bearingOffsetRange = new BearingOffsetRange( -theta, theta );<br />
}<br />
return bearingOffsetRange;<br />
}</syntaxhighlight><br />
<br />
Stuff like that. You can see it at work as my wave crashes over my opponent (whom I represent as a circle rather than a box), assuming you enable painting and press 'w' to tell Hubris to paint its waves. I use it to measure the range of angles that would have scored a hit.<br />
<br />
I've still got my white whales that I can't let go, such as bullet shielding.</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Chase-san&diff=16915User talk:Chase-san2010-07-01T08:42:02Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Just to confirmed, you come from USA, right? But why your rumble flag is Japan? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 10:51, 12 April 2009 (UTC)<br />
<br />
If you read the country flags page on the old wiki, you'll find<br />
<pre>I be changing of my mind on my flag, and at the same time, uploaded<br />
a new GIF. I would perfer the Japanese flag, as they need someone defending<br />
them in the top 100. The old one looks like a badly squished bright red<br />
dot, where as the japanese one is a little darker. So this flag for the<br />
'chase' package please. --Chase-san</pre><br />
So Chase-san is going under the japanese flag just because he wants to essentially. --[[User:Rednaxela|Rednaxela]] 14:50, 12 April 2009 (UTC)<br />
* Thanks, now I understand. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:53, 12 April 2009 (UTC)<br />
** Other people have done this aswell in robocode. In the end the flags are jsut there for looks, you could ahve a fake flag if you wanted (I suppose). --[[User:Chase-san|Chase]] 23:21, 22 April 2009 (UTC)<br />
<br />
----<br />
<br />
Hey Chase, where can I find your EvilDrone? I'd like to see it, not in action, but the code. And can you tell me which version of robocode that you are allowed to do that thing? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 05:13, 23 April 2009 (UTC)<br />
<br />
:Well that would be a bit hard, you would need a very old version of robocode to even view it. I will search around but I think the code is long since gone. Basically all it did was something like robocode.battle.bullets.add(new robocode.bulletpeer()), assigned it to itself and placed it projected off enemy location (gained from reading the enemy location from the internal class) at an PI/50 intervals (ergo PI*2/100). and set the velocity to fly towards the enemy. If you wanna see something like ti disable the security manager and use the new method of peer management that Robocode uses. You should be able to do something like that with that system. Just don't try making your robot teleport, robocode didn't like it then I doubt it likes it now. --[[User:Chase-san|Chase]] 06:23, 23 April 2009 (UTC)<br />
<br />
::ACtually I found some really old versions of two of my hackbots, they are on my server. www.csdgn.org/robo This EvilDrone isn't the really amazing one I describe, but it still always wins. --[[User:Chase-san|Chase]] 06:28, 23 April 2009 (UTC)<br />
<br />
::: Thanks! Ahhh. It's 1.2.1 Beta (from your JAR) which is un-downloadable :-( &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:37, 23 April 2009 (UTC)<br />
<br />
== Redirects ==<br />
<br />
It's pretty funny to watch the [[Special:Recentchanges|recent changes page]] while we make all these redirects. --[[User:AaronR|AaronR]] 20:19, 12 November 2007 (UTC)<br />
<br />
Hehe, yah, it was, it was like a Redirect war. --[[User:Chase-san|Chase-san]] 20:21, 12 November 2007 (UTC)<br />
<br />
== Okay, maybe not ==<br />
<br />
Maybe I canot jump right back into robocode again. I have been working on a great deal of 3D stuff lately I am not sure if I can think in 2D anymore. I actually created a linear targeting gun that works in 3 Dimensions, and the like. But only as experiments. I will look into getting back into things now that class is lettting out for the summer. But I know I probably was not the nicest person back then, but I hope I will be welcomed back if that day comes. --[[User:Chase-san|Chase]] 09:54, 13 May 2009 (UTC)<br />
<br />
You will be welcomed if you come back. Robocode community is very quiet lately. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:21, 13 May 2009 (UTC)<br />
<br />
I didn't know you then, so I have no reason to not welcome you ;-). --[[User:Zyx|zyx]] 13:08, 13 May 2009 (UTC)<br />
<br />
When were you not nice? Welcome back. And if two dimensions isn't enough for you, you can use as many as you want if you go back to the [[Dynamic Clustering|DC]] and [[Kd-Tree]] work. =) --[[User:Voidious|Voidious]] 14:27, 13 May 2009 (UTC)<br />
: I did have a Bucket KD-Tree with a working range search to speed up my Pytko (which I never installed). I think I was working to get a honest working tree search in, but the bucket method of the tree pretty much made up for almost any added precision that would otherwise be gained by searching back along the path. --[[Chase-san]]<br />
<br />
== Robofight ==<br />
<br />
Well, Robocode did implement a lot of thing, why don't you build it on top of Robocode? Or as a plug-in for Robocode? You know, there is an incomplete Battleview3D plug-in in Robocode's SCM trunk, you might want to examine it. Your physics looks good, btw. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:39, 18 July 2009 (UTC)<br />
<br />
: Well this is a bit beyond the scope of what Robocode can really hope to do I think.<br />
: I have been writing mostly C/C++ since July, and I have done some opengl. If I can use a OpenGL wrapper in java I might be able to use that for this. However despite this still somewhat being on my eventual 'todo' list I have other more pressing things right now I need to work on. (Like College work! :P)<br />
: But to me, one of the really neat thing about this is the possibility for custom models. Of course there would be option to scale them to a certain 'area' if to large and would probably be in the format of an average obj file. I have worked with those before, they are very simple.<br />
: Which would make the battles very interesting to watch. Initially it will probably only use wireframe models, to avoid having to texture map. (and it looks cool)<br />
: But until I actually do something this is all just speculation. <br />
: --[[User:Chase-san|Chase]] 10:02, 6 November 2009 (UTC)<br />
<br />
:: Okay, since I have done opengl before I decided to try out JOGL, and amazingly its almost identical to the honest to go C opengl in the way of commands. So that makes this easy enough I can make this nice 3D demo for everyone. I didn't do any texture mapping (making a texture takes to long, imho), but the rest of it is there. I have two ships flying orbits around the center. This is just GL trickery right now and not example of actually programmed robots, but I wanted to show I could do it now. Because before I had absolutely no clue on the 3D.<br />
::I also would like opinions on the size of the ship to the size of the field there. In retrospect I should of just added an additional unmoving ship in the center so its easier to peek at the model. But if any of you have any 3D modeling programs you can poke the model I have in the zip. Mine is about 20 minutes with some cheap smoothing done on it.<br />
::I will add a version of the physics engine here soon, and a basic programming interface for testing some things. But needless to say, debugging graphics on this would look awesome (and maybe also really hard to see).<br />
:: [http://www.csdgn.org/files/Roboflight3DTest.zip Download 3D Demo]<br />
:: Uhm, oh the file is a bit big (1.7 mb), because I tried to pack the dynamic libraries for all the relevant systems (Windows, Linux, Mac OS X).<br />
::--[[User:Chase-san|Chase]] 15:30, 7 November 2009 (UTC)<br />
<br />
::: You make my head spin with that. But I think Robot only driving on the ground, unless you make an aeroplane robot, which should be really hard to write (and control from the API) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:49, 7 November 2009 (UTC)<br />
:: Wow! Cool! I personally think the field should be bigger, especially if the bots are going to be able to move at the speed they do in your simulation. Similar to robocode, I think it should take at least 100 ticks to fly from corner to the other, and half that for bullets to travel from one side to the other. Another thought: since this is in 3D, we need to give the bullets some thickness or they won't be able to intercept. They can't just be modelled by a straight line anymore. --[[User:Skilgannon|Skilgannon]] 21:34, 7 November 2009 (UTC)<br />
::: Well I can completely change their speed, size, and the like. The field currently is 'technically' only 2x2x2 (-1 to 1) in size, and those models are very small, but to the actual robot it could be anything from 2x2x2 to 1000x1000x1000, dynamically resizing the robots as needed. But okay. --[[User:Chase-san|Chase]] 04:41, 8 November 2009 (UTC)<br />
<br />
<br />
Obviously this has not received my full attention! However I would like to pose a question to all of you.<br />
<br />
http://www.csdgn.org/files/images/three_axes.gif<br />
<br />
I was wondering what the relative limits on the axis should be. Since the hit box on a ship will be non static, meaning you have a smaller profile when your side is facing then your top, I was considering restricting the ability to turn on the yaw the most and give the roll the most freedom, putting pitch somewhere in between. Considering the majority of your thrust will be along the x axis (forward and back, but with limited thrusting ability along the z and y). I was wondering if this seemed fair (since a high yaw would allow you to have a low hit box and be able to turn quickly when circling your enemy surfer style) --[[User:Chase-san|Chase]] 03:23, 22 April 2010 (UTC)<br />
<br />
: I think prioritizing limits that way makes sense personally. On second thought though, I wonder if making pitch and yaw the same for symmetry would make sense? One thing to consider is that one could always bank to the side as to allow pitch and yaw to be combined. --[[User:Rednaxela|Rednaxela]] 15:21, 23 April 2010 (UTC)<br />
<br />
:: If it is a plane, then I think pitch is easier to do than yaw. For pitch, you just pull the controller. For yaw, well, hard to control I believe =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:30, 23 April 2010 (UTC)<br />
<br />
Oh, and in other news on this, aside from the few of the local to global coordinate and thrust translations I need to do yet, I can internal code mapping to display code. Roll, yaw, pitch all work. Velocity works, I have to apply the rotation to the thrust still (since thrust is local) and then apply it to the velocity. Once I get the fluid dynamics reapplied, it should be ready for some basic programming in the flight department. --[[User:Chase-san|Chase]] 04:13, 22 April 2010 (UTC)<br />
<br />
: On that note, I have a core test for you. Basically this bot is a somewhat inefficient 3D version of walls. This is not 3D trickery, this is the actual core doing its job. Physics (if you can call a simple drag physics), rotation, thrust, etc. They all work. It uses a system similar to the current robocode for setting it's turn, or at least the last version of it I looked at. The field it is on is HUGE, 2000x2000x2000, it is bound the the display so that is the reason if it looks like it is going insanely fast and turning on a dime (I will fix this at some point by giving the engine its own thread). [http://www.csdgn.org/files/RoboflightCoreTest.zip Core Test 0] To be honest I am a bit annoyed with myself, since the last time I worked on this I found it hard, now I don't, not really. --[[User:Chase-san|Chase]] 06:55, 22 April 2010 (UTC)<br />
<br />
http://www.csdgn.org/files/images/roboflight.png<br />
<br />
Alright, now I have something really done. Alright, I rewrote the graphics and engine. Two really simple bots with really simple behavior. Loopy does loops, WallyX is like the previous walls, except he will change which set of walls he flies on randomly when at the midpoint, meaning he will cover all 6 (eventually).<br />
<br />
I have detached the engine from the screen rendering, the engine is fixed at 20 fps for the moment, but the display is much higher. I added the ability to rotate the display manually (with momentum) and shift it up and down and even zoom in on it (mouse wheel). The yellow line shows thier direction of movement (since it is not always along thier x axis during turns). Still would like to hear your opinion on the turn radius of the robots. Oh and here is the demo so you can try it yourself, I decided to split the libraries into their own archive (so I don't ahve to upload them again).<br />
[http://www.csdgn.org/files/jogl_lib.zip JOGL Libraries]<br />
[http://www.csdgn.org/files/RoboflightCore2.zip Roboflight Core Test 2]<br />
<br />
--[[User:Chase-san|Chase]] 21:55, 22 April 2010 (UTC)<br />
<br />
: As a side note I have in the past already determined a way to do linear non-iterative targeting in 3D. It was done by calculating the point at which the two objects would meet. It looks a little something like this. --[[User:Chase-san|Chase]] 00:45, 23 April 2010 (UTC)<br />
<syntaxhighlight>/** Returns a vector that you should aim at, give both objects travel at a constant rate, in a linear direction */<br />
Vector3d Intercept(Vector3d cPos, Vector3d tPos, double cVel, Vector3d tVel) {<br />
Vector3d rPos = new Vector3d(tPos);<br />
Vector3d tVel2 = new Vector3d(tVel);<br />
rPos.sub(tPos);<br />
double b = rPos.dot(tVel);<br />
double a = cVel*cVel - tVel.dot(tVel);<br />
tVel2.scale(b + Math.sqrt(b*b + a * (rPos.dot(rPos))) / a);<br />
rPos = new Vector3d(tPos);<br />
rPos.add(tVel2);<br />
return rPos;<br />
}</syntaxhighlight><br />
<br />
:: Neat. Now I can't help but ponder non-iterative circular targeting in 3d... that gets trickier I'd say... hm --[[User:Rednaxela|Rednaxela]] 15:21, 23 April 2010 (UTC)<br />
<br />
Cool! If the robot is a plane (thus 'flight'), I believe pitch should be a bit lower (base on source code in code 2 anyway). Your control is a bit interesting -- I wonder how can I thrust from the z axis. If so, I think your should limit the thrust on y and z axis to be s lot lover than the x axis. But the probably on your todos list already. --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:30, 23 April 2010 (UTC)<br />
<br />
: Yes, actualy, I plan to limit the thrust on the X and Y axis to be at most 0.1 or 0.2, where as the x axis can go all the way to 1.0. Depending on how I decide to do the movement dynamics, the inverse of x might be at most -0.2 or all the way to -1.0. Depending on if I want a game like robocode, where backwards can be the same magnitude as forward. I will also limit the total maximum magnitude of the thrust to 1.0, if over 1.0, so 1.0 on x and 0.2 on Y would give it a total magnitude of sqrt(1.0*1.0 + 0.2*0.2), or a bit over 1, so I would normalize it to 1. Meaning both thrust vectors would be reduced, but if under this, no normalization will occur.<br />
: As for the pitch and yaw. I wanted to give pitch a greater turn radius so that robots will expose a greater hitbox to the enemy to make use of this better turning ability, if they are orbiting the enemy in standard robocode fashion. If i was really evil, I would get rid of Yaw altogether. (thus requiring robots to roll and pitch to make a turn) --[[User:Chase-san|Chase]] 17:34, 23 April 2010 (UTC)<br />
<br />
For bullet collision, and bullet missile collision, I will probably still use a line, but use a [http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm#dist3D_Segment_to_Segment() shortest distance between two line segments] algorithm to determine if they had collided. Might have to do it in substeps, and only if the two bullets line paths distances are less than a certain amount (to avoid unneeded computationally expensive checks for bullets nowhere near each other). Robot/Missile or Robot/Bullet collision will probably make use of a [http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/ line and plane intersection] algorithm, this would require a check of all 6 surfaces (most likely), since unlike usual robocode, the hit box changes orientation and is of non-square dimensions. --[[User:Chase-san|Chase]] 17:49, 23 April 2010 (UTC)<br />
<br />
== Wow 2 Years... ==<br />
<br />
Looking at the timestamp of the last bot I released (Pytko), it has been over 2 years since I released anything. I have been doing other things since then, but the robocode fever really did burn itself out I guess... It is no longer "I can stop any time I like!", but "I not sure if I can restart.". The thing is, it has been so long since I have worked on a robot, I would have to cover the basics again... While I consider this a great chance for a fresh beginning in the community, there is little room left for innovation, and I doubt I would be the one to make any such breakthrough (unless I try to make an [http://en.wikipedia.org/wiki/Adaptive_resonance_theory ART] based bot and it works). --[[User:Chase-san|Chase]] 03:37, 3 March 2010 (UTC)<br />
<br />
Well, I feel that melee has greater room for innovation than 1v1 still, and that the Team an Twin formats are still relatively unexplored and likely have many breakthroughs to be made still. --[[User:Rednaxela|Rednaxela]] 03:55, 3 March 2010 (UTC)<br />
<br />
Just two years.... Remember Phoenix took David three years =) --[[User:Nat|<span style="color:#099;">Nat</span>]] [[User talk:Nat|<span style="color:#0a5;">Pavasant</span>]] 15:13, 3 March 2010 (UTC)<br />
<br />
I kind of know the feeling. I started working on [[Diamond]] last April after ~16 months of non-Robocoding. You look at 1v1 and you're like, "do I really want to even start climbing this mountain?" =) But I'd barely touched Melee before then, so it was a very refreshing and enjoyable experience to explore new territory. And, of course, eventually the 1v1 bug bit me again, too. Anyway, welcome back and good luck. =) --[[User:Voidious|Voidious]] 15:35, 3 March 2010 (UTC)<br />
*I am often working on Hubris in the background, but every innovation falls flat. I'm sure I could get much farther playing with movement, but I'm really just not that interested in that aspect. I just keep building the foundation of the robot and changing my statistical gun around. Meh. Then I get irritated and slip back into the shadows for a while. --[[User:Pedersen|Martin]] 16:23, 3 March 2010 (UTC)<br />
<br />
You removed orbit and wristwatch. Both those bots have been giving me trouble for years you know. Just because your bots aren't top 10 doesn't mean they aren't contributing to the fun that is robocode. I've spent quite a bit of time trying to time out their movements for maximum effect :) BTW, welcome back! --[[User:Miked0801|Miked0801]] 16:11, 3 March 2010 (UTC)<br />
: Hah thanks. Maybe I will try for some melee. 1 on 1 is just really hard. Maybe my Kohonen surfing might work better if I make it Min-Risk and shove it into melee (never know). --[[User:Chase-san|Chase]] 20:16, 3 March 2010 (UTC)<br />
:: Prototype gives some pretty strong bots a tough time ([[Diamond]] among them until just recently). On a semi-related note, you might like to read [[Gaff/Targeting]] for some NN-bot inspiration. =) [[Pris]] (Gaff's sister) uses NN for both gun and surfing. --[[User:Voidious|Voidious]] 20:38, 3 March 2010 (UTC)<br />
<br />
== Well in that case ==<br />
<br />
Prototype had a ton of work put into it, reading over its code now, it makes me wonder what exactly my plan was for it. I however very much enjoyed working on Pytko, so I think I might work on that bot some more. Even though it is a classical pattern matcher, it doesn't have a movement to call it's own, so I figure I should resolve that. Even though I doubt I will quickly come up with a better one then Raiko's. --[[User:Chase-san|Chase]] 06:44, 4 March 2010 (UTC)<br />
<br />
== HFSPM? ==<br />
<br />
Forgive me, but I'm curious... what does HFS in HFSPM stand for? :) --[[User:Rednaxela|Rednaxela]] 01:31, 28 June 2010 (UTC)<br />
<br />
: Nothing to special, it's Heavily Folded Symbolic Pattern Matcher. I have no idea if its anything more special than a normal one, except it uses my own symbol maker. Unfortunately, even I cannot seem to replicate those results anymore (at least against RaikoMX). Which makes me very sad. By the way, do you have some other means of contact? &#8212; <span style="font-family: monospace">[[User:Chase-san|Chase]]-[[User_talk:Chase-san|san]]</span> 01:43, 28 June 2010 (UTC)<br />
<br />
:: Actually Nevermind! I found the problem (somehow I removed the AdjustYForXTurn stuff). &#8212; <span style="font-family: monospace">[[User:Chase-san|Chase]]-[[User_talk:Chase-san|san]]</span> 01:59, 28 June 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User_talk:Chase-san/Kd-Tree&diff=16914User talk:Chase-san/Kd-Tree2010-07-01T08:42:00Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>== NullPointerExceptions and inaccuracy ==<br />
<br />
Trying to test your Kd-Tree in the benchmark framework, I'm getting some NullPointerExceptions due to right.rect.getNearest(k) returning null sometimes. I don't know if it's the proper fix, I changed the relevant lines to be like:<br />
<syntaxhighlight>PointKD p = right.rect.getNearest(k);<br />
if(p != null && k.distanceSq(p) < t) {<br />
</syntaxhighlight>Something else is wrong also I believe, because it's only getting "88% accuracy" out of the benchmark results, so it's not finding all of the nearest neighbors correctly. --[[User:Rednaxela|Rednaxela]] 22:23, 1 March 2010 (UTC)<br />
:That should only happen if the rectangle hasn't gotten expanded ever, which shouldn't happen, unless you haven't added anything to the tree at all (darn me and removing all my safeties). Since this gets set during the add. Can you give me some idea of the data you are feeding into it? --[[User:Chase-san|Chase]] 22:44, 1 March 2010 (UTC)<br />
:: Well, it's adding to the tree before it's searching. See, [[File:KNN.jar|KNN.jar]] along with [http://homepages.ucalgary.ca/~agschult/robocode/gun-data-Diamond-vs-jk.mini.CunobelinDC%200.3.csv.gz Diamond vs CunobelinDC gun data], a recording I made of every kd-tree operation performed by an older version of Voidious's Diamond during a battle. I can upload an updated KNN.jar that includes the testing of your tree if you wish. Personally I've found the framework invaluable for testing my tree, making it easy to see when something I just did added a bug. --[[User:Rednaxela|Rednaxela]] 22:55, 1 March 2010 (UTC)<br />
::: I see, I got it running, and I get the error too. Let me see whats going on. --[[User:Chase-san|Chase]] 23:25, 1 March 2010 (UTC)<br />
::: Well I found parts of the problem, it gets 100% now, but its about pretty slow (not as slow as Linear search), I suppose that is to be expected, seeing how hard it is on the GC. Still not sure why Rect is returning null, since it shouldn't (probably something stupid per usual). Well I based this new one off my old one, maybe I should write one from scratch. :P --[[User:Chase-san|Chase]] 00:02, 2 March 2010 (UTC)<br />
<br />
<pre><br />
K-NEAREST NEIGHBOURS ALGORITHMS BENCHMARK<br />
-----------------------------------------<br />
Reading data from data.csv<br />
Read 25621 saves and 10300 searches.<br />
<br />
Running 10 repetition(s) for k-nearest neighbours searching:<br />
:: 13 dimension(s); 40 neighbour(s)<br />
Warming up the JIT with 5 repetitions first...<br />
<br />
Running tests... COMPLETED.<br />
<br />
RESULT << k-nearest neighbours search with Voidious' Linear search >><br />
: Average searching time = 2.007 miliseconds<br />
: Average worst searching time = 37.627 miliseconds<br />
: Average adding time = 3.96 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Chase-san's Bucket PR k-d tree >><br />
: Average searching time = 1.023 miliseconds<br />
: Average worst searching time = 29.937 miliseconds<br />
: Average adding time = 8.38 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Simonton's Bucket PR k-d tree >><br />
: Average searching time = 0.493 miliseconds<br />
: Average worst searching time = 45.444 miliseconds<br />
: Average adding time = 7.15 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Voidious' Bucket PR k-d tree >><br />
: Average searching time = 0.836 miliseconds<br />
: Average worst searching time = 35.729 miliseconds<br />
: Average adding time = 6.39 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree >><br />
: Average searching time = 0.152 miliseconds<br />
: Average worst searching time = 38.736 miliseconds<br />
: Average adding time = 7.43 microseconds<br />
: Accuracy = 100%<br />
<br />
<br />
BEST RESULT: <br />
- #1 Rednaxela's Bucket kd-tree [0.1518]<br />
- #2 Simonton's Bucket PR k-d tree [0.4928]<br />
- #3 Voidious' Bucket PR k-d tree [0.8362]<br />
- #4 Chase-san's Bucket PR k-d tree [1.0227]<br />
- #5 Voidious' Linear search [2.0067]<br />
<br />
Benchmark running time: 493.49 seconds<br />
</pre><br />
<br />
Some results... All I can say is.. this current implementation, the worst search time is the lowest of all of them (though not by a ton, I suppose). But I wonder why that is. --[[User:Chase-san|Chase]] 00:29, 2 March 2010 (UTC)<br />
<br />
<pre><br />
RESULT << k-nearest neighbours search with Chase-san's Bucket PR k-d tree >><br />
: Average searching time = 0.649 miliseconds<br />
: Average worst searching time = 34.114 miliseconds<br />
: Average adding time = 8.92 microseconds<br />
: Accuracy = 10<br />
</pre><br />
It seems Caching the distance cut the time by about 40%. (other times are close to what they are above). Oh well this is probably my last post on the wiki tonight. --[[User:Chase-san|Chase]] 00:45, 2 March 2010 (UTC)<br />
<br />
As far as "I wonder why that is", I would say a variety of factors are involved. Firstly, I'd say the way you use comparators slows things down, due to the calling overhead. Secondly, a default bucket size of 200 seems odd; I've found that the optimal bucket size is more in the area of 24 to 32, depending on the specifics of the tree. With those things changed, as well as some other optimization details around the place, I'd guess the speed could get to would be around that of Duyn's tree perhaps, at least as fast as Simonton's tree. To go a step further, one could replace the Dequeue with a heap, in order to avoid full sorting overhead on points that will not be part of the final set of returned points. Anyway, not a bad job though. It does beat Voidious' tree so far after all which is a well enough made tree. :) --[[User:Rednaxela|Rednaxela]] 01:15, 2 March 2010 (UTC)<br />
<br />
: Here is the low down. It seems what was causing the problem with the null was the fact of a bucket getting points with exactly the same value on a certain dimension, meanin that all the points were placed to one side or the other (in this case the left) of that dimension, and the other side got nothing (poor child). The fact is the rectangles were only defined with something was added to the child, and I assumed since I divided the domain perfectly in half, this error was impossible to get (as I mentioned in my first bit there). <pre>That should only happen if the rectangle hasn't gotten expanded ever, which shouldn't happen, unless you haven't added anything to the tree at all</pre> I had pretty much answered my own question, but was too dense to realize it. however I got tired of poking at my old tree (preformance just kept getting worse), so I made a cut down version with a ShiftArray in it (basically array copy stuff back along the array and just insert the item in place, which is what my prioritydeque pretty much did anyway, but this does it with much less code). I got rid of the whole PointKD, RectangleKD functions, now I have just a thing that takes double[], I added a value clause, so it is just not a key-tree or set, anymore. I am running 10 iterations with KNN to get a benchmark, I will post those when they finish (on another computer). --[[User:Chase-san|Chase]] 03:38, 2 March 2010 (UTC)<br />
<br />
<pre><br />
K-NEAREST NEIGHBOURS ALGORITHMS BENCHMARK<br />
-----------------------------------------<br />
Reading data from data.csv<br />
Read 25621 saves and 10300 searches.<br />
<br />
Running 10 repetition(s) for k-nearest neighbours searching:<br />
:: 13 dimension(s); 40 neighbour(s)<br />
Warming up the JIT with 5 repetitions first...<br />
<br />
Running tests... COMPLETED.<br />
<br />
RESULT << k-nearest neighbours search with Voidious' Linear search >><br />
: Average searching time = 1.873 miliseconds<br />
: Average worst searching time = 34.274 miliseconds<br />
: Average adding time = 3.42 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Chase-san's Bucket PR k-d tree >><br />
: Average searching time = 0.532 miliseconds<br />
: Average worst searching time = 24.898 miliseconds<br />
: Average adding time = 7.76 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Chase's Hyper Bucket KD-Tree >><br />
: Average searching time = 0.433 miliseconds<br />
: Average worst searching time = 24.474 miliseconds<br />
: Average adding time = 6.82 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Simonton's Bucket PR k-d tree >><br />
: Average searching time = 0.437 miliseconds<br />
: Average worst searching time = 38.07 miliseconds<br />
: Average adding time = 6.36 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Voidious' Bucket PR k-d tree >><br />
: Average searching time = 0.763 miliseconds<br />
: Average worst searching time = 31.013 miliseconds<br />
: Average adding time = 5.62 microseconds<br />
: Accuracy = 100%<br />
<br />
RESULT << k-nearest neighbours search with Rednaxela's Bucket kd-tree >><br />
: Average searching time = 0.138 miliseconds<br />
: Average worst searching time = 36.875 miliseconds<br />
: Average adding time = 6.69 microseconds<br />
: Accuracy = 100%<br />
<br />
<br />
BEST RESULT: <br />
- #1 Rednaxela's Bucket kd-tree [0.1375]<br />
- #2 Chase's Hyper Bucket KD-Tree [0.4326]<br />
- #3 Simonton's Bucket PR k-d tree [0.4372]<br />
- #4 Chase-san's Bucket PR k-d tree [0.5324]<br />
- #5 Voidious' Bucket PR k-d tree [0.7634]<br />
- #6 Voidious' Linear search [1.873]<br />
<br />
Benchmark running time: 463.63 seconds<br />
</pre><br />
<br />
I am not you Rednaxela, I think this is as far as I am going to get, I think I will post the hyper version though (it is smaller). --[[User:Chase-san|Chase]] 03:44, 2 March 2010 (UTC)<br />
<br />
== Oh yeah, am I the only one that has a Range function? ==<br />
<br />
Pretty sure. At least, the only one with a Hyperrectangle style one. --[[User:Rednaxela|Rednaxela]] 05:17, 2 March 2010 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Zyx/Talk_Archive_20090506&diff=16913User:Zyx/Talk Archive 200905062010-07-01T08:38:27Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Greetings! Welcome to the Robowiki Zyx! Feel free to ask any question you might have! Btw, [[Newton]] seems pretty strong, care to tell us about it or [[AntBot|Ant]]. Best wishes in your robocoding adventures! --[[Rednaxela]]<br />
<br />
Thanks [[Rednaxela]], I was just writing my "story" when you posted, I will expand [[Newton]] and [[AntBot|Ant]] in a couple of minutes. -- [[Zyx]]<br />
<br />
Wow, how did you find [[Stormrider]]? It's been out of action for ages.... If you want a version that is slightly newer, and much stronger, take a look at DrussGT, it's download link is on the RoboRumble/Participants page. Anyways, welcome to the wiki, and good luck with your coding =) If you have any questions feel free to ask. -- [[Skilgannon]]<br />
<br />
Hehehe [[Stormrider]] was on the new wiki in the [[Bots]] section, and it said it was very competitive so I downloaded it. I was really new to everything at the moment, now I'm more settled, I'm running RoboRumble so I have [[DrussGT]], BTW congrats man, it seems to be very comfortable at the top place :). Thanks for the help and for killing my bot so I'd be interested in learning more. -- [[zyx]]<br />
<br />
:(Oh he may be comfortable at the top for now, but I'm determined to topple [[DrussGT]] eventually... Can't have it's reign last as long as Dookious's did... :) --[[Rednaxela]])<br />
<br />
:Sounds like a neat goal, good luck at it :-). -- [[zyx]]<br />
<br />
:I've still got a few tricks up my sleeve, I just haven't had time to implement them. Involving both guns and movement. And new types of stats. But come on, I'm studying Mechanical Engineering and you're doing Computer Engineering, surely you should have passed me ages ago? ;-) And I've been hearing that you were working on RougeDC's replacement in little snippets here and there, are you ever going to release that to the rumble? -- [[Skilgannon]]<br />
<br />
:Haha, RougeDC's younger and stronger brother doesn't have much done yet... but I'll probably make a hard drive to get at least the gun working in winter break... and my hope is that current generation surfers will be in for some hurt... ;) -- [[Rednaxela]]<br />
<br />
Oh, and sorry for cluttering your talk page with rivalry Zyx :) --[[User:Rednaxela|Rednaxela]] 21:39, 26 November 2008 (UTC)<br />
<br />
:That's what talk pages are for ;) -- [[zyx]]<br />
<br />
== Dynamic Weighting ==<br />
<br />
Do you know of any bot that calculates the weights for [[Dynamic Clustering]] during a battle? Actually if it calculates it's segmentation, or something like that on real time is enough for me. I want a bot that ''learns'' how the enemy is learning. I'm currently working on a DC based bot that uses VCS to adjusts the weights for the ''distancer'' with very promising results. I know many people have used offline methods to do this, I want to know if there is a bot that actually does it during the battle. --[[User:Zyx|zyx]] 21:06, 12 April 2009 (UTC)<br />
<br />
Me, [[Voidious]], [[Simonton]], [[ABC]] and I'm sure others have tried, all without any real success. My methods have included: 1) finding entropy between profile-peak height and any of the attributes (running during non-firing ticks), 2) pulling clusters with each weight modified both directions and seeing which clusters are most accurate with the VG, 3) checking which attribute has the least variation in the last X GFs which were within a certain window and increasing that attribute's weight. So far what we've all found is that a hand-tuned set of weights performs just as well and runs many times quicker. I'm actually dealing with a similar issue in [[Wintermute]], except in the movement, where I'm reluctant to use anything except BulletHitBullet events for changing the weightings because the HitByBullet is affected by what your weights already are. In fact, because the bot probably moved to a safe place for the highly weighted system, it will decrease the weighting for that system (because it got a hit in an area where there shouldn't be any danger), making it cycle between systems that might not be optimal. I know you use something similar in [[YersiniaPestis]], did you take this into account? Did you manage to find a way around it? --[[User:Skilgannon|Skilgannon]] 21:38, 12 April 2009 (UTC)<br />
: For the movement I haven't come up with anything better than hand-tuned yet, for the gun I'm doing the following. I keep evenly segmented VCS for each attribute I have in the tree, and then have the following algorithms in a VG array to adjust weights, I run this every time a wave passes the enemy.<br />
<br />
:* Visits/TotalVisits. Where Visits is the number of visits I have for the spotted window in the wave segment for each attribute and TotalVisits is the sum of all visit counts in a single segment(all segments have the same amount bins updated so is the same for each one). <br />
:* Visits/WindowVisits. Visits is the same as above, and WindowVisits is the sum of all visits in the current factor window across all segments.<br />
:* Each attributs weight is the sum of the standard deviation of all it's segments.<br />
<br />
There has been many others, but these 3 have the best performance. The first two are kept in rolling averages. And all three, are kept as mentioned and later normalized to have a unit vector of weight. I have this on a new bot, because I wanted to get [[YersiniaPestis]] in the DC party, so I can't compare one to one yet, but after the tests are done and I decide the best numbers for rolling depths, number of bins, number of slices, etc. I will add the best one to [[YersiniaPestis]] and see if it performs better with no other change. But the new gun has over 2 points on (my slightly modified) TC index, the problem is that the weighting system is not the only difference. --[[User:Zyx|zyx]] 23:11, 12 April 2009 (UTC)<br />
<br />
Another thing, what you say about the way I update my movement on HitByBullet makes a lot of sense, I will try a version that only updates on BulletHitBullet to see. But on the other hand, it was hit on place where there seemed less danger, then real question might be, why did he think there was not a big danger. In any case, my biggest learning experience in Robocode is that guessing what is good is nonsense, trying is the only way to realize the truth. --[[User:Zyx|zyx]] 23:15, 12 April 2009 (UTC)<br />
<br />
* I've also pondered over both, but my conclusion was that there will always be 'random noise' that your movement cannot account for, and that the HitByBullet will *ONLY* give results that depreciate the highest weighting system. The big disadvantage is that the learning speed goes down a lot when only using BulletHitBullet.--[[User:Skilgannon|Skilgannon]] 06:28, 13 April 2009 (UTC)<br />
<br />
Quick question, I'm currently testing about 7 versions of a modified [[YersiniaPestis]] 1.3.7 to use dynamically adjusted weights, I still don't know if any of them will be better. But in case I found a better version should I upload it to the Rumble? I wouldn't be keeping it in the rumble because I want him to be a pure DC bot, but my new bot is probably not going to be ready to release in a couple of days, and even if it is, is not a good comparison because is a different bot in many other ways. I will anyway post download links to better versions using the new system so you can all see how it does, but would it be politically right to upload it to the rumble just to ''prove'' that dynamic weights are good? I would of course be running a client if I upload it, but since I don't feel that uploading should be taking so lightly, I don't know if it would feel right. Also I test again only a handful of bots, my current test bed is the MC2K7 reference bots, plus the top 6 bots, 3 pattern matchers, and 3 very simple bots. I've found that this tests have been very accurate to a bot being better than another one compared to the real rumble results, but I'm sure you all agree that the real rumble is a bit unpredictable sometimes. I'll let you know about the test results sometime when I have them, I have too many bots being tested right now, so results take hours to finish a single season. --[[User:Zyx|zyx]] 01:45, 13 April 2009 (UTC)<br />
<br />
: I say go for it. I don't think it's a big deal to post a test version to the rumble, especially if you're running a client and doing all that local testing. Though I almost feel like an outsider to the RoboRumble at this point, so take my opinion for what you will. =) --[[User:Voidious|Voidious]] 02:07, 13 April 2009 (UTC)<br />
:* You've done too much for Robocode to be an outsider. The new bots have completed one test season and the best one is 2 points over in APS, I know 1 season is not close to accurate, but if it is actually that much better I'll drop the ''pure DC'', I already got into the DC party with a pure DC bot, there is no good reason to dismiss a seemingly good improvement. What I think now I would do if the new system is measurably better, I'll make a mixed one with some hand-tuned and some dynamic weights in the VG array and release it as the next version instead of just test bot. --[[User:Zyx|zyx]] 04:51, 13 April 2009 (UTC)<br />
: You can change it to start using VCS any time you want, you've made top 10 with DC so you're part of the party now =). I removed [[Stormrider]] from the rumble because I felt it was too similar in code to [[DrussGT]], but as far as I know I'm still a member =) --[[User:Skilgannon|Skilgannon]] 06:28, 13 April 2009 (UTC)<br />
<br />
Just entered YersiniaPestis 1.3.7.2 in the rumble, the only real difference is I added 5 new Distancers to the gun, all from the types I explained above, 2 of the first type, 2 of second type and 1 of the third. The ones that have two of same type is because one have a lower rolling depth than the other. My initial guess is that it will be better APS-wise, but it may lose the PL-crown. I still kept my hand-tuned ones, but they have lower priority than the new ones, and those were tuned to beat top bots rather than simple ones, hopefully it will still hold it's ground, we'll see. --[[User:Zyx|zyx]] 02:23, 14 April 2009 (UTC)<br />
: Removed version 1.3.7.2 from the rumble, results were bad, but I still think there is potential here. I'll keep working and post if find something interesting. --[[User:Zyx|zyx]] 04:59, 16 April 2009 (UTC)<br />
<br />
== Sneak Attack ==<br />
I just realized there are ways to shoot completely undetected bullets, I tried to make a bot based on that but I can't find an easy way to use the exploit and be competitive at the same time. So I decided to just post how to fire undetectable bullets, I haven't really searched, so maybe this has been said elsewhere.<br />
<br />
I think most surfers have some way to detect (as good as they can) when their enemy hits a wall so they are not confused by that energy drop. So if you run towards a wall at some speed, let's say full speed (8), and when you are just about to hit the wall you decelerate and a fire a 1 power bullet. Your enemy will calculate your damage as 8 / 2 - 1 = 3, but you were actually going at 6 at the hit time, so you got 6 / 2 - 1 = 2 wall hit damage, but since you shot a 1 powered bullet they won't see anything strange as your energy dropped 3. And even if someone has thought of that, and took the guess that maybe the bot decelerated you can shoot only sometimes, and make him surf bogus waves.<br />
<br />
This bot shows how to shoot the invisible bullets, it bounces on and off from the top wall (sometimes the bottom) and shoots head on, so it will lose to almost every(if not all) bots. But I challenge anyone to try and detect accurately when he fires. My bots detect some of them, but is not even close to accurate.<br />
<syntaxhighlight><br />
package zyx.nano;<br />
<br />
import robocode.AdvancedRobot;<br />
import robocode.HitWallEvent;<br />
import robocode.ScannedRobotEvent;<br />
import robocode.util.Utils;<br />
<br />
public class SneackAttack extends AdvancedRobot {<br />
static int direction = 1;<br />
private boolean nh;<br />
private int t;<br />
public void run() {<br />
while ( true ) {<br />
if ( getRadarTurnRemainingRadians() == 0 ) setTurnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
execute();<br />
}<br />
}<br />
public void onScannedRobot(ScannedRobotEvent event) {<br />
double bearing = getHeadingRadians() + event.getBearingRadians();<br />
setTurnGunRightRadians(Utils.normalRelativeAngle(bearing - getGunHeadingRadians()));<br />
setTurnRightRadians(Utils.normalRelativeAngle(-getHeadingRadians()));<br />
setTurnRadarRightRadians(Utils.normalRelativeAngle(bearing - getRadarHeadingRadians()) * 1.99);<br />
double v = getVelocity();<br />
if ( v < 0 ) v += 2; else if ( v > 0 ) v -= 2;<br />
double nx = getX() + Math.sin(getHeadingRadians()) * getVelocity() + Math.sin(getHeadingRadians()) * v;<br />
double ny = getY() + Math.cos(getHeadingRadians()) * getVelocity() + Math.cos(getHeadingRadians()) * v;<br />
if ( nh ) {<br />
if ( Math.random() < 0.8 ) setFire(1);<br />
setAhead(0);<br />
} else {<br />
setAhead(100 * direction);<br />
}<br />
nh = false;<br />
if ( t == 5 ) direction = -direction;<br />
if ( --t <= 0 && (nx < 19 || ny < 19 || nx > 781 || ny > 581) ) {<br />
nh = true;<br />
}<br />
}<br />
public void onHitWall(HitWallEvent arg0) {<br />
direction = -direction;<br />
t = 20;<br />
}<br />
}<br />
</syntaxhighlight><br />
Have fun. --[[User:Zyx|zyx]] 07:13, 18 March 2009 (UTC)<br />
<br />
Haha, perfectly accurate detection is impossible. It has been discussed [http://robowiki.net/cgi-bin/robowiki?EnergyDrop here] (see some of ABCs notes) why one can at best guess the wall damage with an error between +0.5 and -1.0. The only possible real countermeasures I believe are: 1) Fire low-weight waves whenever the enemy hits the wall or 2) Detect if you got hit by a wallhit-concealed bullet, and if so presume they always make wallhit-concealed hits so long as gunheat indicates that they could have. A truely accurate countermeasure? That's impossible. --[[User:Rednaxela|Rednaxela]] 07:25, 18 March 2009 (UTC)<br />
* Heheh, I assumed someone realized this, that's why I said I didn't search for it (it is 3:30 am here). I thought about you 1st counter option, but I guessed it was not worth the trouble(at least not yet) since I don't see how a bot can use this and actually become strong against a top bot. My current surfing algorithm surfs fake waves when he doesn't have at least 2 real waves, I did that mostly to avoid getting in dangerous spots for a bullet that hasn't been fired yet, but I think it will dodge some of those invisible bullets. And there many more important things that can be improved still. --[[User:Zyx|zyx]] 07:41, 18 March 2009 (UTC)<br />
* There are nearly no surfer detecting it, also many surfer do not even detecting wall hit since the bots that hit wall usually a simple robot that can take out easily, and I think it have only little advantage. Say, if you hit, you will get back 3 LP, meaning no change to your LP (firing and hitting cost 3) but if you miss, you will lost 2 energy without doing anything! At distance 300, you have ~12% chance, at distance 400 only ~9% chance! You may said that you have brilliant gun, but ot hit surfer it need more than that! &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:49, 18 March 2009 (UTC)<br />
* Actually, a fair number of surfers will behave VERY simplistically when they don't know of any waves. I know of one that will just sit still maintaining a certain distance. I know of others that will just orbit in one direction. Given how many surfers do that, I bet you could beat a fair number of them with hidden bullets IF you had a strong gun AND were able to make youre movement unpredictable while still only firing when it can be hidden. --[[User:Rednaxela|Rednaxela]] 14:42, 18 March 2009 (UTC)<br />
* Oh! I forgot about that! Anyway, try hitting DrussGT with hidden bullet :) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:16, 18 March 2009 (UTC)<br />
* Yes I'm sure there are bots that can be affected by them, but I don't believe it can be used to make a bot perform better than having a good surfing with nearly zero wall hits. About hitting DrussGT, I don't think top bots can be harmed much by this, so I will not try to hit him :) --[[User:Zyx|zyx]] 15:21, 18 March 2009 (UTC)<br />
* From what I remember, DrussGT doesn't have any wallhit detection. I might have added it in once, but I'm not sure if I kept it or if it was too buggy. Anyways, it just fires a wave if your gunheat is at an allowable level, so would get the bullet power wrong but would still surf a wave. --[[User:Skilgannon|Skilgannon]] 21:48, 12 April 2009 (UTC)<br />
<br />
Another way to fire hidden bullet is to move toward walls will slow velocity (say 6), then a tick before hitting, accelerate to 7 and fire(3), enemy ''without'' wall hit detection will see energy drop of 5.5, therefore they don't care since almost every surfer have <code>if (bulletPower > 0.09 && bulletPower < 3.01)</code>. Enemy ''with'' wall hit detection will see energy drop of 3.5, therefore they don't care, too. But this way is easier to detect than one you mentioned. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 03:29, 13 April 2009 (UTC)<br />
* Hehehe, that's a nice one, actually yes I believe is even more effective than the fire(1), I will at some point try a bot with a smaller wall stick, setMaxVelocity(7), and when wall hit is unavoidable accelerate and shoot, not as a main targeting strategy but as a part of a normally behaved good bot. --[[User:Zyx|zyx]] 04:43, 13 April 2009 (UTC)<br />
** There's no need for setMaxVelocity(7), you can move at velocity 7 and hit wall at 8, too. Or you mean to setMaxVelocity(7) two ticks before hit and setMaxVelocity(8) a tick before hit? That way you need super precise prediction that can handler wall hit. Anyway, this way is easier to detect from enemy than one you mentioned, because accelerate always 1, but decelerate can be 1 or 2. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 05:14, 13 April 2009 (UTC)<br />
*** I mean setting setMaxVelocity(7) for normal behavior and set it to 8 when the wall-hit/hidden bullet is to come. Because that way I can keep a normal movement the rest of battle, using 7 as my max velocity. I think it would be needed a more precise and complex prediction to make the bot go at 7 before the wall-hit and at 8 at the hit time, so I would setMaxVelocity(7) to avoid caring about it myself, and only set it to 8 when I want to hit the wall, if the enemy uses my last acceleration or it keeps track of my max velocity (I don't but maybe some bots do) they will never guess I hit at 8 because they will never see me go at 8 during the battle :p. But I will do this only after I'm bored with trying to make real good bots. --[[User:Zyx|zyx]] 05:55, 13 April 2009 (UTC)<br />
** Moving with a max speed of 7 will hurt you more due to reduced MaxEscapeAngle, than you will gain with these 'hidden' bullets. Most good bots do take into account wallhits, even when de/accelerating, but it is true, perfect prediction does not exist in this case. --[[User:GrubbmGait|GrubbmGait]] 10:49, 13 April 2009 (UTC)<br />
*** I agree that most good bots do take into account wallhits, but not current DrussGT. And, which bot do take account de/accelerating? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:15, 13 April 2009 (UTC)<br />
**** [[GresSuffurd]] takes into account de/acceleration, but not when in the last tick as mentioned above. GresSuffurd is not a topbot though, because of its limited features and simplicity. (But I like to think that it is bugfree in the things it does do). --[[User:GrubbmGait|GrubbmGait]] 12:56, 13 April 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Zyx/Radar_Widest_Area_Angle&diff=16912User:Zyx/Radar Widest Area Angle2010-07-01T08:38:25Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>== Motivation ==<br />
<br />
Many bots, including top bots, when a round starts they simply set their radar to turn, in a somewhat arbitrary way (most turn it right). But there is a relatively easy way to decide the best way to turn it, to minimize the expected number of ticks needed to find your opponent. Turning in the best way will most likely have a very marginal improvement if any, but either way it can't harm the normal behavior.<br />
<br />
== Idea ==<br />
The following code divides the battle field into two areas, the one bounded by the current radar heading turning it right Math.PI radians, and the one doing the same to the left. If the area to the right is bigger then it returns Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY otherwise.<br />
<br />
== Usage ==<br />
Change the usual<br />
<syntaxhighlight><br />
if ( getRadarTurnRemainingRadians() == 0 ) setTurnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
</syntaxhighlight><br />
<br />
for<br />
<syntaxhighlight><br />
if ( getRadarTurnRemainingRadians() == 0 ) setTurnRadarRightRadians(zyx.mega.radar.Radar.getWidestAreaAngle(this));<br />
</syntaxhighlight><br />
<br />
== Code ==<br />
<syntaxhighlight><br />
package zyx.mega.radar;<br />
import static java.lang.Double.NEGATIVE_INFINITY;<br />
import static java.lang.Double.POSITIVE_INFINITY;<br />
import static java.lang.Math.PI;<br />
import static java.lang.Math.abs;<br />
import static java.lang.Math.atan2;<br />
import static java.lang.Math.cos;<br />
import static java.lang.Math.max;<br />
import static java.lang.Math.min;<br />
import static java.lang.Math.signum;<br />
import static java.lang.Math.sin;<br />
import static robocode.util.Utils.normalRelativeAngle;<br />
import java.awt.geom.Point2D;<br />
import robocode.AdvancedRobot;<br />
public class Radar {<br />
public static double getWidestAreaAngle(AdvancedRobot robot) {<br />
double X[] = { 0, robot.getBattleFieldWidth() };<br />
double Y[] = { 0, robot.getBattleFieldHeight() };<br />
Point2D me = new Point2D.Double(robot.getX(), robot.getY());<br />
int corner_count[] = {0, 0};<br />
Point2D right[] = new Point2D[2];<br />
double righta[] = new double[2];<br />
for ( double x : X ) for ( double y : Y ) {<br />
double a = normalRelativeAngle(atan2(x - me.getX(), y - me.getY()) - robot.getRadarHeadingRadians());<br />
double tt = signum(a);<br />
if ( tt < 0 ) {<br />
if ( ++corner_count[0] > 2 ) return NEGATIVE_INFINITY;<br />
} else {<br />
if ( corner_count[1] == 2 ) return POSITIVE_INFINITY;<br />
righta[corner_count[1]] = abs(a);<br />
right[corner_count[1]++] = new Point2D.Double(x, y);<br />
}<br />
}<br />
double length = X[1] * Y[1] * 2;<br />
LineEQ ray1 = new LineEQ(me, Project(me, robot.getRadarHeadingRadians(), length));<br />
LineEQ ray2 = new LineEQ(me, Project(me, robot.getRadarHeadingRadians() + PI, length));<br />
LineEQ test[] = {<br />
new LineEQ(new Point2D.Double(0,0), new Point2D.Double(X[1], 0)),<br />
new LineEQ(new Point2D.Double(X[1],0), new Point2D.Double(X[1], Y[1])),<br />
new LineEQ(new Point2D.Double(X[1], Y[1]), new Point2D.Double(0,Y[1])),<br />
new LineEQ(new Point2D.Double(0, Y[1]), new Point2D.Double(0,0)),<br />
};<br />
Point2D x = new Point2D.Double();<br />
double area_right = Area(me, right[0], right[1]);<br />
for ( LineEQ li : test ) {<br />
if ( Intersect(ray1, li, x) ) {<br />
Point2D y = right[0];<br />
if ( righta[0] > righta[1] ) y = right[1];<br />
area_right += Area(me, x, y);<br />
}<br />
if ( Intersect(ray2, li, x) ) {<br />
Point2D y = right[1];<br />
if ( righta[0] > righta[1] ) y = right[0];<br />
area_right += Area(me, x, y);<br />
}<br />
}<br />
System.out.printf("%.4f %.4f\n", area_right, X[1] * Y[1] - area_right);<br />
return X[1] * Y[1] - area_right < area_right ? POSITIVE_INFINITY : NEGATIVE_INFINITY;<br />
}<br />
private static Point2D Project(Point2D start, double bearing, double distance) {<br />
return new Point2D.Double(start.getX() + sin(bearing) * distance,<br />
start.getY() + cos(bearing) * distance);<br />
}<br />
private static class LineEQ {<br />
double A, B, C;<br />
Point2D pmin, pmax;<br />
public LineEQ(Point2D p1, Point2D p2) {<br />
A = p2.getY() - p1.getY();<br />
B = p1.getX() - p2.getX();<br />
C = A * p1.getX() + B * p1.getY();<br />
pmin = new Point2D.Double(min(p1.getX(), p2.getX()), min(p1.getY(), p2.getY()));<br />
pmax = new Point2D.Double(max(p1.getX(), p2.getX()), max(p1.getY(), p2.getY()));<br />
}<br />
};<br />
private static boolean Intersect(LineEQ line1, LineEQ line2, Point2D p) {<br />
double det = line1.A * line2.B - line2.A * line1.B;<br />
if ( abs(det) < 1e-5 ) return false;<br />
p.setLocation((line2.B * line1.C - line1.B * line2.C) / det, (line1.A * line2.C - line2.A * line1.C) / det);<br />
return <br />
p.getX() + 1e-9 > line1.pmin.getX() && p.getX()- 1e-9 < line1.pmax.getX() &&<br />
p.getY() + 1e-9 > line1.pmin.getY() && p.getY()- 1e-9 < line1.pmax.getY() &&<br />
p.getX() + 1e-9 > line2.pmin.getX() && p.getX()- 1e-9 < line2.pmax.getX() &&<br />
p.getY() + 1e-9 > line2.pmin.getY() && p.getY()- 1e-9 < line2.pmax.getY();<br />
}<br />
private static double Area(Point2D origin, Point2D v1, Point2D v2) {<br />
return abs((v1.getX() - origin.getX()) * (v2.getY() - origin.getY()) - (v1.getY() - origin.getY()) * (v2.getX() - origin.getX())) / 2; <br />
}<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Voidious/Optimal_Velocity&diff=16911User:Voidious/Optimal Velocity2010-07-01T08:38:20Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>__TOC__<br />
== First attempt ==<br />
<br />
I don't want to clutter the [[Talk:Robocode/Game Physics]] page with full versions of this, but I want the updated full version somewhere... The goal is to go <code>distance</code> in the fewest number of ticks, limited by <code>Rules.ACCELERATION</code>, <code>Rules.DECELERATION</code>, and <code>currentCommands.getMaxVelocity()</code>.<br />
<syntaxhighlight><br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
double dx = velocity * sin(bodyHeading);<br />
double dy = velocity * cos(bodyHeading);<br />
<br />
x += dx;<br />
y += dy;<br />
<br />
if (dx != 0 || dy != 0) {<br />
updateBoundingBox();<br />
}<br />
<br />
if (distance != 0) {<br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
}<br />
}<br />
<br />
/**<br />
* Returns the new velocity based on the current velocity and distance to move.<br />
*<br />
* @param velocity the current velocity<br />
* @param distance the distance to move<br />
* @return the new velocity based on the current velocity and distance to move<br />
*/<br />
private double getNewVelocity(double velocity, double distance) {<br />
// If the distance is negative, then change it to be positive and change the sign of the input velocity and the result<br />
if (distance < 0) {<br />
return -getNewVelocity(-velocity, -distance);<br />
}<br />
<br />
double newVelocity;<br />
<br />
// Get the speed, which is always positive (because it is a scalar)<br />
final double speed = Math.abs(velocity);<br />
<br />
if (velocity < 0) {<br />
// Check if we are decelerating, i.e. if the velocity is negative.<br />
newVelocity = speed - Rules.DECELERATION;<br />
<br />
// Check if we are going from deceleration into acceleration<br />
if (newVelocity < 0) {<br />
// If we have decelerated to velocity = 0, then the remaining time must be used for acceleration<br />
double decelTime = speed / Rules.DECELERATION;<br />
double accelTime = (1 - decelTime);<br />
<br />
// New velocity (v) = d / t, where time = 1 (i.e. 1 turn). Hence, v = d / 1 => v = d<br />
// However, the new velocity must be limited by the max. velocity<br />
newVelocity = Math.min(Rules.ACCELERATION * accelTime, distance));<br />
<br />
// Note: We change the sign here due to the sign check later when returning the result<br />
velocity *= -1;<br />
}<br />
} else {<br />
// Deceleration distance (d) is calculated iteratively due to Robocode's<br />
// discrete time system.<br />
final double decelDist = decelDistance(speed);<br />
<br />
// Deceleration ticks is the number of ticks it will take to get to<br />
// zero velocity.<br />
final long decelTime = Math.round( // VOIDIOUS: for rounding errors? maybe unnecessary<br />
Math.ceil((speed - Rules.DECELERATION) / Rules.DECELERATION));<br />
<br />
// The maximum distance coverable with an equivalent decelTime<br />
final double decelTimeMaxDist = ((decelTime + 1) / 2.0) * decelTime // sum of 1..decelTime<br />
* Rules.DECELERATION;<br />
<br />
if (distance <= Rules.DECELERATION) {<br />
// If we can cover remaining distance and then completely stop,<br />
// set speed = distance<br />
newVelocity = Math.max(speed - Rules.DECELERATION, distance);<br />
} else if (distance <= decelTimeMaxDist) {<br />
// If we can cover distance in decelTime, split any extra<br />
// distance (between decelDist and distance) over decelTime<br />
// ticks<br />
newVelocity = speed - Rules.DECELERATION +<br />
((distance - decelDist) / decelTime);<br />
} else {<br />
// If we need more than decelTime ticks, try to spread the<br />
// extra distance over (decelTime + 1) ticks. This will just max<br />
// the acceleration if it needs to (ie, if we need more ticks).<br />
// VOIDIOUS: I think this part would break if Rules.ACCELERATION<br />
// were set above Rules.DECELERATION; we might need an<br />
// extra case or something. Doh. =(<br />
newVelocity = Math.min(speed + Rules.ACCELERATION,<br />
(decelTime * Rules.DECELERATION) +<br />
((distance - decelTimeMaxDist) / Math.max(decelTime + 1, 2)));<br />
}<br />
}<br />
<br />
// VOIDIOUS: I think it makes more sense to do this here; no need to decelerate maximally<br />
// if you don't need to to accomodate a new setMaxVelocity.<br />
newVelocity = Math.max(speed - Rules.DECELERATION,<br />
Math.min(speed + Rules.ACCELERATION,<br />
Math.min(newVelocity, currentCommands.getMaxVelocity())));<br />
<br />
// Return the new velocity with the correct sign. We have been working with the speed, which is always positive<br />
return (velocity < 0) ? -newVelocity : newVelocity;<br />
}<br />
<br />
private static final double decelDistance(double speed){<br />
double distance = 0;<br />
while(speed > 0){<br />
speed = Math.max(0,speed - Rules.DECELERATION);<br />
distance += speed;<br />
}<br />
return distance;<br />
}<br />
</syntaxhighlight><br />
<br />
* Version 1 posted in-line at [[Talk:Robocode/Game Physics]].<br />
* Version 2 bounds newVelocity by speed + Rules.ACCELERATION and sets a min of 2 for the number of ticks to split the extra distance over.<br />
<br />
== getMaxVelocity solution ==<br />
<br />
Phrasing this a different way, we might try to figure out the max velocity we can go now and still decelerate to a given distance. I think this works, and it does seem like a much more elegant solution.<br />
<syntaxhighlight><br />
double getMaxVelocity(double distance)<br />
{<br />
long decelTime = decelTime(distance);<br />
double decelDist = (decelTime / 2.0) * (decelTime-1) // sum of 0..(decelTime-1)<br />
* Rules.DECELERATION;<br />
<br />
return ((decelTime - 1) * Rules.DECELERATION) +<br />
((distance - decelDist) / decelTime);<br />
}<br />
<br />
long decelTime(double distance) {<br />
long x = 1;<br />
do {<br />
// (square(x) + x) / 2) = 1, 3, 6, 10, 15...<br />
if (distance <= ((square(x) + x) / 2) * Rules.DECELERATION) {<br />
return x;<br />
}<br />
x++;<br />
} while (true);<br />
}<br />
<br />
long square(long i) {<br />
return i * i;<br />
}<br />
</syntaxhighlight><br />
<br />
I derived this by first mapping some things out for different distances, then dissecting it:<br />
* [0, 2] - distance<br />
* (2, 6] - 2 + ((distance-2)/2)<br />
* (6, 12] - 4 + ((distance-6)/3)<br />
* (12, 20] - 6 + ((distance-12)/4)<br />
<br />
== Hijack 2 ==<br />
<br />
Ok, another hijack here. I took Skilgannon's much-reduced version of the code from [[Talk:Positive/Optimal Velocity]], fixed up some white space formatting because I'm OCD, and added support for Fnl's new decel-through-zero rules.<br />
<syntaxhighlight><br />
private static double getNewVelocity(double velocity, double distance) {<br />
if (distance < 0)<br />
// If the distance is negative, then change it to be positive<br />
// and change the sign of the input velocity and the result<br />
return -getNewVelocity(-velocity, -distance);<br />
<br />
final double goalVel;<br />
if(distance == Double.POSITIVE_INFINITY)<br />
goalVel = currentCommands.getMaxVelocity();<br />
else<br />
goalVel = Math.min(getMaxVelocity(distance),<br />
currentCommands.getMaxVelocity());<br />
<br />
if(velocity >= 0)<br />
return Math.max(velocity - Rules.DECELERATION,<br />
Math.min(goalVel, velocity + Rules.ACCELERATION));<br />
//else<br />
return Math.max(velocity - Rules.ACCELERATION,<br />
Math.min(goalVel, velocity + maxDecel(-velocity)));<br />
}<br />
<br />
final static double getMaxVelocity(double distance) {<br />
final double decelTime = Math.max(1,Math.ceil(<br />
//sum of 0... decelTime, solving for decelTime using quadratic formula<br />
(Math.sqrt((4*2/Rules.DECELERATION)*distance + 1) - 1)/2));<br />
<br />
final double decelDist = (decelTime / 2.0) * (decelTime-1) // sum of 0..(decelTime-1)<br />
* Rules.DECELERATION;<br />
<br />
return ((decelTime - 1) * Rules.DECELERATION) +<br />
((distance - decelDist) / decelTime);<br />
}<br />
<br />
private static double maxDecel(double speed) {<br />
double decelTime = speed / Rules.DECELERATION;<br />
double accelTime = (1 - decelTime);<br />
<br />
return Math.min(1, decelTime) * Rules.DECELERATION +<br />
Math.max(0, accelTime) * Rules.ACCELERATION;<br />
}<br />
</syntaxhighlight><br />
The only functional change is replacing Rules.DECELERATION with maxDecel(-velocity) in the one spot. --[[User:Voidious|Voidious]] 15:55, 16 July 2009 (UTC)<br />
<br />
[[Category:Source Code]]</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Starrynte/Melee_Evaluator_Source&diff=16910User:Starrynte/Melee Evaluator Source2010-07-01T08:38:12Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div><syntaxhighlight><br />
package Put_Your_Package_Here;<br />
import robocode.*;<br />
import java.util.Vector;<br />
<br />
public class MeleeEvaluate<br />
{<br />
static private double rating[][]; //holds the ratings<br />
static private int currentStage; //the stage we're in<br />
static private int totalOthers; //total other bots (in the beginning of the battle)<br />
static private double tmpeval;<br />
/*<br />
* Ratings:<br />
* Survival: The average energy gain during a stage<br />
* Hitrate: The average hitrate during a stage<br />
* Infliction: The average damage inflicted during a stage<br />
* Damage: The average damage encountered during a stage<br />
* Survival up through a stage: How often you survive up to and through an ENTIRE stage<br />
* Survival in a stage only: How often your survive in one SINGLE stage<br />
* Skipped turns: The average number of skipped turns during a stage<br />
* Hit walls: The average number of wall hits during a stage<br />
*<br />
*/<br />
static private AdvancedRobot robot; //the robot<br />
static private int[] bulletsFired; //bullets fired so far, by stage<br />
static private int[] rounds; //number of rounds in each stage<br />
static private int stages; //total stages<br />
static private final int NUMSTATS=7; //number of ratings<br />
int others=10; //robot.getOthers(): to prevent multiple printing up stats at the end of a battle<br />
<br />
<br />
public MeleeEvaluate(){<br />
throw new RuntimeException("YOU MUST SPECIFY EXACTLY ONE (1) ADVANCED ROBOT AS A PARAMETER!"); <br />
}<br />
<br />
public MeleeEvaluate(Robot robot){<br />
this();<br />
} <br />
<br />
public MeleeEvaluate(AdvancedRobot bot){<br />
currentStage=0;<br />
if(rating==null){<br />
stages=(int)Math.ceil((bot.getOthers()+1)/2);<br />
rating=new double[stages][NUMSTATS];//5 default stages (98,76,54,32,1) ... with ratings described above<br />
bulletsFired=new int[stages];//see above<br />
rounds=new int[stages];//see above<br />
}<br />
<br />
robot=bot;<br />
this.currentStage=0;<br />
this.totalOthers=this.others=bot.getOthers();<br />
}<br />
<br />
public void execute(){<br />
if(this.others>-1 || robot.getOthers()>0){//the next 3 lines of code, including this one, along with the last one in this function, prevent multiple printing of stats<br />
this.others=robot.getOthers(); <br />
}<br />
Vector v=robot.getAllEvents();<br />
for(int i=0,size=v.size();i<size;i++){<br />
Object obj=v.get(i);<br />
if(obj instanceof DeathEvent){ onDeath((DeathEvent)obj); continue; }<br />
if(obj instanceof RobotDeathEvent){ onRobotDeath((RobotDeathEvent)obj); continue; }<br />
if(obj instanceof SkippedTurnEvent){ rating[currentStage][5]++; continue; }<br />
if(obj instanceof HitByBulletEvent){ onHitByBullet((HitByBulletEvent)obj); continue; }<br />
if(obj instanceof BulletHitEvent){ onBulletHit((BulletHitEvent)obj); continue; }<br />
if(obj instanceof BulletMissedEvent){ onBulletMissed((BulletMissedEvent)obj); continue; }<br />
if(obj instanceof HitRobotEvent){ onHitRobot((HitRobotEvent)obj); continue; } <br />
if(obj instanceof HitWallEvent){ rating[currentStage][6]++; continue; }<br />
if(obj instanceof BulletHitBulletEvent){ onBulletHitBullet((BulletHitBulletEvent)obj); }<br />
}<br />
<br />
if(this.others==0){ rating[currentStage][4]++; onDeath(null); this.others=-1; }<br />
}<br />
<br />
private static void onRobotDeath(RobotDeathEvent e){<br />
int tempStage=currentStage;<br />
currentStage=(totalOthers - robot.getOthers())>>1; //currentStage with 10 bots: 9,8 - 0 | 7,6 - 1 | 5,4 - 2 | 3,2 - 3 | 1 - 4 <br />
if(tempStage+1==currentStage && robot.getOthers()>0){ //if the stage changed AND there are robots left (no robots left handled later) <br />
rating[tempStage][4]++; //update survival stage<br />
rounds[currentStage]++; <br />
}<br />
}<br />
<br />
private static void onHitByBullet(HitByBulletEvent e){<br />
tmpeval=(((tmpeval=e.getBullet().getPower())>1) ? (tmpeval*4) + (2*(tmpeval-1)):tmpeval*4);<br />
rating[currentStage][0]-=tmpeval; //update survival using formula<br />
rating[currentStage][3]+=tmpeval; //update damage using formula<br />
}<br />
<br />
private static void onBulletHit(BulletHitEvent e){<br />
tmpeval=e.getBullet().getPower();<br />
rating[currentStage][0]+=tmpeval*2; //update survival: you lose <power> amount of energy for shooting, but you get 3*<power> energy back<br />
rating[currentStage][1]=((rating[currentStage][1]*((double)bulletsFired[currentStage]))+1)/(++bulletsFired[currentStage]); //update hitrate: first calculate the bullets hit based on hitrate before, then update new hitrate and bullets fired<br />
rating[currentStage][2]+=((tmpeval>1) ? (tmpeval*4) + (2*(tmpeval-1)):tmpeval*4); //update damage inflicted using formula<br />
}<br />
<br />
private static void onBulletMissed(BulletMissedEvent e){<br />
rating[currentStage][0]-=e.getBullet().getPower(); //update survival: energy expended for firing<br />
rating[currentStage][1]=(rating[currentStage][1]*((double)bulletsFired[currentStage]))/(++bulletsFired[currentStage]); //update hitrate: first calculate the bullets hit based on hitrate before, then update new hitrate and bullets fired<br />
}<br />
<br />
private static void onBulletHitBullet(BulletHitBulletEvent e){<br />
rating[currentStage][0]-=e.getBullet().getPower(); //update survival: energy expended for firing<br />
//don't need to update hitrate: bulletHitBullet isn't entirely your fault<br />
}<br />
<br />
private static void onHitRobot(HitRobotEvent e){<br />
rating[currentStage][0]-=0.6d; //update survival: robot loses 0.6 energy<br />
rating[currentStage][2]+=0.6d; //update infliction: hit robot loses 0.6 energy<br />
rating[currentStage][3]+=0.6d; //update damage: i lose 0.6 energy<br />
}<br />
<br />
private static void onDeath(DeathEvent e){<br />
rounds[0]++;<br />
printStats();<br />
}<br />
<br />
public double[][] getRawStats(){<br />
return rating;<br />
}<br />
<br />
public double[][] getStats(){<br />
double[][] stats=rating;<br />
int round=robot.getRoundNum()+1;<br />
for(int i=0;i<stages;i++){<br />
for(int j=0;j<NUMSTATS;j++){<br />
if(j==1){ continue; } //don't average over round for hitrate<br />
stats[i][j]/=round;<br />
}<br />
}<br />
return stats;<br />
}<br />
<br />
<br />
public static void printStats(){<br />
final int round=robot.getRoundNum()+1; <br />
robot.out.println();<br />
for(int i=0;i<stages;i++){<br />
robot.out.println("Stage " + (i+1) + ":");<br />
robot.out.println("Average energy gain: " + (rating[i][0]/round));<br />
robot.out.println("Average hitrate: " + rating[i][1]);<br />
robot.out.println("Average inflicted damage: " + (rating[i][2]/round));<br />
robot.out.println("Average damage encountered: " + (rating[i][3]/round));<br />
robot.out.println("Average survival up through this stage: " + (rating[i][4]/round));<br />
robot.out.println("Average survival in this stage only: " + (rating[i][4]/rounds[i]));<br />
robot.out.println("Average skipped turns: " + (rating[i][5]/round));<br />
robot.out.println("Average wall hits: " + (rating[i][6]/round));<br />
}<br />
} <br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Starrynte/Melee_Evaluator&diff=16909User:Starrynte/Melee Evaluator2010-07-01T08:38:10Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>A utility that provides stats on your bot's performance in melee battles (currently only supports AdvancedRobot and battles with an even number of bots, and even then the standard 10 bots a battle is recommended).<br />
<br />
==How to Use==<br />
1. Copy [[User:Starrynte/Melee Evaluator Source|the code here]] and paste it into a new class called MeleeEvaluate<br />
2. Change the package to yours and compile the code<br />
3. Add this to your bot's code, where the variables are: <syntaxhighlight>static MeleeEvaluate me;</syntaxhighlight><br />
4. Then, inside run(), but outside the infinite loop (right after public void run() ), copy and paste this code: <syntaxhighlight><br />
if(me==null){<br />
me=new MeleeEvaluate(this);<br />
}<br />
Condition go=new Condition("go"){<br />
public boolean test(){<br />
return true;<br />
}<br />
};<br />
go.setPriority(100);<br />
addCustomEvent(go);<br />
</syntaxhighlight><br />
If your bot uses blocking calls, make sure this code goes before the blocking calls in run()<br />
5. Finally, copy and paste this code right outside run() (like onScannedRobot): <syntaxhighlight><br />
public void onCustomEvent(CustomEvent e){<br />
me.execute();<br />
}<br />
</syntaxhighlight><br />
6. Compile your bot, run it in battles, and watch the console!</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Starrynte/Remez&diff=16908User:Starrynte/Remez2010-07-01T08:38:09Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>A utility for finding polynomial approximations for a function of your choice.<br />
<br />
Current feature(s):<br />
* Any function of your choice<br />
* Any degree polynomial of your choice<br />
* Any interval of your choice (i.e. approximates function over [-1,1] )<br />
<br />
Planned feature(s):<br />
* Rational approximations<br />
<br />
===How to Use===<br />
The code is below. Simply change the top part labeled "your settings", and the program does the rest.<br />
(Note: Attempting to do "crazy" approximations (i.e. high degree, low interval) will result in erratic behavior, presumably due to double precision)<br />
<syntaxhighlight><br />
public class Remez {<br />
//---YOUR SETTINGS---<br />
static double f(double x){ //THE FUNCTION TO BE APPROXIMATED<br />
return Math.sin(x);<br />
}<br />
static final int DEG = 6; //DEGREE OF THE POLYNOMIAL - MUST BE POSITIVE<br />
static final double lowx = 0d, highx = Math.PI*2; //APPROXIMATES F(X) FROM LOWX TO HIGHX <br />
<br />
<br />
//---MAIN PROGRAM CODE---<br />
<br />
<br />
static final double RANGE = highx - lowx;<br />
static final int COLUMNS = DEG + 3;<br />
static final int ROWS = DEG + 2;<br />
static final double[] extrema = new double[ROWS];<br />
static final double[][] matrix = new double[ROWS][COLUMNS];<br />
<br />
public static void main(String[] args) {<br />
for(int i=0;i<ROWS;i++) extrema[i]=0.5 * (-Math.cos(i*Math.PI/(DEG + 1)) + 1) * RANGE + lowx; <br />
for(int i=0;i<20;i++) remez();<br />
for(int i=0;i<DEG;i++) System.out.print(matrix[i][COLUMNS-1] + " + x * ("); <br />
System.out.print(matrix[DEG][COLUMNS-1]);<br />
for(int i=0;i<DEG;i++) System.out.print(")");<br />
System.out.println("\nMax error: " + matrix[ROWS-1][COLUMNS-1]);<br />
} <br />
<br />
private static void remez(){<br />
for(int i=0;i<ROWS;i++){ <br />
for(int j=0;j<DEG+1;j++) matrix[i][j]=Math.pow(extrema[i],j); <br />
matrix[i][DEG+1]=(i&1)==0?1d:-1d;<br />
matrix[i][DEG+2]=f(extrema[i]);<br />
}<br />
rref(matrix);<br />
extrema[0]=lowx;<br />
int z=1;<br />
for(double x=lowx+(RANGE/1000);x<=highx && z<(DEG+2);x+=(RANGE/1000)){<br />
if(deverf(x) * deverf(x-(RANGE/1000)) < 0){<br />
extrema[z]=extrema(x-(RANGE/1000),x);<br />
z++;<br />
}<br />
}<br />
}<br />
<br />
private static void rref(double[][] m){<br />
int lead; double factor;<br />
for(int r=1;r<ROWS;r++){ //starting at second row<br />
lead=0;<br />
for(int i=0;i<r;i++,lead++){<br />
factor=m[r][lead]/m[i][lead];<br />
for(int c=lead;c<COLUMNS;c++){ <br />
m[r][c]-=factor*m[i][c];<br />
}<br />
}<br />
for(int c=COLUMNS-1;c>=lead;c--){<br />
m[r][c]/=m[r][lead];<br />
}<br />
}<br />
for(int r=ROWS-2;r>=0;r--){ //starting at second last row<br />
lead=COLUMNS-2;<br />
for(int i=ROWS-1;i>r;i--,lead--){<br />
factor=m[r][lead];<br />
for(int c=lead;c<COLUMNS;c++){<br />
m[r][c]-=factor*m[i][c];<br />
}<br />
}<br />
}<br />
}<br />
<br />
private static double deverf(double x){<br />
final double h = 0.001 * (1 + Math.abs(x));<br />
double dev = (f(x+h) - f(x-h))/(2*h); <br />
for(int r=1;r<(ROWS-1);r++){ //constant term doesn't affect derivative<br />
dev -= r * matrix[r][COLUMNS-1] * Math.pow(x,r-1);<br />
}<br />
return dev;<br />
}<br />
<br />
private static double extrema(double lbound,double rbound){<br />
double mid;<br />
while(Math.abs(rbound-lbound)>0.0000000002){<br />
if(deverf(lbound)*deverf(mid=(rbound+lbound)*0.5) > 0) lbound=mid;<br />
else rbound=mid;<br />
}<br />
return (lbound+rbound)*0.5;<br />
}<br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Skilgannon/Optimal_Velocity&diff=16907User:Skilgannon/Optimal Velocity2010-07-01T08:38:07Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>I'll be gone to Mozambique for a week, I expect people to find cases that break this code while I'm gone =)<br />
<br />
<syntaxhighlight><br />
/**<br />
* Returns the new velocity based on the current velocity and distance to move.<br />
*<br />
* @param velocity the current velocity<br />
* @param distance the distance to move<br />
* @return the new velocity based on the current velocity and distance to move<br />
*/<br />
private static double getNewVelocity(double velocity, double distance) {<br />
<br />
if (distance < 0) <br />
return -getNewVelocity(-velocity, -distance);<br />
// If the distance is negative, then change it to be positive<br />
// and change the sign of the input velocity and the result<br />
<br />
double maxVel = currentCommands.getMaxVelocity();<br />
if (velocity < 0)<br />
return Math.min(velocity + Rules.DECELERATION, Math.min(distance,maxVel));<br />
//we want to go in the opposite direction, so decelerate <br />
<br />
else{ <br />
//we are going in the direction we want, test what happens if we accelerate<br />
<br />
double accel = Math.min(Rules.ACCELERATION, maxVel - velocity);<br />
//speed up, but not more than max velocity. decel if maxVel is less than vel.<br />
<br />
accel = Math.max(accel, -Rules.DECELERATION);<br />
//prevent excess deceleration due to bot lowering the max velocity<br />
// while velocity is high<br />
<br />
if (distance > decelDistance(velocity + accel))<br />
return velocity + accel;<br />
else if(accel != 0 && distance > decelDistance(velocity))<br />
return velocity;<br />
else{<br />
if(distance < Rules.DECELERATION <br />
//we'll be able to cover remaining distance in 1 tick and then decel to stop<br />
<br />
&& velocity <= Rules.DECELERATION + distance<br />
//and our velocity is low enough for us to get to that required velocity<br />
)<br />
return Math.min(distance, maxVel);<br />
<br />
double distDiff = distance - decelDistance(velocity - Rules.DECELERATION);<br />
double decelTime = Math.ceil(velocity / Rules.DECELERATION);<br />
<br />
accel = distDiff/decelTime - Rules.DECELERATION;<br />
<br />
double newVel = Math.max(-maxVel, Math.min(velocity + accel, maxVel));<br />
<br />
return Math.max(velocity - Rules.DECELERATION, Math.min(newVel, <br />
velocity + Rules.ACCELERATION));<br />
}<br />
<br />
}<br />
<br />
}<br />
/**<br />
* Returns the linear distance it would take to decelerate from a given positive velocity<br />
*<br />
* @param velocity the positive velocity from which to test<br />
* @return the linear distance required to decelerate to a standstill<br />
*/<br />
<br />
private static final double decelDistance(double velocity){<br />
double t =velocity / Rules.DECELERATION;<br />
double floor_t = Math.floor(t);<br />
return 0.5*floor_t*(floor_t+1)*Rules.DECELERATION + (velocity%2)*Math.ceil(t);<br />
} <br />
</syntaxhighlight><br />
--[[User:Skilgannon|Skilgannon]] 08:25, 16 July 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Robobot/User_Page_Redirect&diff=16906User:Robobot/User Page Redirect2010-07-01T08:38:04Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Hi all (mainly [[User:Voidious|Voidious]]), do you guys want me to perform a user page redirect replace task now? I've finished the code, converting all redirects it get from [[:Category:User Page Redirect]], anyway the current version cannot handler the <nowiki>[[Page|Title]]</nowiki> format yet. Now it is only command line comment (a java class that only do a thing in its main method) because the main GUI is still under development. Here is a code (quite messy since it is my first testing version of code, and edit into this pieces) Using sightly modified version [[wikipedia:User:MER-C/Wiki.java]].<br />
<br />
<syntaxhighlight><br />
package net.robowiki.robobot;<br />
<br />
import java.io.*;<br />
import java.text.*;<br />
import java.util.*<br />
<br />
import javax.security.auth.login.LoginException;<br />
<br />
import org.wikipedia.en.wiki.user.mer_c.Wiki;<br />
<br />
public class BotTest {<br />
public static Wiki wiki = new Wiki("testwiki.roborumble.org");<br />
public static Wiki local = new Wiki("localhost");<br />
<br />
public static final String talkPage = "<div style=\"text-align:center;display:block;border:2px red solid;background:#fcc;color:#c00;margin:0.5em;padding:0.8em\"><big>'''You MUST NOT edit this page. Any change to this page will STOP a whole bot operations. If you want to talk about this bot, visit [[User:Robobot/talk]] instead.'''</big><p>If you want to cease the bot operations for any reasonable reasons, please leave comment on this page with the reasons. Robot will cease its operations while there are other messages on this page.</p></div>";<br />
<br />
public static void main(String[] args) throws IOException {<br />
try {<br />
wiki.login("Robobot", "<CENSORED>".toCharArray());<br />
local.login("WikiSysop", "1234".toCharArray());<br />
} catch (Exception e) {<br />
e.printStackTrace();<br />
return;<br />
}<br />
try {<br />
String talkPageText = wiki.getPageText("User_talk:Robobot");<br />
<br />
if (!talkPageText.trim().equals(talkPage.trim())) {<br />
System.err.println("ERROR: Robot operation had been ceased by its talk page!");<br />
return;<br />
} else {<br />
System.out.println("Passed talk page check.");<br />
}<br />
} catch (Exception e) {<br />
e.printStackTrace();<br />
return;<br />
}<br />
<br />
// Getting lists of all user page redirect available<br />
String categoryName = "User_Page_Redirect";<br />
String[] pagesname = wiki.getCategoryMembers(categoryName);<br />
<br />
HashMap<String, String> redirectsList = new HashMap<String, String>();<br />
<br />
for (String page : pagesname) {<br />
String content = wiki.getPageText(page);<br />
<br />
String[] contents = content.trim().split("[\r\n]+");<br />
<br />
// Quick hack to get the target page<br />
String target = contents[0].replaceAll("#REDIRECT +\\[\\[(.*)\\]\\]", "$1");<br />
<br />
redirectsList.put(page, target);<br />
}<br />
<br />
try {<br />
// It is manual now, but I can make it auto in no time<br />
String pagetext = wiki.getPageText("GuessFactor/Archived_Talk_20071112");<br />
<br />
for (String name : redirectsList.keySet()) {<br />
// Quick replacing hack again<br />
pagetext = pagetext.replace("[[" + name + "]]", "[["<br />
+ redirectsList.get(name) + "|" + name + "]]");<br />
}<br />
<br />
// saving to my local test wiki now, change local to wiki to work with real wiki<br />
local.edit("Test User Link Fix", pagetext, "", false);<br />
<br />
} catch (IOException e) {<br />
// TODO Auto-generated catch block<br />
e.printStackTrace();<br />
} catch (LoginException e) {<br />
// TODO Auto-generated catch block<br />
e.printStackTrace();<br />
}<br />
updateLastRunning();<br />
}<br />
<br />
public static void updateLastRunning() {<br />
System.out.println("Updating last running time...");<br />
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,<br />
DateFormat.FULL, Locale.US);<br />
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"),<br />
Locale.US);<br />
df.setCalendar(c);<br />
Date dateToFormat = c.getTime();<br />
System.out.println("Time: " + df.format(dateToFormat));<br />
try {<br />
wiki.edit("Template:Robobot/Status", genStatusTemplate("Pending",<br />
"green", "Last run: " + df.format(dateToFormat)),<br />
"update last running time", false);<br />
} catch (LoginException e) {<br />
// TODO Auto-generated catch block<br />
e.printStackTrace();<br />
} catch (IOException e) {<br />
// TODO Auto-generated catch block<br />
e.printStackTrace();<br />
}<br />
<br />
}<br />
<br />
public static String genStatusTemplate(String status, String color,<br />
String comment) {<br />
StringBuilder aa = new StringBuilder();<br />
aa.append("<noinclude><!--\n");<br />
aa.append("\n");<br />
aa<br />
.append("**************************************************************\n");<br />
aa.append("\n");<br />
aa<br />
.append("** ** This template will get updated by automatic bot. ** **\n");<br />
aa<br />
.append("** ** DO NOT EDIT THIS PAGE ** **\n");<br />
aa.append("\n");<br />
aa<br />
.append("**************************************************************\n");<br />
aa.append("\n");<br />
aa<br />
.append("--></noinclude>{| style=\"clear: right; width:270px; float:right; margin:0em 0em 0em 1em; border:1px solid #87CEEB; text-align:center; background-color:#FFFFFF;\"\n");<br />
aa<br />
.append("| style=\"background-color:#f0ffff; text-align:center;\" colspan=\"2\" |'''[[User:Robobot|Robobot]] Status'''\n");<br />
aa.append("|-\n");<br />
aa<br />
.append("| style=\"background-color:#FFFFFF; font-size: 40px; text-align:center; padding-top: 20px; padding-bottom: 5px;\" | <div style=\"color:"<br />
+ color<br />
+ "\">"<br />
+ status<br />
+ "</div><span style=\"font-size:12px\"><br />"<br />
+ comment + "</span>\n");<br />
aa.append("|}\n");<br />
return aa.toString();<br />
}<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
Quite buggy, huh? Anyway, the GUI is developing, and I'll publish .jar when done (and I need to write new Ant script =() &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:40, 21 May 2009 (UTC)<br />
<br />
Ahhh... letters casing is what I've forgot (nano and rozu) Just adding dirty hack about casing. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:45, 21 May 2009 (UTC)<br />
<br />
The [[GuessFactor/Archived Talk 20071112]] had been updated using bot, it look rather fine so if no one comment here, I'll start working around archived talk with above code. Log can be found in [[Special:RecentChanges|Recent Changes]] page [{{fullurl:Special:RecentChanges|hidebots=0}} here] &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:01, 21 May 2009 (UTC)<br />
<br />
I've only briefly examined the code, but it looks OK to me and the test run on [[GuessFactor/Archived Talk 20071112]] worked fine, so I say fire it up. Nice work. --[[User:Voidious|Voidious]] 15:05, 21 May 2009 (UTC)<br />
<br />
There is still a problem with aliases (aka nick). Anyway, when more aliases added to user page redirect category I'll fire it up again. Now I'm firing on the [[:Category:Archived Talk]] category. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:19, 21 May 2009 (UTC)<br />
<br />
And the edit finished. Randomly checks told me that it have no errors, but if ther are any feel free to rollback. [[User:Voidious|Voidious]], asking for your permission, can I fire my bot at full speed? Normally, wiki(pedia) bots will have some throttle delayed to prevent server overload, but I don't think server here will overloaded so I'm asking here. It took me exactly 11 minutes to perform things I just performed.<br />
<br />
Just realize that I forgot to enter edit summary for the bot. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:34, 21 May 2009 (UTC)<br />
<br />
Well, it looks like it only made 4-5 edits per minute, so I don't think you need to add any additional delay. If we ever run this bot (or another) on the server itself, I'd probably want to add a small delay (like 1 second or less) between edits. --[[User:Voidious|Voidious]] 15:46, 21 May 2009 (UTC)<br />
<br />
: Actually it is throttled to the most of 6 edits per minute. (current throttle delay is <code>Thread.sleep(10000 - System.currentTimeMillis() + startTimeMillis)</code>, it comes with the framework) I ask to reducing it to perhaps 5000 or 3000? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 15:52, 21 May 2009 (UTC)<br />
<br />
: Oh, I misunderstood. In that case, full speed (no throttling) would make me a little nervous, but I think 1000 ms (1 second) should be more than enough (so long as we have only one bot, anyway). --[[User:Voidious|Voidious]] 16:02, 21 May 2009 (UTC)<br />
<br />
: Thanks. I fired my bot again, now set throttle to 1000 ms (which make the most of 60 edits per minute, but actually it need a time to fetch the page content/replace text to so it around 30 edits). I now added check if there are any changes before saved. Now it modified all talk pages, archived talk category and discussions category (around 180 pages all) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 07:40, 22 May 2009 (UTC)<br />
<br />
:: Last run rook 14:54.8941 minutes with 119 edits &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 08:13, 22 May 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Skilgannon/Free_Code&diff=16905User:Skilgannon/Free Code2010-07-01T08:38:02Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>This is a neat method that I made up. It takes array of 'indexes' (be it guess factors, or indexes where you are logging hits) between 0 and max and returns a double between 0 and 1 of how 'clustered' your array is. 1 if all the values are the same, and 0 if there are infinite values spread perfectly evenly. Note, this is very different from a standard deviation calculation. In this code there can be as many 'dense' points on the graph as you want, and it won't try to accommodate them all from one mean. Instead, it relies on the fact that <br />
<math> (d+k)^2 + (d-k)^2 > 2 \times d^2 </math><br />
<br />
<syntaxhighlight> <br />
public static double clustering(float[] indexes, float max){<br />
float[] sorted = new float[indexes.length];<br />
System.arraycopy(indexes,0,sorted,0,indexes.length);<br />
java.util.Arrays.sort(sorted);<br />
<br />
double clustering = sorted[0] + max <br />
- sorted[sorted.length - 1];<br />
clustering *= clustering;<br />
<br />
for(int i = 1; i < sorted.length; i++){<br />
double diff = sorted[i] - sorted[i-1];<br />
clustering += diff*diff;<br />
} <br />
return clustering/(max*max);<br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Rsim/Code_snippets&diff=16904User:Rsim/Code snippets2010-07-01T08:37:59Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>== My Bullet Shielding Code Snippet ==<br />
<br />
This is how i check for bullet-hit-bullet collisions. If you find this code useful , have any questions or see ways to improve this code, please tell me :)<br />
<br />
<syntaxhighlight><br />
...<br />
//moveAheadTime is the number of time units before this bot will fire<br />
//moveAheadDistance is the distance (in direction heading) it will have moved during moveAheadTime<br />
Point2D.Double enemyBulletLocation = Util.project(enemyShootingLocation,enemyBulletBearing,moveAheadTime*enemyBulletSpeed);<br />
Point2D.Double shootingLocation = Util.project(bot.location,heading,moveAheadDistance);<br />
for (int t=0;t<timeTillEnemyBulletHitBot-1-moveAheadTime;t++){<br />
// Move enemy bullet location half way<br />
Point2D.Double nextEnemyBulletLocation = Util.project(enemyBulletLocation,enemyBulletBearing,enemyBulletSpeed/2);<br />
double bearing = Util.absoluteBearing(shootingLocation,nextEnemyBulletLocation);<br />
double distance = shootingLocation.distance(nextEnemyBulletLocation);<br />
double optimalPower = (20.0-distance/(t+0.5))/3;<br />
optimalPower = Math.min(MAX_POWER,Math.max(0.1,optimalPower));<br />
double optimalSpeed = Rules.getBulletSpeed(optimalPower);<br />
// Move enemy bullet location half way remaining half way<br />
nextEnemyBulletLocation = Util.project(nextEnemyBulletLocation,enemyBulletBearing,enemyBulletSpeed/2); <br />
Line2D.Double enemyBulletLine = new Line2D.Double(enemyBulletLocation,nextEnemyBulletLocation); <br />
Point2D.Double botBulletLocation = Util.project(shootingLocation,bearing,t*optimalSpeed);<br />
Point2D.Double botNextBulletLocation = Util.project(botBulletLocation,bearing,optimalSpeed);<br />
Line2D.Double botBulletLine = new Line2D.Double(botBulletLocation,botNextBulletLocation);<br />
if(checkIntersection(enemyBulletLine,botBulletLine)){<br />
//we have a bullet-hit-bullet collision. do something useful<br />
...<br />
}<br />
enemyBulletLocation=nextEnemyBulletLocation;<br />
}<br />
...<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Rednaxela/kD-Tree&diff=16903User:Rednaxela/kD-Tree2010-07-01T08:37:58Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>A nice efficient small kD-Tree. Currently the fasted kD-Tree implementation on Robowiki. Feel free to use.<br />
<br />
== Plans ==<br />
<br />
Right now I'm working a rewrite, intended to have cleaner code, follow Java convention better, and be at least as fast. Current plans for the rewrite are:<br />
* '''''Done!''''' <s>'''Cleaner code:''' Follow Java/OOP conventions better, since much that I abandoned in the below code was not necessary for speed.</s><br />
* '''''Done!''''' <s>'''Nearest Neighbor Iterator:''' Provides an iterator to get nearest neighbor. This allows iterated fetching in case one doesn't know exactly how many neighbors one needs (i.e. if some are unusable data points due to other checks). Theoretical speed penalety should be very slim, perhaps even negligible.</s><br />
* '''Further improved speed''': Yes, it's possible! Today I thought of three brand new techniques I should be able to use to increase speed further!<br />
:* '''''Done!''''' <s>'''Flexible path ordering:''' Since 'second choice' paths already have a full distance-to-bounding-box calculation done, why not use this information in order to check the 'paths not yet taken' based that computed distance rather than tree structure. Should be more optimal.</s><br />
:* '''''Unsuccessful. No improvement.''''' <s>'''Dimension-pruned distance calculations:''' With real data, there is often a situation where within a particular node, only some of the dimensions differ between points. It should be simple to track these 'unused' dimensions in a particular node and use this to optimize the distance calculation.</s><br />
:* '''Implicit Subtrees:''' I thought about how I'm using an array to store the 'bucket', and thought "wouldn't it be nice to not have to calculate the distance for every single point in the bucket..." Well, it turns out, that can be avoided, all while keeping it in the nice compact array! It's just a matter of turning the bucket arrays into [[wikipedia:Implicit kd-tree|implicit kd-trees]]! This should keep the advantages of the bucket system for making the incrementally created tree balanced, while at the same time being more efficient!<br />
<br />
I also plan to explore:<br />
* [[wikipedia:R-tree|R-Tree]]/[[wikipedia:X-tree|X-Tree]] type structures. They allow n-ary trees instead of only 2-ary trees like kd-trees, are self-balancing. Might have good results.<br />
* [[wikipedia:VP-tree|VP-Tree]] type structures. Splits based on distance to points may be more effective perhaps.<br />
<br />
If you have any comments on these plans, comments would be appreciated: [[User talk:Rednaxela/kD-Tree]]<br />
<br />
== The Code ==<br />
<br />
<code><syntaxhighlight><br />
/**<br />
* Copyright 2009 Rednaxela<br />
* <br />
* This software is provided 'as-is', without any express or implied<br />
* warranty. In no event will the authors be held liable for any damages<br />
* arising from the use of this software.<br />
* <br />
* Permission is granted to anyone to use this software for any purpose,<br />
* including commercial applications, and to alter it and redistribute it<br />
* freely, subject to the following restrictions:<br />
* <br />
* 1. The origin of this software must not be misrepresented; you must not<br />
* claim that you wrote the original software. If you use this software<br />
* in a product, an acknowledgment in the product documentation would be<br />
* appreciated but is not required.<br />
* <br />
* 2. This notice may not be removed or altered from any source<br />
* distribution.<br />
*/<br />
<br />
package ags.utils;<br />
<br />
import java.util.ArrayList;<br />
import java.util.Arrays;<br />
import java.util.LinkedList;<br />
import java.util.List;<br />
<br />
/**<br />
* An efficient well-optimized kd-tree<br />
* <br />
* @author Rednaxela<br />
*/<br />
public abstract class KdTree<T> {<br />
// Static variables<br />
private static final int bucketSize = 24;<br />
<br />
// All types<br />
private final int dimensions;<br />
private final KdTree<T> parent;<br />
<br />
// Root only<br />
private final LinkedList<double[]> locationStack;<br />
private final Integer sizeLimit;<br />
<br />
// Leaf only<br />
private double[][] locations;<br />
private Object[] data;<br />
private int locationCount;<br />
<br />
// Stem only<br />
private KdTree<T> left, right;<br />
private int splitDimension;<br />
private double splitValue;<br />
<br />
// Bounds<br />
private double[] minLimit, maxLimit;<br />
private boolean singularity;<br />
<br />
// Temporary<br />
private Status status;<br />
<br />
/**<br />
* Construct a KdTree with a given number of dimensions and a limit on<br />
* maxiumum size (after which it throws away old points)<br />
*/<br />
private KdTree(int dimensions, Integer sizeLimit) {<br />
this.dimensions = dimensions;<br />
<br />
// Init as leaf<br />
this.locations = new double[bucketSize][];<br />
this.data = new Object[bucketSize];<br />
this.locationCount = 0;<br />
this.singularity = true;<br />
<br />
// Init as root<br />
this.parent = null;<br />
this.sizeLimit = sizeLimit;<br />
if (sizeLimit != null) {<br />
this.locationStack = new LinkedList<double[]>();<br />
}<br />
else {<br />
this.locationStack = null;<br />
}<br />
}<br />
<br />
/**<br />
* Constructor for child nodes. Internal use only.<br />
*/<br />
private KdTree(KdTree<T> parent, boolean right) {<br />
this.dimensions = parent.dimensions;<br />
<br />
// Init as leaf<br />
this.locations = new double[Math.max(bucketSize, parent.locationCount)][];<br />
this.data = new Object[Math.max(bucketSize, parent.locationCount)];<br />
this.locationCount = 0;<br />
this.singularity = true;<br />
<br />
// Init as non-root<br />
this.parent = parent;<br />
this.locationStack = null;<br />
this.sizeLimit = null;<br />
}<br />
<br />
/**<br />
* Get the number of points in the tree<br />
*/<br />
public int size() {<br />
return locationCount;<br />
}<br />
<br />
/**<br />
* Add a point and associated value to the tree<br />
*/<br />
public void addPoint(double[] location, T value) {<br />
KdTree<T> cursor = this;<br />
<br />
while (cursor.locations == null || cursor.locationCount >= cursor.locations.length) {<br />
if (cursor.locations != null) {<br />
cursor.splitDimension = cursor.findWidestAxis();<br />
cursor.splitValue = (cursor.minLimit[cursor.splitDimension] + cursor.maxLimit[cursor.splitDimension]) * 0.5;<br />
<br />
// Never split on infinity or NaN<br />
if (cursor.splitValue == Double.POSITIVE_INFINITY) {<br />
cursor.splitValue = Double.MAX_VALUE;<br />
}<br />
else if (cursor.splitValue == Double.NEGATIVE_INFINITY) {<br />
cursor.splitValue = -Double.MAX_VALUE;<br />
}<br />
else if (Double.isNaN(cursor.splitValue)) {<br />
cursor.splitValue = 0;<br />
}<br />
<br />
// Don't split node if it has no width in any axis. Double the<br />
// bucket size instead<br />
if (cursor.minLimit[cursor.splitDimension] == cursor.maxLimit[cursor.splitDimension]) {<br />
double[][] newLocations = new double[cursor.locations.length * 2][];<br />
System.arraycopy(cursor.locations, 0, newLocations, 0, cursor.locationCount);<br />
cursor.locations = newLocations;<br />
Object[] newData = new Object[newLocations.length];<br />
System.arraycopy(cursor.data, 0, newData, 0, cursor.locationCount);<br />
cursor.data = newData;<br />
break;<br />
}<br />
<br />
// Don't let the split value be the same as the upper value as<br />
// can happen due to rounding errors!<br />
if (cursor.splitValue == cursor.maxLimit[cursor.splitDimension]) {<br />
cursor.splitValue = cursor.minLimit[cursor.splitDimension];<br />
}<br />
<br />
// Create child leaves<br />
KdTree<T> left = new ChildNode(cursor, false);<br />
KdTree<T> right = new ChildNode(cursor, true);<br />
<br />
// Move locations into children<br />
for (int i = 0; i < cursor.locationCount; i++) {<br />
double[] oldLocation = cursor.locations[i];<br />
Object oldData = cursor.data[i];<br />
if (oldLocation[cursor.splitDimension] > cursor.splitValue) {<br />
// Right<br />
right.locations[right.locationCount] = oldLocation;<br />
right.data[right.locationCount] = oldData;<br />
right.locationCount++;<br />
right.extendBounds(oldLocation);<br />
}<br />
else {<br />
// Left<br />
left.locations[left.locationCount] = oldLocation;<br />
left.data[left.locationCount] = oldData;<br />
left.locationCount++;<br />
left.extendBounds(oldLocation);<br />
}<br />
}<br />
<br />
// Make into stem<br />
cursor.left = left;<br />
cursor.right = right;<br />
cursor.locations = null;<br />
cursor.data = null;<br />
}<br />
<br />
cursor.locationCount++;<br />
cursor.extendBounds(location);<br />
<br />
if (location[cursor.splitDimension] > cursor.splitValue) {<br />
cursor = cursor.right;<br />
}<br />
else {<br />
cursor = cursor.left;<br />
}<br />
}<br />
<br />
cursor.locations[cursor.locationCount] = location;<br />
cursor.data[cursor.locationCount] = value;<br />
cursor.locationCount++;<br />
cursor.extendBounds(location);<br />
<br />
if (this.sizeLimit != null) {<br />
this.locationStack.add(location);<br />
if (this.locationCount > this.sizeLimit) {<br />
this.removeOld();<br />
}<br />
}<br />
}<br />
<br />
/**<br />
* Extends the bounds of this node do include a new location<br />
*/<br />
private final void extendBounds(double[] location) {<br />
if (minLimit == null) {<br />
minLimit = new double[dimensions];<br />
System.arraycopy(location, 0, minLimit, 0, dimensions);<br />
maxLimit = new double[dimensions];<br />
System.arraycopy(location, 0, maxLimit, 0, dimensions);<br />
return;<br />
}<br />
<br />
for (int i = 0; i < dimensions; i++) {<br />
if (Double.isNaN(location[i])) {<br />
minLimit[i] = Double.NaN;<br />
maxLimit[i] = Double.NaN;<br />
singularity = false;<br />
}<br />
else if (minLimit[i] > location[i]) {<br />
minLimit[i] = location[i];<br />
singularity = false;<br />
}<br />
else if (maxLimit[i] < location[i]) {<br />
maxLimit[i] = location[i];<br />
singularity = false;<br />
}<br />
}<br />
}<br />
<br />
/**<br />
* Find the widest axis of the bounds of this node<br />
*/<br />
private final int findWidestAxis() {<br />
int widest = 0;<br />
double width = (maxLimit[0] - minLimit[0]) * getAxisWeightHint(0);<br />
if (Double.isNaN(width)) width = 0;<br />
for (int i = 1; i < dimensions; i++) {<br />
double nwidth = (maxLimit[i] - minLimit[i]) * getAxisWeightHint(i);<br />
if (Double.isNaN(nwidth)) nwidth = 0;<br />
if (nwidth > width) {<br />
widest = i;<br />
width = nwidth;<br />
}<br />
}<br />
return widest;<br />
}<br />
<br />
/**<br />
* Remove the oldest value from the tree. Note: This cannot trim the bounds<br />
* of nodes, nor empty nodes, and thus you can't expect it to perfectly<br />
* preserve the speed of the tree as you keep adding.<br />
*/<br />
private void removeOld() {<br />
double[] location = this.locationStack.removeFirst();<br />
KdTree<T> cursor = this;<br />
<br />
// Find the node where the point is<br />
while (cursor.locations == null) {<br />
if (location[cursor.splitDimension] > cursor.splitValue) {<br />
cursor = cursor.right;<br />
}<br />
else {<br />
cursor = cursor.left;<br />
}<br />
}<br />
<br />
for (int i = 0; i < cursor.locationCount; i++) {<br />
if (cursor.locations[i] == location) {<br />
System.arraycopy(cursor.locations, i + 1, cursor.locations, i, cursor.locationCount - i - 1);<br />
cursor.locations[cursor.locationCount-1] = null;<br />
System.arraycopy(cursor.data, i + 1, cursor.data, i, cursor.locationCount - i - 1);<br />
cursor.data[cursor.locationCount-1] = null;<br />
do {<br />
cursor.locationCount--;<br />
cursor = cursor.parent;<br />
} while (cursor.parent != null);<br />
return;<br />
}<br />
}<br />
// If we got here... we couldn't find the value to remove. Weird...<br />
}<br />
<br />
/**<br />
* Enumeration representing the status of a node during the running<br />
*/<br />
private static enum Status {<br />
NONE, LEFTVISITED, RIGHTVISITED, ALLVISITED<br />
}<br />
<br />
/**<br />
* Stores a distance and value to output<br />
*/<br />
public static class Entry<T> {<br />
public final double distance;<br />
public final T value;<br />
<br />
private Entry(double distance, T value) {<br />
this.distance = distance;<br />
this.value = value;<br />
}<br />
}<br />
<br />
/**<br />
* Calculates the nearest 'count' points to 'location'<br />
*/<br />
@SuppressWarnings("unchecked")<br />
public List<Entry<T>> nearestNeighbor(double[] location, int count, boolean sequentialSorting) {<br />
KdTree<T> cursor = this;<br />
cursor.status = Status.NONE;<br />
double range = Double.POSITIVE_INFINITY;<br />
ResultHeap resultHeap = new ResultHeap(count);<br />
<br />
do {<br />
if (cursor.status == Status.ALLVISITED) {<br />
// At a fully visited part. Move up the tree<br />
cursor = cursor.parent;<br />
continue;<br />
}<br />
<br />
if (cursor.status == Status.NONE && cursor.locations != null) {<br />
// At a leaf. Use the data.<br />
if (cursor.locationCount > 0) {<br />
if (cursor.singularity) {<br />
double dist = pointDist(cursor.locations[0], location);<br />
if (dist <= range) {<br />
for (int i = 0; i < cursor.locationCount; i++) {<br />
resultHeap.addValue(dist, cursor.data[i]);<br />
}<br />
}<br />
}<br />
else {<br />
for (int i = 0; i < cursor.locationCount; i++) {<br />
double dist = pointDist(cursor.locations[i], location);<br />
resultHeap.addValue(dist, cursor.data[i]);<br />
}<br />
}<br />
range = resultHeap.getMaxDist();<br />
}<br />
<br />
if (cursor.parent == null) {<br />
break;<br />
}<br />
cursor = cursor.parent;<br />
continue;<br />
}<br />
<br />
// Going to descend<br />
KdTree<T> nextCursor = null;<br />
if (cursor.status == Status.NONE) {<br />
// At a fresh node, descend the most probably useful direction<br />
if (location[cursor.splitDimension] > cursor.splitValue) {<br />
// Descend right<br />
nextCursor = cursor.right;<br />
cursor.status = Status.RIGHTVISITED;<br />
}<br />
else {<br />
// Descend left;<br />
nextCursor = cursor.left;<br />
cursor.status = Status.LEFTVISITED;<br />
}<br />
}<br />
else if (cursor.status == Status.LEFTVISITED) {<br />
// Left node visited, descend right.<br />
nextCursor = cursor.right;<br />
cursor.status = Status.ALLVISITED;<br />
}<br />
else if (cursor.status == Status.RIGHTVISITED) {<br />
// Right node visited, descend left.<br />
nextCursor = cursor.left;<br />
cursor.status = Status.ALLVISITED;<br />
}<br />
<br />
// Check if it's worth descending. Assume it is if it's sibling has<br />
// not been visited yet.<br />
if (cursor.status == Status.ALLVISITED) {<br />
if (nextCursor.locationCount == 0<br />
|| (!nextCursor.singularity && pointRegionDist(location, nextCursor.minLimit,<br />
nextCursor.maxLimit) > range)) {<br />
continue;<br />
}<br />
}<br />
<br />
// Descend down the tree<br />
cursor = nextCursor;<br />
cursor.status = Status.NONE;<br />
} while (cursor.parent != null || cursor.status != Status.ALLVISITED);<br />
<br />
ArrayList<Entry<T>> results = new ArrayList<Entry<T>>(resultHeap.values);<br />
if (sequentialSorting) {<br />
while (resultHeap.values > 0) {<br />
resultHeap.removeLargest();<br />
results.add(new Entry<T>(resultHeap.removedDist, (T)resultHeap.removedData));<br />
}<br />
}<br />
else {<br />
for (int i = 0; i < resultHeap.values; i++) {<br />
results.add(new Entry<T>(resultHeap.distance[i], (T)resultHeap.data[i]));<br />
}<br />
}<br />
<br />
return results;<br />
}<br />
<br />
// Override in subclasses<br />
protected abstract double pointDist(double[] p1, double[] p2);<br />
<br />
protected abstract double pointRegionDist(double[] point, double[] min, double[] max);<br />
<br />
protected double getAxisWeightHint(int i) {<br />
return 1.0;<br />
}<br />
<br />
/**<br />
* Internal class for child nodes<br />
*/<br />
private class ChildNode extends KdTree<T> {<br />
private ChildNode(KdTree<T> parent, boolean right) {<br />
super(parent, right);<br />
}<br />
<br />
// Distance measurements are always called from the root node<br />
protected double pointDist(double[] p1, double[] p2) {<br />
throw new IllegalStateException();<br />
}<br />
<br />
protected double pointRegionDist(double[] point, double[] min, double[] max) {<br />
throw new IllegalStateException();<br />
}<br />
}<br />
<br />
/**<br />
* Class for tree with Weighted Squared Euclidean distancing<br />
*/<br />
public static class WeightedSqrEuclid<T> extends KdTree<T> {<br />
private double[] weights;<br />
<br />
public WeightedSqrEuclid(int dimensions, Integer sizeLimit) {<br />
super(dimensions, sizeLimit);<br />
this.weights = new double[dimensions];<br />
Arrays.fill(this.weights, 1.0);<br />
}<br />
<br />
public void setWeights(double[] weights) {<br />
this.weights = weights;<br />
}<br />
<br />
protected double getAxisWeightHint(int i) {<br />
return weights[i];<br />
}<br />
<br />
protected double pointDist(double[] p1, double[] p2) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < p1.length; i++) {<br />
double diff = (p1[i] - p2[i]) * weights[i];<br />
if (!Double.isNaN(diff)) {<br />
d += diff * diff;<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
<br />
protected double pointRegionDist(double[] point, double[] min, double[] max) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < point.length; i++) {<br />
double diff = 0;<br />
if (point[i] > max[i]) {<br />
diff = (point[i] - max[i]) * weights[i];<br />
}<br />
else if (point[i] < min[i]) {<br />
diff = (point[i] - min[i]) * weights[i];<br />
}<br />
<br />
if (!Double.isNaN(diff)) {<br />
d += diff * diff;<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
}<br />
<br />
/**<br />
* Class for tree with Unweighted Squared Euclidean distancing<br />
*/<br />
public static class SqrEuclid<T> extends KdTree<T> {<br />
public SqrEuclid(int dimensions, Integer sizeLimit) {<br />
super(dimensions, sizeLimit);<br />
}<br />
<br />
protected double pointDist(double[] p1, double[] p2) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < p1.length; i++) {<br />
double diff = (p1[i] - p2[i]);<br />
if (!Double.isNaN(diff)) {<br />
d += diff * diff;<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
<br />
protected double pointRegionDist(double[] point, double[] min, double[] max) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < point.length; i++) {<br />
double diff = 0;<br />
if (point[i] > max[i]) {<br />
diff = (point[i] - max[i]);<br />
}<br />
else if (point[i] < min[i]) {<br />
diff = (point[i] - min[i]);<br />
}<br />
<br />
if (!Double.isNaN(diff)) {<br />
d += diff * diff;<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
}<br />
<br />
/**<br />
* Class for tree with Weighted Manhattan distancing<br />
*/<br />
public static class WeightedManhattan<T> extends KdTree<T> {<br />
private double[] weights;<br />
<br />
public WeightedManhattan(int dimensions, Integer sizeLimit) {<br />
super(dimensions, sizeLimit);<br />
this.weights = new double[dimensions];<br />
Arrays.fill(this.weights, 1.0);<br />
}<br />
<br />
public void setWeights(double[] weights) {<br />
this.weights = weights;<br />
}<br />
<br />
protected double getAxisWeightHint(int i) {<br />
return weights[i];<br />
}<br />
<br />
protected double pointDist(double[] p1, double[] p2) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < p1.length; i++) {<br />
double diff = (p1[i] - p2[i]);<br />
if (!Double.isNaN(diff)) {<br />
d += ((diff < 0) ? -diff : diff) * weights[i];<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
<br />
protected double pointRegionDist(double[] point, double[] min, double[] max) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < point.length; i++) {<br />
double diff = 0;<br />
if (point[i] > max[i]) {<br />
diff = (point[i] - max[i]);<br />
}<br />
else if (point[i] < min[i]) {<br />
diff = (min[i] - point[i]);<br />
}<br />
<br />
if (!Double.isNaN(diff)) {<br />
d += diff * weights[i];<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
}<br />
<br />
/**<br />
* Class for tree with Manhattan distancing<br />
*/<br />
public static class Manhattan<T> extends KdTree<T> {<br />
public Manhattan(int dimensions, Integer sizeLimit) {<br />
super(dimensions, sizeLimit);<br />
}<br />
<br />
protected double pointDist(double[] p1, double[] p2) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < p1.length; i++) {<br />
double diff = (p1[i] - p2[i]);<br />
if (!Double.isNaN(diff)) {<br />
d += (diff < 0) ? -diff : diff;<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
<br />
protected double pointRegionDist(double[] point, double[] min, double[] max) {<br />
double d = 0;<br />
<br />
for (int i = 0; i < point.length; i++) {<br />
double diff = 0;<br />
if (point[i] > max[i]) {<br />
diff = (point[i] - max[i]);<br />
}<br />
else if (point[i] < min[i]) {<br />
diff = (min[i] - point[i]);<br />
}<br />
<br />
if (!Double.isNaN(diff)) {<br />
d += diff;<br />
}<br />
}<br />
<br />
return d;<br />
}<br />
}<br />
<br />
/**<br />
* Class for tracking up to 'size' closest values<br />
*/<br />
private static class ResultHeap {<br />
private final Object[] data;<br />
private final double[] distance;<br />
private final int size;<br />
private int values;<br />
public Object removedData;<br />
public double removedDist;<br />
<br />
public ResultHeap(int size) {<br />
this.data = new Object[size];<br />
this.distance = new double[size];<br />
this.size = size;<br />
this.values = 0;<br />
}<br />
<br />
public void addValue(double dist, Object value) {<br />
// If there is still room in the heap<br />
if (values < size) {<br />
// Insert new value at the end<br />
data[values] = value;<br />
distance[values] = dist;<br />
upHeapify(values);<br />
values++;<br />
}<br />
// If there is no room left in the heap, and the new entry is lower<br />
// than the max entry<br />
else if (dist < distance[0]) {<br />
// Replace the max entry with the new entry<br />
data[0] = value;<br />
distance[0] = dist;<br />
downHeapify(0);<br />
}<br />
}<br />
<br />
public void removeLargest() {<br />
if (values == 0) {<br />
throw new IllegalStateException();<br />
}<br />
<br />
removedData = data[0];<br />
removedDist = distance[0];<br />
values--;<br />
data[0] = data[values];<br />
distance[0] = distance[values];<br />
downHeapify(0);<br />
}<br />
<br />
private void upHeapify(int c) {<br />
for (int p = (c - 1) / 2; c != 0 && distance[c] > distance[p]; c = p, p = (c - 1) / 2) {<br />
Object pData = data[p];<br />
double pDist = distance[p];<br />
data[p] = data[c];<br />
distance[p] = distance[c];<br />
data[c] = pData;<br />
distance[c] = pDist;<br />
}<br />
}<br />
<br />
private void downHeapify(int p) {<br />
for (int c = p * 2 + 1; c < values; p = c, c = p * 2 + 1) {<br />
if (c + 1 < values && distance[c] < distance[c + 1]) {<br />
c++;<br />
}<br />
if (distance[p] < distance[c]) {<br />
// Swap the points<br />
Object pData = data[p];<br />
double pDist = distance[p];<br />
data[p] = data[c];<br />
distance[p] = distance[c];<br />
data[c] = pData;<br />
distance[c] = pDist;<br />
}<br />
else {<br />
break;<br />
}<br />
}<br />
}<br />
<br />
public double getMaxDist() {<br />
if (values < size) {<br />
return Double.POSITIVE_INFINITY;<br />
}<br />
return distance[0];<br />
}<br />
}<br />
}<br />
<br />
</syntaxhighlight></code></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Rednaxela/BotBase&diff=16902User:Rednaxela/BotBase2010-07-01T08:37:52Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>This is a class I've been basing all of my recent non-codesize-restricted bots off of.<br />
<br />
'''Note:''' This is somewhat out-of-date. I plan to update it some time.<br />
<br />
== BotBase.java ==<br />
<syntaxhighlight>package ags.muse.base;<br />
<br />
import ags.muse.base.actors.*;<br />
<br />
import java.awt.Color;<br />
import java.awt.Graphics2D;<br />
import java.util.ArrayList;<br />
import java.util.List;<br />
<br />
import robocode.BulletHitBulletEvent;<br />
import robocode.BulletHitEvent;<br />
import robocode.BulletMissedEvent;<br />
import robocode.CustomEvent;<br />
import robocode.DeathEvent;<br />
import robocode.Event;<br />
import robocode.HitByBulletEvent;<br />
import robocode.HitRobotEvent;<br />
import robocode.HitWallEvent;<br />
import robocode.MessageEvent;<br />
import robocode.RobotDeathEvent;<br />
import robocode.ScannedRobotEvent;<br />
import robocode.SkippedTurnEvent;<br />
import robocode.StatusEvent;<br />
import robocode.WinEvent;<br />
import robocode.TeamRobot;<br />
<br />
/**<br />
* @author Alexander Schultz<br />
*/<br />
abstract public class BotBase extends TeamRobot {<br />
private Rules rules;<br />
private GunActor gunActor;<br />
private MovementActor movementActor;<br />
private RadarActor radarActor;<br />
private BroadcastActor broadcastActor;<br />
<br />
public Rules getRules() {<br />
return rules;<br />
}<br />
<br />
public GunActor getGunActor() {<br />
return gunActor;<br />
}<br />
<br />
public MovementActor getMovementActor() {<br />
return movementActor;<br />
}<br />
<br />
public RadarActor getRadarActor() {<br />
return radarActor;<br />
}<br />
<br />
public BroadcastActor getBroadcastActor() {<br />
return broadcastActor;<br />
}<br />
<br />
private final List<Event> events = new ArrayList<Event>();<br />
<br />
private List<Event> getEvents() {<br />
List<Event> output = new ArrayList<Event>(events);<br />
events.clear();<br />
return output;<br />
}<br />
<br />
public void onCustomEvent(CustomEvent arg0) { events.add(arg0); }<br />
public void onMessageReceived(MessageEvent arg0) { events.add(arg0); }<br />
public void onBulletHit(BulletHitEvent arg0) { events.add(arg0); }<br />
public void onBulletHitBullet(BulletHitBulletEvent arg0) { events.add(arg0); }<br />
public void onBulletMissed(BulletMissedEvent arg0) { events.add(arg0); }<br />
public void onDeath(DeathEvent arg0) { events.add(arg0); }<br />
public void onHitByBullet(HitByBulletEvent arg0) { events.add(arg0); }<br />
public void onHitRobot(HitRobotEvent arg0) { events.add(arg0); }<br />
public void onHitWall(HitWallEvent arg0) { events.add(arg0); }<br />
public void onRobotDeath(RobotDeathEvent arg0) { events.add(arg0); }<br />
public void onScannedRobot(ScannedRobotEvent arg0) { events.add(arg0); }<br />
public void onStatus(StatusEvent arg0) { events.add(arg0); }<br />
public void onWin(WinEvent arg0) { events.add(arg0); }<br />
public void onSkippedTurn(SkippedTurnEvent arg0) {<br />
events.add(arg0);<br />
System.out.println("Warning! Turn skipped!");<br />
}<br />
<br />
// Echo broadcast messages back to self<br />
@Override<br />
public void broadcastMessage(java.io.Serializable s) throws java.io.IOException {<br />
super.broadcastMessage(s);<br />
events.add(new MessageEvent(rules.NAME, s));<br />
}<br />
<br />
public void setColors(final Color bodyColor, final Color scanColor, final Color gunColor, final Color radarColor) {<br />
if (!running)<br />
throw new UnsupportedOperationException("Bot must be running before colors may be set.");<br />
<br />
this.setBodyColor(bodyColor);<br />
this.setScanColor(scanColor);<br />
this.setGunColor(gunColor);<br />
this.setRadarColor(radarColor);<br />
}<br />
<br />
abstract public void init();<br />
abstract public void runTick(List<Event> events);<br />
abstract public void _onPaint(Graphics2D g);<br />
<br />
private final void preInit() {<br />
// Set turning to be independent<br />
this.setAdjustGunForRobotTurn(true);<br />
this.setAdjustRadarForRobotTurn(true);<br />
this.setAdjustRadarForGunTurn(true);<br />
<br />
// Set up rules class<br />
rules = new Rules(this);<br />
<br />
// Start up staticsaver<br />
StaticSaver.init(this);<br />
<br />
// Set up actors<br />
gunActor = new GunActor(this);<br />
movementActor = new MovementActor(this);<br />
radarActor = new RadarActor(this);<br />
broadcastActor = new BroadcastActor(this);<br />
}<br />
<br />
private void ensureVersion() {<br />
if (getTime() < 2) {<br />
boolean gotstatus = false;<br />
for (Event event : events) {<br />
if (event instanceof robocode.StatusEvent)<br />
gotstatus = true;<br />
if (event instanceof robocode.DeathEvent)<br />
gotstatus = true;<br />
if (event instanceof robocode.WinEvent)<br />
gotstatus = true;<br />
}<br />
// If we didn't get a StatusEvent DeathEvent, or WinEvent something is wrong... (i.e. very old robocode version)<br />
if (!gotstatus) {<br />
System.out.println("Got no status event! Dying now! :(");<br />
while (true);<br />
}<br />
}<br />
}<br />
<br />
private boolean running = false;<br />
@Override<br />
public void run() {<br />
if (running)<br />
throw new UnsupportedOperationException("Main loop already running!");<br />
<br />
running = true;<br />
<br />
preInit();<br />
<br />
init();<br />
<br />
while(true) {<br />
if (events.size() != 0) {<br />
ensureVersion();<br />
runTick(getEvents());<br />
}<br />
execute();<br />
}<br />
}<br />
<br />
@Override<br />
public void onPaint(Graphics2D g) {<br />
if (events.size() != 0) {<br />
ensureVersion();<br />
runTick(getEvents());<br />
}<br />
_onPaint(g);<br />
}<br />
}</syntaxhighlight><br />
<br />
== Rules.java ==<br />
<syntaxhighlight>package ags.muse.base;<br />
<br />
import robocode.TeamRobot;<br />
<br />
/**<br />
* A consoladated "Rules" class, which includes gun cooling rate, field size,<br />
* teammate listings, and always uses radians.<br />
* <br />
* Essentially stores all battle information that is known from the very start<br />
* of the battle that does not change.<br />
* <br />
* @author Alexander Schultz<br />
*/<br />
public class Rules {<br />
// Redirection to robocode.Rules<br />
public final double ACCELERATION = robocode.Rules.ACCELERATION;<br />
public final double DECELERATION = robocode.Rules.DECELERATION;<br />
public final double GUN_TURN_RATE = robocode.Rules.GUN_TURN_RATE_RADIANS;<br />
public final double MAX_BULLET_POWER = robocode.Rules.MAX_BULLET_POWER;<br />
public final double MAX_TURN_RATE = robocode.Rules.MAX_TURN_RATE_RADIANS;<br />
public final double MAX_VELOCITY = robocode.Rules.MAX_VELOCITY;<br />
public final double MIN_BULLET_POWER = robocode.Rules.MIN_BULLET_POWER;<br />
public final double RADAR_SCAN_RADIUS = robocode.Rules.RADAR_SCAN_RADIUS;<br />
public final double RADAR_TURN_RATE = robocode.Rules.RADAR_TURN_RATE_RADIANS;<br />
public final double ROBOT_HIT_BONUS = robocode.Rules.ROBOT_HIT_BONUS;<br />
public final double ROBOT_HIT_DAMAGE = robocode.Rules.ROBOT_HIT_DAMAGE;<br />
public double getBulletDamage(double bulletPower) { return robocode.Rules.getBulletDamage(bulletPower); }<br />
public double getBulletHitBonus(double bulletPower) { return robocode.Rules.getBulletHitBonus(bulletPower); }<br />
public double getBulletSpeed(double bulletPower) { return robocode.Rules.getBulletSpeed(bulletPower); }<br />
public double getGunHeat(double bulletPower) { return robocode.Rules.getGunHeat(bulletPower); }<br />
public double getTurnRate(double velocity) { return robocode.Rules.getTurnRateRadians(velocity); }<br />
public double getWallHitDamage(double velocity) { return robocode.Rules.getWallHitDamage(velocity); }<br />
<br />
// New features<br />
public final double GUN_COOLING_RATE;<br />
public final double BATTLEFIELD_WIDTH;<br />
public final double BATTLEFIELD_HEIGHT;<br />
public final String[] TEAMMATES;<br />
public final int ENEMIES;<br />
public final String NAME;<br />
<br />
public Rules(TeamRobot peer) {<br />
GUN_COOLING_RATE = peer.getGunCoolingRate();<br />
BATTLEFIELD_WIDTH = peer.getBattleFieldWidth();<br />
BATTLEFIELD_HEIGHT = peer.getBattleFieldHeight();<br />
if (peer.getTeammates() != null)<br />
TEAMMATES = peer.getTeammates();<br />
else<br />
TEAMMATES = new String[0];<br />
NAME = peer.getName();<br />
ENEMIES = peer.getOthers()-TEAMMATES.length;<br />
}<br />
<br />
public boolean isTeammate(String name) {<br />
if (TEAMMATES == null)<br />
return false;<br />
for (String teammate : TEAMMATES) {<br />
if (teammate.equals(name)) return true;<br />
}<br />
return false;<br />
}<br />
<br />
public double damageToBulletPower(double energy) {<br />
if (energy/4 <= 1)<br />
return energy/4;<br />
else<br />
return (energy+2)/6;<br />
}<br />
<br />
public double getHitRegneration(double bulletPower) {<br />
return 3*bulletPower; <br />
}<br />
}</syntaxhighlight><br />
<br />
== StaticSaver.java ==<br />
<syntaxhighlight>package ags.muse.base;<br />
<br />
import java.io.File;<br />
import java.io.FileInputStream;<br />
import java.io.IOException;<br />
<br />
import robocode.AdvancedRobot;<br />
import robocode.RobocodeFileOutputStream;<br />
<br />
public class StaticSaver {<br />
private static File dataDirectory;<br />
<br />
public static void init(AdvancedRobot bot) {<br />
dataDirectory = bot.getDataDirectory();<br />
System.out.println("Bot data directory:");<br />
System.out.print("\t");<br />
System.out.println(dataDirectory.getAbsolutePath());<br />
}<br />
<br />
public static RobocodeFileOutputStream getOutputFile(String filename, boolean append) throws IOException {<br />
if (dataDirectory == null)<br />
throw new java.lang.IllegalStateException();<br />
File file = new File(dataDirectory, filename);<br />
RobocodeFileOutputStream fileWriter = new RobocodeFileOutputStream(file.getPath(), append);<br />
return fileWriter;<br />
}<br />
<br />
public static FileInputStream getInputFile(String filename) throws IOException {<br />
if (dataDirectory == null)<br />
throw new java.lang.IllegalStateException();<br />
File file = new File(dataDirectory, filename);<br />
return new FileInputStream(file);<br />
}<br />
}</syntaxhighlight><br />
<br />
== BroadcastActor.java ==<br />
<br />
<syntaxhighlight>package ags.muse.base.actors;<br />
<br />
import robocode.TeamRobot;<br />
<br />
public class BroadcastActor {<br />
private final TeamRobot peer;<br />
<br />
public BroadcastActor(TeamRobot peer) {<br />
this.peer = peer;<br />
}<br />
<br />
public void broadcastMessage(java.io.Serializable s) {<br />
try {<br />
peer.broadcastMessage(s);<br />
} catch (java.io.IOException e) {<br />
System.out.println("Error during sending team message!");<br />
e.printStackTrace();<br />
}<br />
}<br />
}</syntaxhighlight><br />
<br />
== GunActor.java ==<br />
<syntaxhighlight>package ags.muse.base.actors;<br />
<br />
import robocode.Bullet;<br />
import robocode.TeamRobot;<br />
<br />
public class GunActor {<br />
private final TeamRobot peer;<br />
<br />
public GunActor(TeamRobot peer) {<br />
this.peer = peer;<br />
}<br />
<br />
public Bullet setFire(double arg0) {<br />
return peer.setFireBullet(arg0);<br />
}<br />
<br />
public void setTurnGun(double arg0) {<br />
peer.setTurnGunRightRadians(arg0);<br />
}<br />
}</syntaxhighlight><br />
<br />
== MovementActor.java ==<br />
<syntaxhighlight>package ags.muse.base.actors;<br />
<br />
import robocode.TeamRobot;<br />
<br />
public class MovementActor {<br />
private final TeamRobot peer;<br />
<br />
public MovementActor(TeamRobot peer) {<br />
this.peer = peer;<br />
}<br />
<br />
public void setMove(double velocity) {<br />
setMove(velocity, velocity==0 ? 0 : (velocity > 0 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY));<br />
}<br />
<br />
public void setMove(double velocity, double dist) {<br />
peer.setMaxVelocity(Math.abs(velocity));<br />
peer.setAhead(dist);<br />
}<br />
public void setTurnBody(double arg0) {<br />
peer.setTurnRightRadians(arg0);<br />
}<br />
}</syntaxhighlight><br />
<br />
== RadarActor.java ==<br />
<syntaxhighlight>package ags.muse.base.actors;<br />
<br />
import robocode.TeamRobot;<br />
<br />
public class RadarActor {<br />
private final TeamRobot peer;<br />
<br />
public RadarActor(TeamRobot peer) {<br />
this.peer = peer;<br />
}<br />
<br />
public void setTurnRadar(double arg0) {<br />
peer.setTurnRadarRightRadians(arg0);<br />
}<br />
}</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Positive/Optimal_Velocity&diff=16901User:Positive/Optimal Velocity2010-07-01T08:37:48Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>To not clutter up the [[Talk:Robocode/Game Physics]] page:<br />
<br />
I believe this is the correct getClosestReachableVelocityToVelocity function (feel free to comment):<br />
<br />
<syntaxhighlight><br />
double getClosestReachableVelocityToVelocity(double currentVelocity,double wantedVelocity)<br />
{<br />
// this function assumes wantedVelocity<=Rules.MAXVELOCITY<br />
// with this function you can basically assume setAhead(Infinity) or setAhead(-Infinity)<br />
// was called, and you determine the next velocity based on the max velocity<br />
// set by the robot. For example, if the current velocity is 0 and the max velocity<br />
// set was 4.0, it would return 1.0. If the current velocity was 8.0, it would return 6.0.<br />
if(wantedVelocity<0)<br />
return -getClosestReachableVelocityToVelocity(-currentVelocity,-wantedVelocity);<br />
if(currentVelocity<0)<br />
{<br />
double nextVelocity;<br />
// we are travelling the wrong way, decelerate<br />
nextVelocity = currentVelocity + Rules.DECELERATION;<br />
if(nextVelocity>Rules.ACCELERATION)<br />
// make sure we can't jump from -0.1 to 1.9 or something<br />
nextVelocity = Rules.ACCELERATION;<br />
if(nextVelocity>wantedVelocity)<br />
// if the wanted velocity is for example 0.5, limit the velocity to that.<br />
return wantedVelocity;<br />
else<br />
// else return the highest possible<br />
return nextVelocity;<br />
}<br />
else<br />
{<br />
if(currentVelocity>wantedVelocity)<br />
{<br />
// both velocities are positive, but we need to decelerate<br />
double nextVelocity = currentVelocity - Rules.DECELERATION;<br />
if(nextVelocity<wantedVelocity)<br />
// if we can decelerate more than what's wanted, return what's wanted<br />
return wantedVelocity;<br />
else<br />
// else return the closest to it<br />
return nextVelocity;<br />
}<br />
else<br />
{<br />
// the wantedVelocity is higher than current<br />
double nextVelocity = currentVelocity + Rules.ACCELERATION;<br />
if(nextVelocity>wantedVelocity)<br />
// if we can accelerate more than what's wanted, return what's wanted<br />
return wantedVelocity;<br />
else<br />
// else return the closest to it<br />
return nextVelocity;<br />
}<br />
}<br />
} <br />
</syntaxhighlight><br />
<br />
getMaxVelocity function by Voidious:<br />
<syntaxhighlight><br />
double getMaxVelocity(double distance)<br />
{<br />
if(distance>=20) // temporary fix, works for maxVelocity==8.0 && maxDecel==2.0<br />
return Rules.MAX_VELOCITY;<br />
long decelTime = decelTime(distance);<br />
double decelDist = (decelTime / 2.0) * (decelTime-1) // sum of 0..(decelTime-1)<br />
* Rules.DECELERATION;<br />
<br />
return ((decelTime - 1) * Rules.DECELERATION) +<br />
((distance - decelDist) / decelTime);<br />
}<br />
<br />
long decelTime(double distance) {<br />
long x = 1;<br />
do {<br />
// (square(x) + x) / 2) = 1, 3, 6, 10, 15...<br />
if (distance <= ((square(x) + x) / 2) * Rules.DECELERATION) {<br />
return x;<br />
}<br />
x++;<br />
} while (true);<br />
}<br />
<br />
long square(long i) {<br />
return i * i;<br />
}<br />
</syntaxhighlight><br />
<br />
The getNewVelocity function:<br />
<syntaxhighlight><br />
double getNewVelocity(double velocity, double distance) {<br />
if(distance<0)<br />
return -getNewVelocity(-velocity,-distance);<br />
double highestVelocity = getMaxVelocity(distance); // highest velocity without overshooting<br />
double wantedVelocity = Math.min(highestVelocity,currentCommands.getMaxVelocity());<br />
// the actually wanted velocity by the robot is the highest possible,<br />
// limited by what the robot set by the setMaxVelocity command<br />
return getClosestReachableVelocityToVelocity(velocity, wantedVelocity);<br />
// return whatever is closest to that velocity<br />
}<br />
</syntaxhighlight><br />
<br />
Simulator:<br />
<syntaxhighlight><br />
<br />
public void simulate()<br />
{<br />
double currentVelocity = 8.0;<br />
double distanceRemain = -2.0;<br />
while(distanceRemain!=0.0 || currentVelocity!=0.0)<br />
{<br />
out.println("velocity = "+currentVelocity+"; distance="+distanceRemain);<br />
currentVelocity = getNewVelocity(currentVelocity,distanceRemain);<br />
distanceRemain -=currentVelocity;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Results ==<br />
<br />
StartVelocity = 0.0; StartDistance = 6.0;<br />
<pre><br />
velocity = 0.0; distance=6.0<br />
velocity = 1.0; distance=5.0<br />
velocity = 2.0; distance=3.0<br />
velocity = 2.5; distance=0.5<br />
velocity = 0.5; distance=0.0<br />
</pre><br />
StartVelocity = 0.0; StartDistance = 10;<br />
<pre><br />
velocity = 0.0; distance=10.0<br />
velocity = 1.0; distance=9.0<br />
velocity = 2.0; distance=7.0<br />
velocity = 3.0; distance=4.0<br />
velocity = 3.0; distance=1.0<br />
velocity = 1.0; distance=0.0<br />
</pre><br />
StartVelocity = -1.9; StartDistance = 10;<br />
<pre><br />
velocity = -1.9; distance=10.0<br />
velocity = 0.10000000000000009; distance=9.9<br />
velocity = 1.1; distance=8.8<br />
velocity = 2.1; distance=6.700000000000001<br />
velocity = 3.1; distance=3.600000000000001<br />
velocity = 2.8000000000000007; distance=0.8000000000000003<br />
velocity = 0.8000000000000007; distance=-4.440892098500626E-16;<br />
velocity = -4.440892098500626E-16; distance=0.0<br />
</pre><br />
StartVelocity = 8.0; StartDistance = -2.0;<br />
<pre><br />
velocity = 8.0; distance=-2.0<br />
velocity = 6.0; distance=-8.0<br />
velocity = 4.0; distance=-12.0<br />
velocity = 2.0; distance=-14.0<br />
velocity = -0.0; distance=-14.0<br />
velocity = -1.0; distance=-13.0<br />
velocity = -2.0; distance=-11.0<br />
velocity = -3.0; distance=-8.0<br />
velocity = -4.0; distance=-4.0<br />
velocity = -3.0; distance=-1.0<br />
velocity = -1.0; distance=0.0<br />
</pre><br />
StartVelocity = 5.0; StartDistance = 40.0;<br />
<pre><br />
velocity = 5.0; distance=40.0<br />
velocity = 6.0; distance=34.0<br />
velocity = 7.0; distance=27.0<br />
velocity = 8.0; distance=19.0<br />
velocity = 7.75; distance=11.25<br />
velocity = 5.75; distance=5.5<br />
velocity = 3.75; distance=1.75<br />
velocity = 1.75; distance=0.0<br />
</pre><br />
<br />
== Original game updateMovement code ==<br />
<br />
<syntaxhighlight><br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
double dx = velocity * sin(bodyHeading);<br />
double dy = velocity * cos(bodyHeading);<br />
<br />
x += dx;<br />
y += dy;<br />
<br />
if (dx != 0 || dy != 0) {<br />
updateBoundingBox();<br />
}<br />
<br />
if (distance != 0) {<br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Suggested updateMovement code Positive ==<br />
<br />
Now I'm thinking, if the distance remaining == 0.0, and the velocity is set from 6.0 to 4.0, shouldnt the distance remaining become -4.0? Also, the updateBoundingBox is called whenever velocity!=0, because the condition dx==0 && dy==0 is only when the velocity==0, so that can be easier to check. I suggest:<br />
<br />
<syntaxhighlight><br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
if(velocity!=0)<br />
{<br />
x += velocity * sin(bodyHeading);<br />
y += velocity * cos(bodyHeading);<br />
updateBoundingBox();<br />
}<br />
<br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
}<br />
</syntaxhighlight><br />
<br />
== Corrected updateMovement code ==<br />
<br />
When I run your suggested version against the unit test for 1.6.1.4, I get an error. After some studying and experiments, I found out that the updateMovement() method used in 1.7.1.3 (the "original" on this page) and your suggested version are both buggy. The problem is that the remaining distance is incorrect. The bugfree version compared to 1.6.1.4 is this version:<br />
<br />
<syntaxhighlight><br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
if (velocity == 0) {<br />
currentCommands.setDistanceRemaining(0);<br />
} else {<br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
<br />
x += velocity * sin(bodyHeading);<br />
y += velocity * cos(bodyHeading);<br />
updateBoundingBox();<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
The problem was, that is the robot has a velocity of e.g. 8, and we call setAhead(0), the remaining distance would be set to 0. But this is not correct, as the robot needs to brake first, and will move at least 6 + 4 + 2 = 12 pixels more, meaining that it should end with a remaining distance of -12. My new version about take this into account and works in the 1.6.1.4 code. Unfortunately this also means that our Alpha versions are buggy, as I used this improved version for all of them. That might explain the "big" differences in score! I am affraid that we need to do new alphas and retest them all with this issue in mind. Argh! What to do? Should we make new alphas for Hijack 1 and 2 etc. and retest? We could do this + we gain benefits of all bugfixes that have been made since 1.7.1.3. --[[User:FlemmingLarsen|Fnl]] 22:04, 7 August 2009 (UTC)<br />
<br />
Thankyou for taking the time to investigate this, could you please expand on why you added:<br />
<br />
<syntaxhighlight><br />
if (velocity == 0) {<br />
currentCommands.setDistanceRemaining(0);<br />
} <br />
</syntaxhighlight><br />
<br />
Say you are at -2 velocity, and set distance to travel=100. Wouldn't that code cause distance to travel to be incorrectly set to 0? --[[User:Positive|Positive]] 23:06, 7 August 2009 (UTC)<br />
<br />
[[Fnl]], what I think you are trying to do is prevent bots from reversing back to their original position if setAhead(0) is called? You shouldn't do that by checking if <code>velocity == 0</code> but rather by checking if <code>distance == 0</code> because velocity has nothing to do with what the bot passed as an arguments, distance is. So rather have the updateMovement() method as: <br />
<syntaxhighlight><br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
if(velocity!=0)<br />
{<br />
x += velocity * sin(bodyHeading);<br />
y += velocity * cos(bodyHeading);<br />
updateBoundingBox();<br />
}<br />
if(distance != 0)<br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
}<br />
</syntaxhighlight><br />
--[[User:Skilgannon|Skilgannon]] 23:21, 7 August 2009 (UTC)<br />
<br />
Yes, I believe your version is correct, and that my newest version is buggy (too). Actually, I was using the "if(distance != 0)" in my original code for 1.7.1.3. It seems to work better. And running on the old test cases for 1.6.1.4 shows that the previous version only covers some parts of the errors I saw yesterday with the suggested updateMovement from Positive.<br />
<br />
Doh! This means that the new alphas I made yesterday (5, 6, 7) are incorrect too! :-\<br />
<br />
Okay, so we should wait on doing new tests, and create new Alphas again, again. I need to try out this new version too. --[[User:FlemmingLarsen|Fnl]] 13:16, 8 August 2009 (UTC)<br />
<br />
[[User:Skilgannon|Skilgannon]], it seems your version is buggy too. The problem is that is does not take the braking scenario into account I described earlier. E.g. if the robot is moving at velocity 8, has quite some remaining distance left, and then we call setAhead(0), the robot should end with a remaining distance = -12 after the braking has stopped.<br />
* Time n+0: Velocity = 8, remaining distance = 1000 -> Now we call setAhead(0)<br />
* Time n+1: Velocity = 8, remaining distance = 0<br />
* Time n+2: Velocity = 6, remaining distance = -6<br />
* Time n+3: Velocity = 4, remaining distance = -10<br />
* Time n+4: Velocity = 2, remaining distance = -12<br />
* Time n+5: Velocity = 0, remaining distance = -12 -> We have finally stopped<br />
<br />
This scenario must be taken into account in order to stay compatible with 1.6.1.4. I guess we need a seperate variable to keep track of the user's setAhead/Back(x) request. --[[User:FlemmingLarsen|Fnl]] 13:48, 8 August 2009 (UTC)<br />
<br />
: Isn't it should be <br />
<br />
:<br />
:* Time n+0: Velocity = 8, remaining distance = 1000 -> Now we call setAhead(0)<br />
:* Time n+1: Velocity = 6, remaining distance = -6<br />
:* Time n+2: Velocity = 4, remaining distance = -10<br />
:* Time n+3: Velocity = 2, remaining distance = -12<br />
:* Time n+4: Velocity = 0, remaining distance = -12 -> We have finally stopped<br />
<br />
:? Because robot did move once more in each tick. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:59, 8 August 2009 (UTC)<br />
:: Yes, you are right here. :-) --[[User:FlemmingLarsen|Fnl]] 21:28, 8 August 2009 (UTC)<br />
<br />
Let see if this work...<br />
<syntaxhighlight><br />
<br />
boolean isOverDriving = false;<br />
<br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
if (velocity == 0 && isOverDriving) {<br />
currentCommands.setDistanceRemaining(0);<br />
isOverDriving = false;<br />
}<br />
<br />
if (Math.signum(distance * velocity) != -1) {<br />
if (getDistanceTraveledUntilStop(velocity) > Math.abs(distance))<br />
isOverDriving = true;<br />
else<br />
isOverDriving = false;<br />
}<br />
<br />
if(velocity != 0) {<br />
x += velocity * sin(bodyHeading);<br />
y += velocity * cos(bodyHeading);<br />
updateBoundingBox();<br />
}<br />
<br />
if(distance != 0)<br />
currentCommands.setDistanceRemaining(distance - newVelocity);<br />
}<br />
<br />
private double getDistanceTraveledUntilStop(double velocity) {<br />
double distance = 0;<br />
velocity = Math.abs(velocity);<br />
while (velocity > 0)<br />
distance += (velocity = getNewVelocity(velociy, 0));<br />
return distance;<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
&raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:21, 8 August 2009 (UTC)<br />
<br />
Testing using hacked Darkcanuck's VelocityTest, my version seems to work fine. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:59, 8 August 2009 (UTC)<br />
<br />
Fnl, with the version I posted as suggestion to the original, it should work like you said. I really can't see why it wouldn't work. To check we are on the same page, if the robot is at 8 velocity, and setAhead(0) is set, it should move backwards after it has overshot, right? If you look at the version I posted, you see the line: <br />
<br />
<syntaxhighlight><br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
}<br />
</syntaxhighlight><br />
<br />
Lets say distance is set to 0, and velocity is set to 6. Then distance remaining will be set here to (0 - 6) = -6. And after that (-6 - 4) = -10. Etc. --[[User:Positive|Positive]] 17:27, 8 August 2009 (UTC)<br />
<br />
[[User:Positive|Positive]], I ran my test again with your version. I am sorry that I wrote that the problem with your version is the remaining distance. This is ''not'' the case, as it is perfect in your version. The problem with your version is that when the robot is braking, it does not stop at velocity = 0. It continues to velocity = -1 in the next turn, and afterward -2, where it should have stopped at velocity = 0. This can be seen with the TestBodyTurnRate (using the BodyTurnRate test robot). The additonal check ''if(distance != 0)'' by [[User:Skilgannon|Skilgannon]] fixes this problem, but wrecks the remaining distance. So we need a method to take both issues into account. :-p Now I will check out [[User:Nat|Nat]]'s version. I cross my fingers that his version works. --[[User:FlemmingLarsen|Fnl]] 21:15, 8 August 2009 (UTC)<br />
<br />
Hrm, but what would be the use of getting a distance of -12 at velocity=0, if the robot doesn't try to get to 0 distance by going -1, -2 etc.? I'll try to test with that robot to see what you mean. --[[User:Positive|Positive]] 21:47, 8 August 2009 (UTC)<br />
<br />
== FNL's test robot ==<br />
Okay, I guees I need to provide a sample robot + give the result I expect so you are able to follow what I am talking about. ;-)<br />
Basically, I just want us to be compatible with version 1.6.1.4, at least for the following test.<br />
<br />
This robot will show a simple movement:<br />
<syntaxhighlight><br />
public class TestVelocityAndRemainingDist extends robocode.AdvancedRobot {<br />
public void run() {<br />
// Set far ahead<br />
setAhead(1000);<br />
<br />
// Execute for 9 turns<br />
for (int i = 0; i < 9; i++) {<br />
executeAndDump();<br />
}<br />
<br />
// Stop moving<br />
stopMovingAndDump();<br />
}<br />
<br />
private void executeAndDump() {<br />
double lastVelocity = getVelocity();<br />
double distanceRemaining = getDistanceRemaining();<br />
<br />
execute();<br />
<br />
out.println(getTime() + ": " + lastVelocity + ", " + distanceRemaining);<br />
}<br />
<br />
private void stopMovingAndDump() {<br />
setAhead(0);<br />
setTurnLeft(0);<br />
<br />
for (int i = 0; i < 7; i++) {<br />
executeAndDump();<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
The results (robot output) we get when running this robot in version 1.6.1.4 is:<br />
<pre><br />
1: 0.0, 1000.0<br />
2: 1.0, 999.0<br />
3: 2.0, 997.0<br />
4: 3.0, 994.0<br />
5: 4.0, 990.0<br />
6: 5.0, 985.0<br />
7: 6.0, 979.0<br />
8: 7.0, 972.0<br />
9: 8.0, 964.0<br />
10: 8.0, 0.0<br />
11: 6.0, -6.0<br />
12: 4.0, -10.0<br />
13: 2.0, -12.0<br />
14: 0.0, 0.0<br />
15: 0.0, 0.0<br />
16: 0.0, 0.0<br />
</pre><br />
<br />
Here the first number is the turn, the second row is the velocity, and the third row is the remaining distance.<br />
<br />
--[[User:FlemmingLarsen|Fnl]] 21:54, 8 August 2009 (UTC)<br />
<br />
When I test using [[User:Positive|Positive]]'s updateMovement, I get almost the same, but have problems with the velocity in the end:<br />
<pre><br />
...<br />
13: 2.0, -12.0<br />
14: 0.0, -12.0<br />
15: -1.0, -11.0<br />
16: -2.0, -10.0<br />
</pre><br />
<br />
That is, the velocity should end at 0. So this is bad compared to 1.6.1.4.<br />
<br />
When I test using [[User:Skilgannon|Skilgannon]]'s and also [[User:Nat|Nat]]'s version of updateMovement, I end with (in both cases):<br />
<br />
<pre><br />
...<br />
10: 8.0, 0.0<br />
11: 6.0, 0.0<br />
12: 4.0, 0.0<br />
13: 2.0, 0.0<br />
14: 0.0, 0.0<br />
15: 0.0, 0.0<br />
16: 0.0, 0.0<br />
</pre><br />
<br />
Here the remaining distance is wrong compared to 1.6.1.4.<br />
<br />
--[[User:FlemmingLarsen|Fnl]] 22:13, 8 August 2009 (UTC)<br />
<br />
(Edit conflict) Okay, so lets say the current velocity is positive, the pseudocode would be (for your suggested behaviour):<br />
<br />
<pre><br />
if remaining distance is positive:<br />
the next velocity is the closest possible to the max velocity without overshooting<br />
the next remaining distance is current remaining distance - next velocity<br />
if remaining distance is negative:<br />
the next velocity is the closest possible to 0<br />
if the next velocity is 0:<br />
the next remaining distance becomes 0<br />
else<br />
the next remaining distance becomes current remaining distance - next velocity<br />
</pre><br />
<br />
Is this correct? --[[User:Positive|Positive]] 22:16, 8 August 2009 (UTC)<br />
: Yes, this looks right to me. :-) --[[User:FlemmingLarsen|Fnl]] 22:31, 8 August 2009 (UTC)<br />
: No, if you move backward you will have negative distance remaining and velocity. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 23:57, 8 August 2009 (UTC)<br />
: Actually, I said "lets say the current velocity is positive". But now I recheck it, the pseudocode would give problems with robots that are at say 8 velocity and want to move -100 (backwards). They'd be cut off at 0 from doing the total move. It's a difficult question, and I think the proposal at the end of this page would be best, leaving the original code as is. --[[User:Positive|Positive]] 00:03, 9 August 2009 (UTC)<br />
<br />
Heh, and if I make this little tweak and run in 1.6.1.4:<br />
<syntaxhighlight><br />
private void stopMovingAndDump() {<br />
setAhead(-0.01);<br />
setTurnLeft(0);<br />
<br />
for (int i = 0; i < 13; i++) {<br />
executeAndDump();<br />
}<br />
}<br />
</syntaxhighlight> it gives <pre>1: 0.0, 1000.0<br />
2: 1.0, 999.0<br />
3: 2.0, 997.0<br />
4: 3.0, 994.0<br />
5: 4.0, 990.0<br />
6: 5.0, 985.0<br />
7: 6.0, 979.0<br />
8: 7.0, 972.0<br />
9: 8.0, 964.0<br />
10: 8.0, -0.01<br />
11: 6.0, -6.01<br />
12: 4.0, -10.01<br />
13: 2.0, -12.01<br />
14: 0.0, -12.01<br />
15: -1.0, -11.01<br />
16: -2.0, -9.01<br />
17: -3.0, -6.01<br />
18: -4.0, -2.01<br />
19: -2.0, -0.009999999999999787<br />
20: -0.009999999999999787, 0.0<br />
21: 0.0, 0.0<br />
22: 0.0, 0.0<br />
</pre> showing how near-zero values behave. Ugh... this highly inconsistant behavior between near-zero and zero makes me tempted to suggest something like having setAhead() behave like 1.6.1.4, but make something like a setBetterAhead() with more intuitive/sane behavior. Personally, I can think of little usefulness of the old setAhead() behavior in a new bot, except to annoy the bot author. If an author wants the bot to coast to a stop, the stop() function makes much more sense. Every single movement I've personally written, or seen anyone else write, is based upon either a "goToPoint()" style method, a "setVelocity()" style method, or is a simple oscillator. For simple oscillators or "setVelocity()" method the "setAhead(0)" condition likely never occurs. For a "goToPoint()" style, "setAhead(0)" will almost always be intended to mean "go where I am now". The ONLY case in which I can see people thinking the current behavior of "setAhead(0)" makes sense, is if what they REALLY meant was "setVelocity(0)". --[[User:Rednaxela|Rednaxela]] 22:28, 8 August 2009 (UTC)<br />
: I really agree with you that the setAhead() and stop is not really intuitive. It fooled me many times as I always forget how it behaves. However, I have never dared to change that as I would break the compatibility and rankings in RoboRumble. ;-) Your idea with setVelocity(0) reminds me of the new robot type in Robocode named [http://robocode.sourceforge.net/docs/robocode/robocode/RateControlRobot.html RateControlRobot]. Go have a look. :-) --[[User:FlemmingLarsen|Fnl]] 22:42, 8 August 2009 (UTC)<br />
:: Interesting, though three things 1) I doubt people really care about the 'rate' often for anything except velocity, 2) Err "setVelocityRate()" seems like a major misnomer. Velocity is the rate of movement, and the rate at which velocity moves is acceleration, so "setVelocityRate()" would logically imply acceleration rather than what it says in those API docs, 3) Since it extends AdvancedRobot and not TeamRobot, you can't use it in a team robot. --[[User:Rednaxela|Rednaxela]] 22:53, 8 August 2009 (UTC)<br />
:: 1) Once in a while people have requested this type of robot in order to "simulate" a real robot. So why not? 2) You are right. I need to do some work here. ;-) 3) Again a very good point! This should be easy to fix, and I will. :-) --[[User:FlemmingLarsen|Fnl]] 23:03, 8 August 2009 (UTC)<br />
:: Oh, and also, here's how I deal with setting velocity in all of my recent bots these days: [[User:Rednaxela/BotBase#MovementActor.java]] --[[User:Rednaxela|Rednaxela]] 23:08, 8 August 2009 (UTC)<br />
<br />
Just for the record, I forgot to add the test result for my updateMovement method from yesterday against the TestVelocityAndRemainingDist robot. My version seems works perfect in this specific scenario. But I am still not sure if it is 100% correct. --[[User:FlemmingLarsen|Fnl]] 22:31, 8 August 2009 (UTC)<br />
<br />
I think like Rednaxela it seems illogical that the distance should first become -12, and then be set to 0 when velocity=0 is reached. I believe there are 2 options:<br />
<br />
# The overshot is added to the remaining distance (my first suggested code).<br />
# Nothing is added to the remaining distance and it stays the same until the robot travels in the right direction. That means that remaining distance would stay at 0 if a robot sets setAhead(0), but will eventually move backwards only by -2 if set with setAhead(-2) independant of what the initial velocity was.<br />
<br />
Otherwise what Rednaxela posted will happen (setAhead(-0.01) being treated completely different from setAhead(0)). --[[User:Positive|Positive]] 22:40, 8 August 2009 (UTC)<br />
<br />
I am not sure what to do. It seems to be most of you want to stick to the behaviour from 1.6.1.4, even if it is odd and hard to understand the behavior. The reason being that you do not want to wreck rankings etc. for the RoboRumble, which is reasonable, but also to allow old robots to run the same way as in previous versions. In the discussion of old versus new rules, most people seems to want stick to the old rules, but without the bugs that can be fixed with little impact. So if we change the rules with the remaining distance here compared to 1.6.1.4, this might have an impact on both compatibility and rankings. But I really value your oppinions, so I will change the behaviour here if this is want most people wants. So what do we/you want? :-) --[[User:FlemmingLarsen|Fnl]] 22:56, 8 August 2009 (UTC)<br />
<br />
: Well, the other issues before affect the 'physical' capabilities of the robot, however since this "setAhead(0)" doesn't, why don't we let the bots in question choose the behavior? We could have setAhead() by default behave as 1.6.1.4, but do one of the following so new bots don't have to worry about it:<br />
:# Deprecate setAhead() in favor of something else with more intuitive behavior<br />
:# or, have something like a "AdvancedRobot.useLegacySetAhead(boolean)", which is by default is true, but new bots can set to false<br />
:--[[User:Rednaxela|Rednaxela]] 23:08, 8 August 2009 (UTC)<br />
<br />
I suggest we keep the functionality the same for bots that call setAhead() and setBack(), deprecate those methods, and add a new function setDistanceRemaining() which follows the new rules where setDistanceRemaining(0) tries to 'bring you back' to this point if you have a non-zero velocity. The "AdvancedRobot.useLegacySetAhead(boolean)" option would also make it harder for codesize-limited bots to make use of the new rules. --[[User:Skilgannon|Skilgannon]] 23:19, 8 August 2009 (UTC)<br />
<br />
Deprecating setAhead and making one that works more intuitively seems like a good option. Maybe setForward / setBackward, same meaning but different words. Not to say it needs to happen in this same version. Of course I agree that setAhead and setBack should continue to function like 1.6.1.4. Really, setAhead(0) seems like a very strange thing to do, anyway, if you ask me. =) So I don't really see it confusing new Robocoders or anything like that. But it's still good for things to be intuitive. --[[User:Voidious|Voidious]] 23:33, 8 August 2009 (UTC)<br />
<br />
: Just a note that 1.6.1.4's updateMovement() is really messy, I think it would be good if we can have cleaner implementation. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 00:10, 9 August 2009 (UTC)<br />
<br />
== Nat's updateMovement ==<br />
<br />
(edit conflict) Ha ha... When I was adapting Skilgannon's code, I read "if(distance != 0)" as "if(velocity != 0)" so mine has the same result as his. This new code should works then, I spent a lot of time debugging this this morning since I forgot that I have isOverDriving as a static variable, which it mustn't or it will share over all robots =)<br />
<syntaxhighlight><br />
private boolean isOverDriving = false;<br />
<br />
private void updateMovement() {<br />
double distance = currentCommands.getDistanceRemaining();<br />
<br />
if (Double.isNaN(distance)) {<br />
distance = 0;<br />
}<br />
<br />
velocity = getNewVelocity(velocity, distance);<br />
<br />
// If we are over-driving our distance and we are now at velocity=0<br />
// then we stopped.<br />
if (Utils.isNear(velocity, 0) && isOverDriving) {<br />
currentCommands.setDistanceRemaining(0);<br />
distance = 0;<br />
isOverDriving = false;<br />
}<br />
<br />
// If we are moving normally and the breaking distance is more<br />
// than remaining distance, enabled the overdrive flag.<br />
if (Math.signum(distance * velocity) != -1) {<br />
if (getDistanceTraveledUntilStop(velocity) > Math.abs(distance)) {<br />
isOverDriving = true;<br />
} else {<br />
isOverDriving = false;<br />
}<br />
}<br />
<br />
currentCommands.setDistanceRemaining(distance - velocity);<br />
<br />
if (velocity != 0) {<br />
x += velocity * sin(bodyHeading);<br />
y += velocity * cos(bodyHeading);<br />
updateBoundingBox();<br />
}<br />
}<br />
<br />
private double getDistanceTraveledUntilStop(double velocity) {<br />
double distance = 0;<br />
velocity = Math.abs(velocity);<br />
while (velocity > 0)<br />
distance += (velocity = getNewVelocity(velocity, 0));<br />
return distance;<br />
}<br />
</syntaxhighlight><br />
I copied this from updateMovement() of my test version, it should works as expected:<br />
<pre><br />
1: 0.0, 1000.0<br />
2: 1.0, 999.0<br />
3: 2.0, 997.0<br />
4: 3.0, 994.0<br />
5: 4.0, 990.0<br />
6: 5.0, 985.0<br />
7: 6.0, 979.0<br />
8: 7.0, 972.0<br />
9: 8.0, 964.0<br />
10: 8.0, 0.0<br />
11: 6.0, -6.0<br />
12: 4.0, -10.0<br />
13: 2.0, -12.0<br />
14: -0.0, 0.0<br />
15: 0.0, 0.0<br />
16: 0.0, 0.0<br />
<br />
1: 0.0, 1000.0<br />
2: 1.0, 999.0<br />
3: 2.0, 997.0<br />
4: 3.0, 994.0<br />
5: 4.0, 990.0<br />
6: 5.0, 985.0<br />
7: 6.0, 979.0<br />
8: 7.0, 972.0<br />
9: 8.0, 964.0<br />
10: 8.0, -0.01<br />
11: 6.0, -6.01<br />
12: 4.0, -10.01<br />
13: 2.0, -12.01<br />
14: -0.0, -12.01<br />
15: -1.0, -11.01<br />
16: -2.0, -9.01<br />
17: -3.0, -6.01<br />
18: -4.0, -2.01<br />
19: -2.005, -0.004999999999999893<br />
20: -0.004999999999999893, 0.0<br />
21: 0.0, 0.0<br />
22: 0.0, 0.0<br />
</pre><br />
&raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 23:39, 8 August 2009 (UTC)<br />
<br />
Nice work [[User:Nat|Nat]]! I verified your results, and it works as 1.6.1.4. =)<br />
<br />
Hence, I intend to use this updateMovement method for version 1.7.1.4. Next question is what getNewMovement method we should use. But this is ongoing on the pool [[User_talk:Voidious/Robocode_Version_Tests|here]] (near the bottom of the page). I think I will stick to the [[Talk:Positive/Optimal_Velocity#Hijack_.3D.29|Hijack]] version by [[User:Skilgannon|Skilgannon]] which uses the old rules, and then produce a final Alpha-8 for all of you to try out. Then I will fix some of the remaining reported bugs on SF and make a Beta later. New features will have to wait for 1.7.2.<br />
<br />
Man... this movement issue has taken a long time to fix! --[[User:FlemmingLarsen|Fnl]] 13:26, 9 August 2009 (UTC)<br />
<br />
Finally! A little sad that you chose Skilgannon's not Voidious'. But I do respect your decision as a tie-break. Hmm... 1.7.1 series seem to fixed the movement issue twice.<br />
<br />
About getNewMovement, I think Voidious' getNewVelocity() and 1.7.1's getUpdateMovement() would be a good combination (the Alpha3), but we need to change Robot API, and thus [[User:Zamboch|Zamboch]] (AKA Pavel Savara) needs to re-generate his .NET =) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 14:22, 9 August 2009 (UTC)<br />
<br />
I decided to go for the Alpha-2 (old rules) version, as I expect Skilgammon to vote on this version and because some have voted on Alpha-4, which is closer to the Alpha-2. However, I also think it is a shame if we don't use Voidious' version (new rules) as I think it is more correct. Even through I wrote that I would only add a final Alpha-8 (old rules), I have added a Alpha-9 (new rules) too. This way the ones interrested in trying it out is able to do that. :-) The new alphas can be found [[User_talk:Voidious/Robocode_Version_Tests#New_Alphas|here]]. --[[User:FlemmingLarsen|Fnl]] 20:29, 9 August 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/kdTree&diff=16900User:Pedersen/kdTree2010-07-01T08:37:41Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div><syntaxhighlight><br />
public class PedersenKDBucketTreeKNNSearch extends KNNImplementation {<br />
<br />
private final KDBucketTree<StringHoldingExemplar> tree;<br />
<br />
public PedersenKDBucketTreeKNNSearch(int dimension) {<br />
super(dimension);<br />
final int bucketSize = 24;<br />
double[] domainMap = new double[ dimension ];<br />
Arrays.fill( domainMap, Double.NaN );<br />
this.tree = new KDBucketTree<StringHoldingExemplar>( bucketSize );<br />
}<br />
<br />
@Override<br />
public void addPoint(double[] location, String value) {<br />
this.tree.add( new StringHoldingExemplar( location, value ) );<br />
}<br />
<br />
@Override<br />
public String getName() {<br />
return "Pedersen's " + this.tree.getClass().getSimpleName();<br />
}<br />
<br />
@Override<br />
public KNNPoint[] getNearestNeighbors(double[] location, int size) {<br />
Neighborhood<StringHoldingExemplar> neighborhood = <br />
new Neighborhood<StringHoldingExemplar>( location,<br />
new StringHoldingExemplar[ size ] );<br />
this.tree.findNearestNeighbors( neighborhood );<br />
<br />
// System.out.println();<br />
// System.out.print( this.tree.description( "1" ) );<br />
// System.out.println();<br />
<br />
// System.out.println( "\t" + new Exemplar( location ).description() );<br />
<br />
return convert( neighborhood );<br />
}<br />
<br />
private KNNPoint[] convert( Neighborhood<StringHoldingExemplar> neighborhood ) {<br />
StringHoldingExemplar[] neighbors = neighborhood.getNeighbors();<br />
double[] distances = neighborhood.getDistances();<br />
<br />
KNNPoint[] points = new KNNPoint[ neighbors.length ];<br />
for( int i = 0; i < neighbors.length; i++ ) {<br />
if( neighbors[ i ] != null ) {<br />
// System.out.println( "Sample:\t" + neighbors[i].description() );<br />
points[ i ] = new KNNPoint( neighbors[ i ].getPayload(), distances[ i ] );<br />
} else {<br />
System.out.println( "Sample [" + i + "] was null." );<br />
points[ i ] = new KNNPoint( null, Double.NaN );<br />
}<br />
}<br />
return points;<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight><br />
public class Exemplar {<br />
<br />
public Exemplar( double domain[] ) {<br />
this.domain = domain;<br />
}<br />
<br />
public String description() {<br />
StringBuilder buffer = new StringBuilder();<br />
buffer.append(this.domain[0]);<br />
for( int i = 1; i < this.domain.length; i++ ) {<br />
buffer.append( "\t" ).append( this.domain[ i ] );<br />
}<br />
return buffer.toString();<br />
}<br />
<br />
final double domain[];<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight><br />
public class StringHoldingExemplar extends Exemplar {<br />
<br />
public StringHoldingExemplar(double[] domain, String payload) {<br />
super(domain);<br />
this.payload = payload;<br />
}<br />
<br />
public String getPayload() { return this.payload; }<br />
<br />
private final String payload;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight><br />
public class KDBucketTree<T extends Exemplar> {<br />
<br />
public KDBucketTree( int bucketSize ) {<br />
this.bucketSize = bucketSize;<br />
}<br />
<br />
public void findNearestNeighbors( Neighborhood<T> neighborhood ) {<br />
if( !this.isTree() ) {<br />
neighborhood.evaluate( this.exemplars );<br />
} else {<br />
if( neighborhood.getControlValueAtIndex( this.branchingIndex ) < this.branchingValue ) {<br />
this.lt.findNearestNeighbors( neighborhood );<br />
if( neighborhood.isBranchEligible( this.branchingIndex, this.branchingValue ) ) {<br />
this.gte.findNearestNeighbors( neighborhood );<br />
}<br />
} else {<br />
this.gte.findNearestNeighbors( neighborhood );<br />
if( neighborhood.isBranchEligible( this.branchingIndex, this.branchingValue ) ) {<br />
this.lt.findNearestNeighbors( neighborhood );<br />
}<br />
}<br />
}<br />
}<br />
<br />
public void add( T e ) {<br />
if( this.isTree() ) {<br />
if( e.domain[ this.branchingIndex ] < this.getSplitValue() ) {<br />
this.lt.add( e );<br />
} else {<br />
this.gte.add( e );<br />
}<br />
} else {<br />
if( this.exemplars.size() > this.bucketSize ) {<br />
System.out.println( "Excessive size: " + this.exemplars.size() );<br />
}<br />
this.exemplars.add( e );<br />
if( this.exemplars.size() > this.bucketSize ) {<br />
this.branch();<br />
}<br />
}<br />
}<br />
<br />
private void branch() {<br />
this.determineSplittingPoint();<br />
List<T> ltList = new ArrayList<T>();<br />
<br />
Iterator<T> iterator = this.exemplars.iterator();<br />
while( iterator.hasNext() ) {<br />
T exemplar = iterator.next();<br />
if( exemplar.domain[ this.branchingIndex ] < this.getSplitValue() ) {<br />
ltList.add( exemplar );<br />
iterator.remove();<br />
}<br />
}<br />
<br />
this.lt = new KDBucketTree<T>( this.bucketSize );<br />
this.lt.put( ltList );<br />
this.gte = new KDBucketTree<T>( this.bucketSize );<br />
this.gte.put( this.exemplars );<br />
this.exemplars = null;<br />
}<br />
<br />
private void put( List<T> exemplars ) {<br />
this.exemplars = exemplars;<br />
}<br />
<br />
private void determineSplittingPoint() {<br />
Iterator<T> iterator = this.exemplars.iterator();<br />
if( iterator.hasNext() ) {<br />
T exemplar = iterator.next();<br />
double[] minimums = Arrays.copyOf( exemplar.domain, exemplar.domain.length );<br />
double[] maximums = Arrays.copyOf( exemplar.domain, exemplar.domain.length );<br />
while( iterator.hasNext() ) {<br />
exemplar = iterator.next();<br />
for( int i = 0; i < exemplar.domain.length; i++ ) {<br />
minimums[ i ] = Math.min( minimums[ i ], exemplar.domain[ i ] );<br />
maximums[ i ] = Math.max( maximums[ i ], exemplar.domain[ i ] );<br />
}<br />
}<br />
this.branchingIndex = 0;<br />
double maxRange = maximums[ 0 ] - minimums[ 0 ];<br />
for( int i = 1; i < exemplar.domain.length; i++ ) {<br />
double range = maximums[ i ] - minimums[ i ];<br />
if( range > maxRange ) {<br />
this.branchingIndex = i;<br />
maxRange = range;<br />
}<br />
}<br />
<br />
this.setSplitValue( minimums[ this.branchingIndex ] + 0.5 * maxRange );<br />
}<br />
<br />
}<br />
<br />
private double getSplitValue() {<br />
return this.branchingValue;<br />
}<br />
<br />
private void setSplitValue( double value ) {<br />
this.branchingValue = value;<br />
}<br />
<br />
public boolean isTree() { return branchingIndex > -1; }<br />
<br />
public static String trim(double value) {<br />
String untrimmed = String.valueOf(value);<br />
String trimmed = untrimmed;<br />
int indexOfDecimal = untrimmed.indexOf('.');<br />
if (indexOfDecimal > 0 && untrimmed.length() > indexOfDecimal + 4) {<br />
trimmed = untrimmed.substring(0, indexOfDecimal + 5);<br />
}<br />
if (untrimmed.indexOf('e') > 0)<br />
trimmed = trimmed + untrimmed.substring(untrimmed.indexOf('e'));<br />
if (untrimmed.indexOf('E') > 0)<br />
trimmed = trimmed + untrimmed.substring(untrimmed.indexOf('E'));<br />
return trimmed;<br />
}<br />
<br />
public String description( String prefix ) {<br />
StringBuilder buffer = new StringBuilder();<br />
if( this.isTree() ) {<br />
buffer.append( "Tree " + prefix + "\t" + this.branchingIndex + "\t" + this.getSplitValue() + "\n" );<br />
buffer.append( this.lt.description( prefix + ".1" ) );<br />
buffer.append( this.gte.description( prefix + ".2" ) );<br />
} else {<br />
buffer.append( "Leaf " + prefix + "\n" );<br />
// for( T e : this.exemplars ) {<br />
// buffer.append( "\t" ).append( e.description() ).append( "\n" );<br />
// }<br />
}<br />
return buffer.toString();<br />
}<br />
<br />
private final int bucketSize;<br />
private List<T> exemplars = new ArrayList<T>();<br />
private int branchingIndex = -1;<br />
private double branchingValue = Double.NaN;<br />
private KDBucketTree<T> lt = null;<br />
private KDBucketTree<T> gte = null;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight><br />
public class Neighborhood<T extends Exemplar> {<br />
<br />
public Neighborhood( double[] control, T sandbox[] ) {<br />
this.control = control;<br />
this.neighbors = sandbox;<br />
this.dSquareds = new double[this.neighbors.length];<br />
Arrays.fill( this.dSquareds, Double.MAX_VALUE );<br />
}<br />
<br />
public void evaluate( Iterable<T> exemplars ) {<br />
for( T e : exemplars ) evaluate( e );<br />
}<br />
<br />
public void evaluate( T e ) {<br />
double dSquared = this.calculateDistanceSquared( this.control, e.domain );<br />
if( dSquared < this.getGreatestSquaredDistance() ) {<br />
this.neighbors[ this.indexOfGreatestDistanceSquared ] = e;<br />
this.dSquareds[ this.indexOfGreatestDistanceSquared ] = dSquared;<br />
this.setIndexOfGreatestSquaredDistance();<br />
}<br />
}<br />
<br />
public double getGreatestSquaredDistance() {<br />
return this.dSquareds[ this.indexOfGreatestDistanceSquared ];<br />
}<br />
<br />
public boolean isBranchEligible( int branchIndex, double branchSplit ) {<br />
return this.getGreatestSquaredDistance() > this.calculateDistanceSquaredToSplittingPlane( branchIndex, branchSplit );<br />
}<br />
<br />
private void setIndexOfGreatestSquaredDistance() {<br />
this.indexOfGreatestDistanceSquared = 0;<br />
for( int i = 1; i < this.dSquareds.length; i++ ) {<br />
if( this.dSquareds[ i ] > this.getGreatestSquaredDistance() ) {<br />
this.indexOfGreatestDistanceSquared = i;<br />
}<br />
}<br />
}<br />
<br />
public double getControlValueAtIndex( int index ) {<br />
return this.control[ index ];<br />
}<br />
<br />
public T[] getNeighbors() { return this.neighbors; }<br />
<br />
public double[] getDistances() {<br />
double[] distances = new double[ this.dSquareds.length ];<br />
for( int i = 0; i < this.dSquareds.length; i++ ) {<br />
distances[ i ] = Math.sqrt( this.dSquareds[ i ] );<br />
}<br />
return distances;<br />
}<br />
<br />
private double calculateDistanceSquared( double[] control, double[] reference ) {<br />
double ds = 0.0;<br />
assert( reference.length == control.length );<br />
for( int i = 0; i < reference.length; i++ ) {<br />
if( !Double.isNaN( reference[ i ] ) ) {<br />
ds += this.square( control[ i ] - reference[ i ] );<br />
}<br />
}<br />
// System.out.println( "Calculated distance squared: " + ds );<br />
return ds;<br />
}<br />
<br />
private double calculateDistanceSquaredToSplittingPlane( int branchIndex, double branchSplit ) {<br />
return this.square( this.control[ branchIndex ] - branchSplit );<br />
}<br />
<br />
private double square( double v ) { return v * v; }<br />
<br />
private final double[] control;<br />
private final T neighbors[];<br />
private final double dSquareds[];<br />
private int indexOfGreatestDistanceSquared = 0;<br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/Code_Samples/Radar&diff=16899User:Pedersen/Code Samples/Radar2010-07-01T08:37:37Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div><h4>package pedersen.systems;</h4><br />
<br />
I have developed three modes of radar operation, used under various circumstances.<br />
<br />
<ul><br />
<li>Passive Mode: sweeps a tiny arc forward of the tank.</li><br />
<li>Duel Mode: sweeps full circle until a target is aquired, then locks on the target with a rather small arc, which scales to the distance from the enemy.</li><br />
<li>Melee Mode: sweeps full circle until a target is aquired, temporarily locking on the target in a wide arc, and periodically circle sweeping afteward.</li><br />
</ul><br />
<br />
The three share an interface and a base class.<br />
<br />
<hr><br />
<br />
<syntaxhighlight><br />
/**<br />
* Common interface for all scanning methods.<br />
*/<br />
public interface ScanningMethod<br />
{<br />
//:://////////////////////////////////////<br />
//:: Methods<br />
//:://////////////////////////////////////<br />
<br />
/**<br />
* Operates the scanner.<br />
* <br />
* @param absoluteHeading the present scanner heading<br />
* @param projectedPosition the projected scanner position<br />
* @param target the present target lock<br />
* <br />
* @return the relative heading change as a result of the operation<br />
*/<br />
public double operate( double absoluteHeading, Vehicle projectedPosition, Target target );<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Constants<br />
//:://////////////////////////////////////<br />
<br />
public static final double maximumRateOfRelativeRotation = Math.PI / 4.0; // 45 degrees<br />
}<br />
<br />
/**<br />
* Common base class for all scanning methods.<br />
*/<br />
public class ScanningMethodBase<br />
{<br />
//:://////////////////////////////////////<br />
//:: Methods<br />
//:://////////////////////////////////////<br />
<br />
/**<br />
* Instructs a scanner to move to an angle offset beyond a heading. <br />
* Subsequent scans flip to the other side of the heading.<br />
* <br />
* @param scanner the scanner to instruct<br />
* @param heading the mean scan heading<br />
* @param sweepAngle the angle to sweep to either side of the mean scan heading<br />
*/<br />
protected void sweep( DynamicHeading scanner, double heading, double sweepAngle )<br />
{<br />
scanner.setAbsoluteTargetHeading( heading + ( sweepAngle * ( -0.5 + scanIndex % 2 ) ) );<br />
}<br />
<br />
//:://////////////////////////////////////<br />
//:: Instance Variables<br />
//:://////////////////////////////////////<br />
<br />
protected static long scanIndex = 0;<br />
}<br />
<br />
/**<br />
* Scanning Methods for locking onto a target until it is destroyed.<br />
* Until a target is aquired, the scanner sweeps clockwise indefinitely.<br />
*/<br />
public class ScanningMethodLockImpl extends ScanningMethodBase implements ScanningMethod<br />
{<br />
//:://////////////////////////////////////<br />
//:: Methods<br />
//:://////////////////////////////////////<br />
<br />
/**<br />
* Operates the scanner.<br />
* <br />
* @param absoluteHeading the present scanner heading<br />
* @param projectedPosition the projected scanner position<br />
* @param target the present target lock<br />
* @return the relative heading change as a result of the operation<br />
*/<br />
public double operate( double absoluteHeading, Vehicle projectedPosition, Target target )<br />
{<br />
DynamicHeading scanner = new DynamicHeadingImpl( maximumRateOfRelativeRotation );<br />
scanner.setHeading( absoluteHeading );<br />
<br />
scanIndex++;<br />
<br />
if( target == null )<br />
{<br />
scanner.setRelativeTargetHeading( maximumRateOfRelativeRotation );<br />
}<br />
else<br />
{<br />
double targetScanNarrow = 2.0 * Math.atan( Vehicle.maximumAbsVelocity / projectedPosition.getDistance( target ) );<br />
this.sweep( scanner, projectedPosition.getBearing( target ).getHeading(), targetScanNarrow );<br />
}<br />
<br />
return scanner.compare( new StaticHeadingImpl( scanner.projectHeading() ) );<br />
}<br />
}<br />
<br />
/**<br />
* Scanning Methods for sweeping a tiny arc to the front.<br />
* This is fluff radar mode for end of round victory dances, etc.<br />
*/<br />
public class ScanningMethodPassiveImpl extends ScanningMethodBase implements ScanningMethod<br />
{<br />
//:://////////////////////////////////////<br />
//:: Methods<br />
//:://////////////////////////////////////<br />
<br />
/**<br />
* Operates the scanner.<br />
* <br />
* @param absoluteHeading the present scanner heading<br />
* @param projectedPosition the projected scanner position<br />
* @param target the present target lock<br />
* @return the relative heading change as a result of the operation<br />
*/<br />
public double operate( double absoluteHeading, Vehicle projectedPosition, Target target )<br />
{<br />
DynamicHeading scanner = new DynamicHeadingImpl( maximumRateOfRelativeRotation );<br />
scanner.setHeading( absoluteHeading );<br />
<br />
scanIndex++;<br />
<br />
this.sweep( scanner, projectedPosition.getHeading(), targetScanOff );<br />
<br />
return scanner.compare( new StaticHeadingImpl( scanner.projectHeading() ) );<br />
}<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Constants<br />
//:://////////////////////////////////////<br />
<br />
private static final double targetScanOff = 0.00001;<br />
}<br />
<br />
/**<br />
* Scanning Methods for situational awareness.<br />
* Until a target is aquired, the scanner sweeps clockwise indefinitely.<br />
* After a target is aquired, the scanner is semi-locked in a wide arc, periodically rescanning the environment.<br />
*/<br />
public class ScanningMethodStandardImpl extends ScanningMethodBase implements ScanningMethod<br />
{<br />
//:://////////////////////////////////////<br />
//:: Methods<br />
//:://////////////////////////////////////<br />
<br />
/**<br />
* Operates the scanner.<br />
* <br />
* @param absoluteHeading the present scanner heading<br />
* @param projectedPosition the projected scanner position<br />
* @param target the present target lock<br />
* @return the relative heading change as a result of the operation<br />
*/<br />
public double operate( double absoluteHeading, Vehicle projectedPosition, Target target )<br />
{<br />
DynamicHeading scanner = new DynamicHeadingImpl( maximumRateOfRelativeRotation );<br />
scanner.setHeading( absoluteHeading );<br />
<br />
if( scanIndex++ > scanCycle) this.resetScanCycle( );<br />
if( ( target == null ) || ( scanIndex < scanSweepCycle ) )<br />
{<br />
scanner.setRelativeTargetHeading( maximumRateOfRelativeRotation );<br />
}<br />
else<br />
{<br />
this.sweep( scanner, projectedPosition.getBearing( target ).getHeading(), targetScanWide );<br />
}<br />
<br />
return scanner.compare( new StaticHeadingImpl( scanner.projectHeading() ) );<br />
}<br />
<br />
<br />
/**<br />
* Resets the scan cycle index, forcing an immediate sweep and a fresh delay for the recurring sweep.<br />
*/<br />
private void resetScanCycle( )<br />
{<br />
scanIndex = 0;<br />
}<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Constants<br />
//:://////////////////////////////////////<br />
<br />
private static final double targetScanWide = maximumRateOfRelativeRotation;<br />
private static final long scanSweepCycle = 8;<br />
private static final long scanCycle = 40;<br />
}<br />
</syntaxhighlight><br />
<br />
<hr><br />
<br />
The scan cycle reset method could be moved into the base class and exposed through the interface so that it can be called when taking an actual shot.</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/Code_Samples/getLateralVelocity&diff=16898User:Pedersen/Code Samples/getLateralVelocity2010-07-01T08:37:35Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>The following code snippet is what I presently (v0.14) use for segmentation on lateral (tangental) velocity. The result is a number between -1.0 and 1.0, representing maximum left or right orbit, respectively. The maximum would be attained at full speed completely tantental to my position. (Actually, this isn't exactly true. Turning slightly towards me is a hair faster.) The code includes a lot of my physics framework, but it should be readable.<br />
<br />
<syntaxhighlight><br />
private static double getTangentalVelocity( StaticPosition firingPosition, Snapshot target )<br />
{<br />
double bearingToTarget = firingPosition.getBearing( target ); // [0,2pi)<br />
StaticPosition projectedTarget = new Projection( target ).project().getStaticPosition();<br />
// the control position is 8.0 units to the right (tangentally) of the present target position<br />
StaticPosition controlPosition = new StaticPositionImpl( target, bearingToTarget + Constraints.rightAngle, Constraints.maxAbsVehicleVelocity );<br />
double bearingToProjectedTarget = Constraints.getNegativePiToPi( firingPosition.getBearing( projectedTarget ) - bearingToTarget );<br />
double bearingToControlPosition = Constraints.getNegativePiToPi( firingPosition.getBearing( controlPosition ) - bearingToTarget );<br />
double tangentalVelocity = bearingToProjectedTarget / bearingToControlPosition;<br />
return tangentalVelocity;<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/Code_Samples/Unit_Testing&diff=16897User:Pedersen/Code Samples/Unit Testing2010-07-01T08:37:34Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Following are two examples of unit test scripts. They are really boring and monotonous to write, but the more exhaustive you are the more likely you are to catch errors with new developments (assuming you run the tests).<br />
<br />
<syntaxhighlight><br />
package pedersen.physics;<br />
<br />
import junit.framework.TestCase;<br />
import pedersen.core.Constraints;<br />
<br />
public class StaticHeadingImplTest extends TestCase<br />
{<br />
<br />
public void testGetHeading()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
assertEquals( "Heading discrepancy.", rawHeading1, heading.getHeading(), Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testEqualsAngleWithDoubleForPositiveMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 2.5;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
assertTrue( "Heading discrepancy.", heading.equalsAngle( rawHeading2 ) );<br />
}<br />
<br />
public void testEqualsAngleWithDoubleForNegativeMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * -1.5;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
assertTrue( "Heading discrepancy.", heading.equalsAngle( rawHeading2 ) );<br />
}<br />
<br />
public void testEqualsAngleWithDoubleForMismatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.3;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
assertFalse( "Heading discrepancy.", heading.equalsAngle( rawHeading2 ) );<br />
}<br />
<br />
public void testEqualsAngleWithStaticHeadingForPositiveMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 2.5;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
assertTrue( "Heading discrepancy.", heading1.equalsAngle( heading2 ) );<br />
}<br />
<br />
public void testEqualsAngleWithStaticHeadingForNegativeMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * -1.5;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
assertTrue( "Heading discrepancy.", heading1.equalsAngle( heading2 ) );<br />
}<br />
<br />
public void testEqualsAngleWithStaticHeadingForMismatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.3;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
assertFalse( "Heading discrepancy.", heading1.equalsAngle( heading2 ) );<br />
}<br />
<br />
public void testGetRelativeAngleWithDoubleForPositiveMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.9;<br />
double rawHeading3 = Math.PI * 0.4;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
double relativeHeading = heading.getRelativeAngle( rawHeading2 );<br />
assertEquals( "Heading discrepancy.", relativeHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetRelativeAngleWithDoubleForNegativeMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.1;<br />
double rawHeading3 = Math.PI * -0.4;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
double relativeHeading = heading.getRelativeAngle( rawHeading2 );<br />
assertEquals( "Heading discrepancy.", relativeHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetRelativeAngleWithDoubleForMismatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.3;<br />
double rawHeading3 = Math.PI * 0.4;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
double relativeHeading = heading.getRelativeAngle( rawHeading2 );<br />
assertFalse( "Heading discrepancy.", Constraints.areEqual( relativeHeading, rawHeading3 ) );<br />
}<br />
<br />
public void testGetRelativeAngleWithStaticHeadingForPositiveMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.9;<br />
double rawHeading3 = Math.PI * 0.4;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
double relativeHeading = heading1.getRelativeAngle( heading2 );<br />
assertEquals( "Heading discrepancy.", relativeHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetRelativeAngleWithStaticHeadingForNegativeMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.1;<br />
double rawHeading3 = Math.PI * -0.4;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
double relativeHeading = heading1.getRelativeAngle( heading2 );<br />
assertEquals( "Heading discrepancy.", relativeHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetRelativeAngleWithStaticHeadingForMismatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.3;<br />
double rawHeading3 = Math.PI * 0.4;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
double relativeHeading = heading1.getRelativeAngle( heading2 );<br />
assertFalse( "Heading discrepancy.", Constraints.areEqual( relativeHeading, rawHeading3 ) );<br />
}<br />
<br />
public void testGetCompoundAngleWithDoubleForPositiveMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.9;<br />
double rawHeading3 = Math.PI * 1.4;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
double compoundHeading = heading.getCompoundAngle( rawHeading2 );<br />
assertEquals( "Heading discrepancy.", compoundHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetCompoundAngleWithDoubleForNegativeMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * -0.9;<br />
double rawHeading3 = Math.PI * 1.6;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
double compoundHeading = heading.getCompoundAngle( rawHeading2 );<br />
assertEquals( "Heading discrepancy.", compoundHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetCompoundAngleWithDoubleForMismatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.3;<br />
double rawHeading3 = Math.PI * 0.4;<br />
StaticHeading heading = new StaticHeadingImpl( rawHeading1 );<br />
double compoundHeading = heading.getCompoundAngle( rawHeading2 );<br />
assertFalse( "Heading discrepancy.", Constraints.areEqual( compoundHeading, rawHeading3 ) );<br />
}<br />
<br />
public void testGetCompoundAngleWithStaticHeadingForPositiveMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.9;<br />
double rawHeading3 = Math.PI * 1.4;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
double compoundHeading = heading1.getCompoundAngle( heading2 );<br />
assertEquals( "Heading discrepancy.", compoundHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetCompoundAngleWithStaticHeadingForNegativeMatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * -0.9;<br />
double rawHeading3 = Math.PI * 1.6;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
double compoundHeading = heading1.getCompoundAngle( heading2 );<br />
assertEquals( "Heading discrepancy.", compoundHeading, rawHeading3, Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testGetCompoundAngleWithStaticHeadingForMismatch()<br />
{<br />
double rawHeading1 = Math.PI * 0.5;<br />
double rawHeading2 = Math.PI * 0.3;<br />
double rawHeading3 = Math.PI * 0.4;<br />
StaticHeading heading1 = new StaticHeadingImpl( rawHeading1 );<br />
StaticHeading heading2 = new StaticHeadingImpl( rawHeading2 );<br />
double compoundHeading = heading1.getCompoundAngle( heading2 );<br />
assertFalse( "Heading discrepancy.", Constraints.areEqual( compoundHeading, rawHeading3 ) );<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight><br />
package pedersen.physics;<br />
<br />
import junit.framework.TestCase;<br />
import pedersen.core.Constraints;<br />
import pedersen.core.Conversions;<br />
import pedersen.core.Snapshot;<br />
import pedersen.core.SnapshotImpl;<br />
<br />
public class ProjectionTest extends TestCase<br />
{<br />
<br />
public void testConstructorWithSnapshot()<br />
{<br />
double x = 5.0, y = -2.0;<br />
double heading = Math.PI * 0.25;<br />
double velocity = -5.5;<br />
Snapshot snapshot = new SnapshotImpl( 0, 0, x, y, heading, velocity, 0.0 );<br />
Projection projection = new Projection( snapshot );<br />
assertEquals( "Projection discrepancy.", x, projection.getX(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", y, projection.getY(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", heading, projection.getHeading(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", velocity, projection.getVelocity(), Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testConstructorWithStaticPositionDoubleDouble()<br />
{<br />
double x = 5.0, y = -2.0;<br />
double heading = Math.PI * 0.25;<br />
double velocity = -5.5;<br />
StaticPosition staticPosition = new StaticPositionImpl( x, y );<br />
Projection projection = new Projection( staticPosition, heading, velocity );<br />
assertEquals( "Projection discrepancy.", x, projection.getX(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", y, projection.getY(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", heading, projection.getHeading(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", velocity, projection.getVelocity(), Constraints.doubleErrorTolerance );<br />
}<br />
<br />
public void testProject()<br />
{<br />
double x1 = 5.0, y1 = -2.0;<br />
double heading1 = Math.PI * 45.0 / 180.0; // 45 degrees<br />
double velocity1 = -5.5;<br />
double targetHeading = Math.PI * -0.25; // -45 degrees / 315 degrees<br />
double maxTurnRate = Conversions.getAbsMaxTurnRateFromVelocity( velocity1 );<br />
double targetVelocity = -8.0;<br />
double heading2 = heading1 - maxTurnRate;<br />
double velocity2 = -6.5;<br />
double x2 = x1 + Math.sin( heading2 ) * velocity2;<br />
double y2 = y1 + Math.cos( heading2 ) * velocity2;<br />
StaticPosition staticPosition = new StaticPositionImpl( x1, y1 );<br />
Projection projection = new Projection( staticPosition, heading1, velocity1 );<br />
projection.setAbsoluteTargetHeading( targetHeading );<br />
projection.setAbsoluteTargetVelocity( targetVelocity );<br />
projection.project();<br />
assertEquals( "Projection discrepancy.", x2, projection.getX(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", y2, projection.getY(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", heading2, projection.getHeading(), Constraints.doubleErrorTolerance );<br />
assertEquals( "Projection discrepancy.", velocity2, projection.getVelocity(), Constraints.doubleErrorTolerance );<br />
}<br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/Code_Samples/RobocodeSG&diff=16896User:Pedersen/Code Samples/RobocodeSG2010-07-01T08:37:33Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Following are some examples of my code to support debugging with RobocodeSG.<br><br />
First is an example of the code in use, followed by my wrapper for the swing graphics, and finally a structure for holding drawable line segments, mostly used for ad-hoc tests such as ensuring my movement projection looks right, or finding the difference in escape angles between an opponent going at a tangent or turning into the wave. -- Martin<br />
<br />
<hr><br />
This is from my WaveOutboundBank class, which maintains a list of waves that I've fired. The StaticPositionImpl constructor being used starts at the wave's origin and finds the point <i>radius</i> units away in the direction of the firing angle.<br />
<syntaxhighlight><br />
public void onPaint( Graphics2D console )<br />
{<br />
long time = Host.singleton.getTurn();<br />
<br />
Iterator iterator = this.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
CombatWave wave = ( CombatWave ) iterator.next();<br />
double radius1 = wave.getRadius( time - 1 );<br />
double radius2 = wave.getRadius( time );<br />
double radius3 = wave.getRadius( time + 1 );<br />
console.setColor( Color.darkGray );<br />
GraphicalDebugger.singleton.drawRing( console, wave, radius1 );<br />
GraphicalDebugger.singleton.drawRing( console, wave, radius2 );<br />
GraphicalDebugger.singleton.drawRing( console, wave, radius3 );<br />
Iterator firingAngleIterator = wave.getFiringAngleIterator();<br />
while( firingAngleIterator.hasNext() )<br />
{<br />
FiringAngle firingAngle = ( FiringAngle ) firingAngleIterator.next();<br />
StaticPosition point1 = new StaticPositionImpl( wave, firingAngle.getFiringAngle(), radius1 );<br />
StaticPosition point2 = new StaticPositionImpl( wave, firingAngle.getFiringAngle(), radius2 );<br />
StaticPosition point3 = new StaticPositionImpl( wave, firingAngle.getFiringAngle(), radius3 );<br />
console.setColor( Color.red );<br />
GraphicalDebugger.singleton.drawLine( console, point1, point2 );<br />
console.setColor( Color.yellow );<br />
GraphicalDebugger.singleton.drawLine( console, point2, point3 );<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<hr><br />
<syntaxhighlight><br />
package pedersen.debug;<br />
<br />
import java.awt.Graphics2D;<br />
import java.awt.geom.Ellipse2D;<br />
import java.awt.geom.Line2D;<br />
import java.awt.geom.Rectangle2D;<br />
import java.util.Iterator;<br />
import java.util.List;<br />
<br />
import pedersen.physics.StaticPosition;<br />
<br />
public class GraphicalDebugger<br />
{<br />
<br />
//:://////////////////////////////////////<br />
//:: Constructors<br />
//:://////////////////////////////////////<br />
<br />
private GraphicalDebugger()<br />
{<br />
}<br />
<br />
//:://////////////////////////////////////<br />
//:: Methods<br />
//:://////////////////////////////////////<br />
<br />
public void init( double newMaxY )<br />
{<br />
this.maxY = newMaxY;<br />
}<br />
<br />
public void drawVehicleHitBox( Graphics2D console, StaticPosition center )<br />
{<br />
console.draw( new Rectangle2D.Double( center.getX() - 18.0, this.maxY - center.getY() - 18.0, 36.0, 36.0 ) );<br />
}<br />
<br />
public void drawRing( Graphics2D console, StaticPosition center, double radius )<br />
{<br />
console.draw( new Ellipse2D.Double( center.getX() - radius, this.maxY - center.getY() - radius, radius + radius, radius + radius ) );<br />
}<br />
<br />
public void drawRings( Graphics2D console, List centers, double radius )<br />
{<br />
Iterator iterator = centers.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
this.drawRing( console, (StaticPosition)iterator.next(), radius );<br />
}<br />
}<br />
<br />
public void drawLine( Graphics2D console, StaticPosition a, StaticPosition b )<br />
{<br />
console.draw( new Line2D.Double( a.getX(), this.maxY - a.getY(), b.getX(), this.maxY - b.getY() ) );<br />
}<br />
<br />
public void drawRenderableLineSegment( Graphics2D console, RenderableLineSegment line )<br />
{<br />
console.setColor( line.color );<br />
console.draw( new Line2D.Double( line.x1, this.maxY - line.y1, line.x2, this.maxY - line.y2 ) );<br />
}<br />
<br />
public void drawRenderableLineSegments( Graphics2D console, List lines )<br />
{<br />
Iterator iterator = lines.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
this.drawRenderableLineSegment( console, (RenderableLineSegment)iterator.next() );<br />
}<br />
}<br />
<br />
<br />
//:://////////////////////////////////////<br />
//:: Instance Variables<br />
//:://////////////////////////////////////<br />
<br />
private double maxY = 0.0;<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Constants<br />
//:://////////////////////////////////////<br />
<br />
public static final GraphicalDebugger singleton = new GraphicalDebugger( );<br />
<br />
}<br />
</syntaxhighlight><br />
<hr><br />
<syntaxhighlight><br />
package pedersen.debug;<br />
<br />
import java.awt.Color;<br />
<br />
import pedersen.physics.StaticPosition;<br />
<br />
public class RenderableLineSegment<br />
{<br />
<br />
public RenderableLineSegment( StaticPosition start, StaticPosition end, Color newColor )<br />
{<br />
this.x1 = start.getX();<br />
this.y1 = start.getY();<br />
this.x2 = end.getX();<br />
this.y2 = end.getY();<br />
this.color = newColor;<br />
}<br />
<br />
public final double x1;<br />
public final double y1;<br />
public final double x2;<br />
public final double y2;<br />
public final Color color;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Thanks. It think i will have a busy evening --[[Loki]]</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/Code_Samples/Graphical_Debugger&diff=16895User:Pedersen/Code Samples/Graphical Debugger2010-07-01T08:37:31Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>The following class is what I presently (9/12/2007) use to manage my drawing routines. During the normal run of my code, any class can add a line, square, or circle to the "to-do" list, specifying how long the graphics should last. Turn scope is for anything constantly updated (e.g. waves, wall intercept position). Round scope records events that last longer (e.g. where bullets have hit, tank travel paths). Battle scope is also available for the long haul.<br />
<br />
Enjoy. -- [[Martin Alan Pedersen|Martin]]<br />
<br />
<syntaxhighlight><br />
public class GraphicalDebugger<br />
{<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Methods<br />
//:://////////////////////////////////////<br />
<br />
public static void drawVehicleHitBox( StaticPosition center, Color color )<br />
{<br />
GraphicalDebugger.addRenderableSquareTurnScope( center, 18.0, color );<br />
}<br />
<br />
public static void drawMarker( StaticPosition center, Color color )<br />
{<br />
GraphicalDebugger.addRenderableSquareTurnScope( center, 2.0, color );<br />
}<br />
<br />
public static void drawRenderableLineSegment( Graphics2D console, RenderableLineSegment o )<br />
{<br />
console.setColor( o.color );<br />
console.draw( new Line2D.Double( o.x1, o.y1, o.x2, o.y2 ) );<br />
}<br />
<br />
public static void drawRenderableRing( Graphics2D console, RenderableRing o )<br />
{<br />
console.setColor( o.color );<br />
console.draw( new Ellipse2D.Double( o.x - o.radius, o.y - o.radius, o.radius + o.radius, o.radius + o.radius ) );<br />
}<br />
<br />
public static void drawRenderableSquare( Graphics2D console, RenderableSquare o )<br />
{<br />
console.setColor( o.color );<br />
console.draw( new Rectangle2D.Double( o.x1, o.y1, o.x2 - o.x1, o.y2 - o.y1 ) );<br />
new Rectangle2D.Double(o.x1, o.y1, o.x2, o.y2 );<br />
}<br />
<br />
public static void drawRenderableLineSegments( Graphics2D console, Queue<RenderableLineSegment> queue )<br />
{<br />
Iterator iterator = queue.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
GraphicalDebugger.drawRenderableLineSegment( console, (RenderableLineSegment)iterator.next() );<br />
}<br />
}<br />
<br />
public static void drawRenderableRings( Graphics2D console, Queue<RenderableRing> queue )<br />
{<br />
Iterator iterator = queue.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
GraphicalDebugger.drawRenderableRing( console, (RenderableRing)iterator.next() );<br />
}<br />
}<br />
<br />
public static void drawRenderableSquares( Graphics2D console, Queue<RenderableSquare> queue )<br />
{<br />
Iterator iterator = queue.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
GraphicalDebugger.drawRenderableSquare( console, (RenderableSquare)iterator.next() );<br />
}<br />
}<br />
<br />
public static void traceVehicleMovement( SnapshotHistory history )<br />
{<br />
Snapshot previousSnapshot = history.getHistoricalSnapshot( 1 );<br />
if( previousSnapshot != null )<br />
{<br />
if( history.getTime() - 1 == previousSnapshot.getTime() )<br />
{<br />
double distance = previousSnapshot.getDistance( history );<br />
float heat = (float)(distance / Constraints.maxAbsVehicleVelocity);<br />
GraphicalDebugger.addRenderableLineSegmentRoundScope( history, previousSnapshot, new Color( heat, heat, heat ) );<br />
}<br />
}<br />
}<br />
<br />
public static void traceBulletMovement( SnapshotHistory history )<br />
{<br />
Snapshot previousSnapshot = history.getHistoricalSnapshot( 1 );<br />
if( previousSnapshot != null )<br />
{<br />
if( history.getTime() - 1 == previousSnapshot.getTime() )<br />
{<br />
double distance = previousSnapshot.getDistance( history );<br />
float heat = (float)(distance / Constraints.maxBulletVelocity);<br />
GraphicalDebugger.addRenderableLineSegmentRoundScope( history, previousSnapshot, new Color( (float)1.0, (float)0.0, heat ) );<br />
}<br />
}<br />
}<br />
<br />
public static void addRenderableLineSegmentBattleScope( StaticPosition a, StaticPosition b, Color c ) { renderableLineSegmentsBattle.add( new RenderableLineSegment( a, b, c ) ); }<br />
public static void addRenderableLineSegmentRoundScope( StaticPosition a, StaticPosition b, Color c ) { renderableLineSegmentsRound.add( new RenderableLineSegment( a, b, c ) ); }<br />
public static void addRenderableLineSegmentTurnScope( StaticPosition a, StaticPosition b, Color c ) { renderableLineSegmentsTurn.add( new RenderableLineSegment( a, b, c ) ); }<br />
public static void addRenderableLineSegmentBattleScope( Line2D.Double line, Color c ) { renderableLineSegmentsBattle.add( new RenderableLineSegment( line, c ) ); }<br />
public static void addRenderableLineSegmentRoundScope( Line2D.Double line, Color c ) { renderableLineSegmentsRound.add( new RenderableLineSegment( line, c ) ); }<br />
public static void addRenderableLineSegmentTurnScope( Line2D.Double line, Color c ) { renderableLineSegmentsTurn.add( new RenderableLineSegment( line, c ) ); }<br />
public static void addRenderableRingBattleScope( StaticPosition a, double b, Color c ) { renderableRingsBattle.add( new RenderableRing( a, b, c ) ); }<br />
public static void addRenderableRingRoundScope( StaticPosition a, double b, Color c ) { renderableRingsRound.add( new RenderableRing( a, b, c ) ); }<br />
public static void addRenderableRingTurnScope( StaticPosition a, double b, Color c ) { renderableRingsTurn.add( new RenderableRing( a, b, c ) ); }<br />
public static void addRenderableSquareBattleScope( StaticPosition a, double b, Color c ) { renderableSquaresBattle.add( new RenderableSquare( a, b, c ) ); }<br />
public static void addRenderableSquareRoundScope( StaticPosition a, double b, Color c ) { renderableSquaresRound.add( new RenderableSquare( a, b, c ) ); }<br />
public static void addRenderableSquareTurnScope( StaticPosition a, double b, Color c ) { renderableSquaresTurn.add( new RenderableSquare( a, b, c ) ); }<br />
<br />
public static void onRoundSetup()<br />
{ <br />
renderableLineSegmentsRound.clear();<br />
renderableRingsRound.clear();<br />
renderableSquaresRound.clear();<br />
}<br />
<br />
public static void onTurnSetup()<br />
{<br />
renderableLineSegmentsTurn.clear();<br />
renderableRingsTurn.clear();<br />
renderableSquaresTurn.clear();<br />
}<br />
<br />
public static void onPaint( Graphics2D console )<br />
{<br />
GraphicalDebugger.drawRenderableLineSegments( console, renderableLineSegmentsBattle );<br />
GraphicalDebugger.drawRenderableLineSegments( console, renderableLineSegmentsRound );<br />
GraphicalDebugger.drawRenderableLineSegments( console, renderableLineSegmentsTurn );<br />
GraphicalDebugger.drawRenderableRings( console, renderableRingsBattle );<br />
GraphicalDebugger.drawRenderableRings( console, renderableRingsRound );<br />
GraphicalDebugger.drawRenderableRings( console, renderableRingsTurn );<br />
GraphicalDebugger.drawRenderableSquares( console, renderableSquaresBattle );<br />
GraphicalDebugger.drawRenderableSquares( console, renderableSquaresRound );<br />
GraphicalDebugger.drawRenderableSquares( console, renderableSquaresTurn );<br />
}<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Constants<br />
//:://////////////////////////////////////<br />
<br />
private static final Queue<RenderableLineSegment> renderableLineSegmentsBattle = new LinkedList<RenderableLineSegment>();<br />
private static final Queue<RenderableLineSegment> renderableLineSegmentsRound = new LinkedList<RenderableLineSegment>();<br />
private static final Queue<RenderableLineSegment> renderableLineSegmentsTurn = new LinkedList<RenderableLineSegment>();<br />
private static final Queue<RenderableRing> renderableRingsBattle = new LinkedList<RenderableRing>();<br />
private static final Queue<RenderableRing> renderableRingsRound = new LinkedList<RenderableRing>();<br />
private static final Queue<RenderableRing> renderableRingsTurn = new LinkedList<RenderableRing>();<br />
private static final Queue<RenderableSquare> renderableSquaresBattle = new LinkedList<RenderableSquare>();<br />
private static final Queue<RenderableSquare> renderableSquaresRound = new LinkedList<RenderableSquare>();<br />
private static final Queue<RenderableSquare> renderableSquaresTurn = new LinkedList<RenderableSquare>();<br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Pedersen/Code_Samples/Persistence&diff=16894User:Pedersen/Code Samples/Persistence2010-07-01T08:37:29Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>I have overhauled my persistence implementation. One addition I have made is allowing logging that does not wait until the end of the match before posting anything (through the <nowiki>getPrintStream( filename )</nowiki> method). All methods are static.<br />
<br />
If the dataDirectory value is not provided, all calls will return null instead of the desired content, preventing file I/O (and the potential for the CanonCaches bug). In the setup of my bot I have the following line:<br><br />
<code>if( Constraints.allowFileIO ) Persistence.setDataDirectory( this.getDataDirectory() );</code><br />
<br />
The Console class manages printing of text and exceptions to System.out, which is the tank's log / debug window.<br />
<br />
Modify to taste.<br />
<br />
<hr><br />
<br />
<syntaxhighlight><br />
/**<br />
* Stores and retrieves data from the local cache.<br />
* Data may be targeting or movement statistics, debug information, etc.<br />
* <br />
* @author Martin Alan Pedersen<br />
*/<br />
public class Persistence<br />
{<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Methods<br />
//:://////////////////////////////////////<br />
<br />
public static void setDataDirectory( File newDataDirectory )<br />
{<br />
Persistence.dataDirectory = newDataDirectory;<br />
}<br />
<br />
/**<br />
* Creates a PrintStream that is compatible with RoboCode's file permissions management.<br />
* <br />
* @param filename the name of the data directory file to be written to<br />
*<br />
* @return a print stream associated with the file<br />
*/<br />
public static PrintStream getPrintStream( String filename )<br />
{<br />
PrintStream outputStream = null;<br />
<br />
File dataFile = getDataFile( filename );<br />
if( dataFile != null )<br />
{<br />
try<br />
{<br />
outputStream = new PrintStream( new RobocodeFileOutputStream( dataFile ) );<br />
}<br />
catch( Exception ex )<br />
{<br />
Console.getInstance().log( "Exception thrown opening PrintStream [" + filename + "]." );<br />
Console.getInstance().log( ex );<br />
if( outputStream != null ) outputStream.close();<br />
}<br />
}<br />
<br />
return outputStream;<br />
}<br />
<br />
/**<br />
* Places the contents of a file in a CharBuffer.<br />
* <br />
* @param filename the name of the data directory file to be read from<br />
*<br />
* @return a CharBuffer containing the entire contents of the file<br />
*/<br />
public static CharBuffer getFileContents( String filename )<br />
{<br />
CharBuffer fileContents = null;<br />
<br />
File dataFile = getDataFile( filename );<br />
if( dataFile != null )<br />
{<br />
FileReader inputStream = null;<br />
try<br />
{<br />
inputStream = new FileReader( dataFile );<br />
CharBuffer buffer = CharBuffer.allocate( (int)dataFile.length() );<br />
if( inputStream.read( buffer ) == (int)dataFile.length() )<br />
{<br />
fileContents = buffer;<br />
}<br />
}<br />
catch( Exception ex )<br />
{<br />
Console.getInstance().log( "Exception thrown reading contents of file [" + filename + "]." );<br />
Console.getInstance().log( ex );<br />
}<br />
finally<br />
{<br />
try<br />
{<br />
if( inputStream != null ) inputStream.close();<br />
}<br />
catch( IOException ex )<br />
{<br />
Console.getInstance().log( "Exception thrown closing input stream [" + filename + "]." );<br />
Console.getInstance().log( ex );<br />
}<br />
}<br />
}<br />
<br />
return fileContents;<br />
}<br />
<br />
/**<br />
* Writes a list of strings to a file.<br />
* <br />
* @param list the list of strings<br />
* @param filename the name of the file to write to<br />
*/<br />
public static void writeListToFile( String filename, List list )<br />
{<br />
PrintStream outputStream = getPrintStream( filename );<br />
if( outputStream != null )<br />
{<br />
try<br />
{<br />
Iterator iterator = list.iterator();<br />
while( iterator.hasNext() )<br />
{<br />
outputStream.println( encrypt( (String) iterator.next() ) );<br />
}<br />
}<br />
catch( Exception ex )<br />
{<br />
Console.getInstance().log( "Exception thrown writing list to file" );<br />
Console.getInstance().log( ex );<br />
}<br />
finally<br />
{<br />
if( outputStream != null ) outputStream.close();<br />
}<br />
}<br />
}<br />
<br />
/**<br />
* Reads a file and converts each line into a list entry.<br />
* <br />
* @param filename the name of the file to read.<br />
* <br />
* @return the lines of the file in the form of a list<br />
*/<br />
public static List readListFromFile( String filename )<br />
{<br />
List list = new ArrayList();<br />
<br />
CharBuffer fileContents = getFileContents( filename );<br />
if( fileContents != null )<br />
{<br />
String buffer = fileContents.toString();<br />
int indexStart = 0;<br />
int indexEnd = buffer.indexOf( "\n", indexStart );<br />
while( indexEnd != -1 )<br />
{<br />
list.add( decrypt( buffer.substring( indexStart, indexEnd ) ) );<br />
indexStart = indexEnd + 1;<br />
indexEnd = buffer.indexOf( "\n", indexStart );<br />
}<br />
}<br />
<br />
return list;<br />
}<br />
<br />
<br />
/**<br />
* Gets a data directory file.<br />
* <br />
* @param filename the name of the data file<br />
* <br />
* @return a File object associated with the data file<br />
*/<br />
private static File getDataFile( String filename )<br />
{<br />
File dataFile = null;<br />
<br />
if( dataDirectory != null )<br />
{<br />
dataFile = new File( dataDirectory, mangle( filename ) );<br />
}<br />
<br />
if( dataFile == null )<br />
{<br />
Console.getInstance().log( "Access to file [" + filename + "] is denied." );<br />
}<br />
<br />
return dataFile;<br />
}<br />
<br />
<br />
/**<br />
* Converts readable data into encrypted data.<br />
* <br />
* @param readable the readable data<br />
* <br />
* @return encrypted data<br />
*/<br />
private static String encrypt( String readable )<br />
{<br />
String unreadable = null;<br />
unreadable = readable; // placeholder<br />
return unreadable;<br />
}<br />
<br />
<br />
/**<br />
* Converts encrypted data into readable data.<br />
* <br />
* @param unreadable encrypted data<br />
* <br />
* @return readable data<br />
*/<br />
private static String decrypt( String unreadable )<br />
{<br />
String readable = null;<br />
readable = unreadable; // placeholder<br />
return readable;<br />
}<br />
<br />
<br />
/**<br />
* Converts a string into a file-friendly one. Intended for converting tank names.<br />
* <br />
* @param original the original name<br />
* <br />
* @return the converted filename<br />
*/<br />
private static String mangle( String original )<br />
{<br />
StringBuffer buffer = new StringBuffer();<br />
char character;<br />
for( int i = 0; i < original.length(); i++ )<br />
{<br />
character = original.charAt( i );<br />
if( ( character > 47 ) && ( character < 58 ) ) buffer.append( character );<br />
else if( ( character > 64 ) && ( character < 91 ) ) buffer.append( character );<br />
else if( ( character > 96 ) && ( character < 123 ) ) buffer.append( character );<br />
}<br />
buffer.append( ".txt" );<br />
return buffer.toString();<br />
}<br />
<br />
//:://////////////////////////////////////<br />
//:: Static Variables<br />
//:://////////////////////////////////////<br />
<br />
private static File dataDirectory = null;<br />
<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Nfwu/Painter&diff=16893User:Nfwu/Painter2010-07-01T08:37:24Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{{User:Nfwu/Nav}}<br />
<br />
Something new I wrote to help with my debugging.<br />
Feel free to use, with or without giving credit.<br />
<br />
== Credit ==<br />
To [[David Alves]] for the basic structure, which was from [[DrawingBot]].<br />
<br />
== Usage ==<br />
<br />
Has to be initalized before being used, as so:<br />
<syntaxhighlight><br />
public void run(){<br />
//I want 2 layers<br />
Painter.init(2);<br />
//Register first layer to key '1'<br />
Painter.setupLayer(0, "Enemy Position", java.awt.event.KeyEvent.VK_1); <br />
//Register second layer to key 'w'<br />
Painter.setupLayer(1, "Waves", java.awt.event.KeyEvent.VK_W);<br />
<br />
//other stuff...<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Event handlers to call from bot:<br />
<syntaxhighlight><br />
public void onKeyPressed(java.awt.event.KeyEvent e){<br />
if (Painter.onKeyPressed(e)) return;<br />
// other stuff<br />
}<br />
public void onKeyReleased(java.awt.event.KeyEvent e){<br />
if (Painter.onKeyReleased(e)) return;<br />
// other stuff<br />
}<br />
public void onPaint(java.awt.Graphics2D g){ Painter.onPaint(g); }<br />
</syntaxhighlight><br />
<br />
Interactive Display Controls:<br />
* Holding "key" displays the relevant layer until the key is released.<br />
* Typing Shift+"key" toggles permanent display of a layer.<br />
* Holding "H" shows a list of layer names and their keycodes.<br />
<br />
More complex graphics can be drawn by extending Painter.Renderable.<br />
<br />
== Full Source Code ==<br />
<br />
<syntaxhighlight>package nfwu;<br />
<br />
import robocode.*;<br />
import java.util.Vector;<br />
import java.util.Iterator;<br />
import java.awt.Color;<br />
import java.awt.Graphics2D;<br />
import java.awt.event.KeyEvent;<br />
<br />
// Credit goes to David Alves for basic structure from DrawingBot.<br />
// Added multiple layers for drawing on.<br />
//Event Handlers to call from bot...<br />
/*<br />
public void run(){<br />
//I want 2 layers<br />
Painter.init(2);<br />
//Register first layer to key '1'<br />
Painter.setupLayer(0, "Enemy Position", java.awt.event.KeyEvent.VK_1); <br />
//Register second layer to key 'w'<br />
Painter.setupLayer(1, "Waves", java.awt.event.KeyEvent.VK_W);<br />
<br />
//other stuff<br />
<br />
}<br />
<br />
public void onKeyPressed(java.awt.event.KeyEvent e){<br />
if (Painter.onKeyPressed(e)) return;<br />
// other stuff<br />
}<br />
<br />
public void onKeyReleased(java.awt.event.KeyEvent e){<br />
if (Painter.onKeyReleased(e)) return;<br />
// other stuff<br />
}<br />
<br />
public void onPaint(java.awt.Graphics2D g){ Painter.onPaint(g); }<br />
<br />
*/<br />
<br />
// Interactive Display Controls:<br />
// Holding "key" displays the relevant layer until the key is released.<br />
// Typing Shift+"key" toggles permanent display of a layer.<br />
// Holding "H" shows a list of layer names and their keycodes.<br />
<br />
public class Painter {<br />
public final static int HELP_KEY = KeyEvent.VK_H; //The 'h' key.<br />
public final static float TEXT_HEIGHT = 12.0f;<br />
static boolean isDisplayingHelpMessage;<br />
static boolean isDisplayingLayersList;<br />
static boolean isShiftPressed;<br />
<br />
//Setup stuff<br />
public static void init(int numberOfLayers){//Call before every round<br />
System.out.println("This bot has debugging graphics.");<br />
System.out.println("Hold the '"+KeyEvent.getKeyText(HELP_KEY)+"' key with Paint enabled for help.");<br />
overlays = new DebugOverlay[numberOfLayers];<br />
isDisplayingHelpMessage = true;<br />
isDisplayingLayersList = false;<br />
isShiftPressed = false;<br />
}<br />
public static void setupLayer(int oid, String name, int key, boolean defaultDisp){ //key must be a valid VK_ code!!!<br />
overlays[oid] = new DebugOverlay(name, key, defaultDisp);<br />
}<br />
public static void setupLayer(int oid, String name, int key){<br />
setupLayer(oid, name, key, false);<br />
}<br />
<br />
//Draw Stuff (oid = the layer id)<br />
public static void drawObject(int oid, Renderable r){<br />
overlays[oid].renderables.add(r);<br />
}<br />
<br />
public static void drawLineRect(int oid, Color color, double x1, double y1, double x2, double y2){ //Rectangular Coords as input<br />
drawObject(oid, new Line(x1, y1, x2, y2, color)); <br />
}<br />
<br />
public static void drawLinePol(int oid, Color color, double x1, double y1, double len, double ang){ //Relative polar Coords as input<br />
double x2 = x1 + Math.sin(ang) * len; //NOTE: Robocode Angles... www<br />
double y2 = y1 + Math.cos(ang) * len; <br />
drawObject(oid, new Line(x1, y1, x2, y2, color));<br />
}<br />
<br />
public static void drawCircle(int oid, Color color, double x, double y, double radius){<br />
drawObject(oid, new Circle(x, y, radius, color));<br />
}<br />
<br />
public static void drawPoint(int oid, Color color, double x, double y){<br />
drawObject(oid, new Dot(x, y, color));<br />
}<br />
<br />
public static void drawText(int oid, Color color, double x, double y, String text){<br />
drawObject(oid, new Text(text, x, y, color));<br />
}<br />
//Event Handlers<br />
public static boolean onKeyPressed(KeyEvent e) {<br />
switch (e.getKeyCode()) {<br />
case KeyEvent.VK_SHIFT:<br />
isShiftPressed = true;<br />
return true;<br />
case HELP_KEY:<br />
if (isShiftPressed) isDisplayingHelpMessage = false;<br />
else isDisplayingLayersList = true;<br />
return true;<br />
}<br />
if (isShiftPressed) return false;<br />
for (int i=0;i<overlays.length;++i){<br />
if (overlays[i].key == e.getKeyCode()){<br />
overlays[i].displayed = true;<br />
return true;<br />
}<br />
return false;<br />
}<br />
<br />
public static boolean onKeyReleased(KeyEvent e) {<br />
switch (e.getKeyCode()) {<br />
case KeyEvent.VK_SHIFT:<br />
isShiftPressed = false;<br />
return true;<br />
case HELP_KEY:<br />
if (isShiftPressed) isDisplayingHelpMessage = false;<br />
else isDisplayingLayersList = false;<br />
return true;<br />
}<br />
//Toggle whether or not shift is pressed<br />
for (int i=0;i<overlays.length;++i){<br />
if (overlays[i].key == e.getKeyCode()){<br />
overlays[i].displayed = !overlays[i].displayed;<br />
return true;<br />
}<br />
}<br />
return false;<br />
}<br />
<br />
public static void onPaint(Graphics2D g){<br />
g.setColor(Color.WHITE);<br />
if (isDisplayingHelpMessage) g.drawString("Hold the '"+KeyEvent.getKeyText(HELP_KEY)+"' key for help.", 0.0f, 0.0f);<br />
else if (isDisplayingLayersList) g.drawString("List of avaliable debug graphics layers:", 0.0f, 0.0f);<br />
for (int j=0;j<overlays.length;++j){<br />
if (isDisplayingLayersList){<br />
g.setColor(Color.WHITE);<br />
g.drawString((overlays[j].displayed?"*":" ")+"["+KeyEvent.getKeyText(overlays[j].key)+"]: "+overlays[j].name, 0.0f, (j+1)*TEXT_HEIGHT);<br />
}<br />
if (overlays[j].displayed)<br />
for(int i=0;i<overlays[j].renderables.size();++i){<br />
Renderable r = (Renderable) overlays[j].renderables.get(i);<br />
r.render(g);<br />
}<br />
overlays[j].renderables.clear();<br />
}<br />
if (isDisplayingLayersList){<br />
g.setColor(Color.WHITE);<br />
g.drawString("Holding the key in brackets displays the layer", 0.0f, (overlays.length+1)*TEXT_HEIGHT);<br />
g.drawString("Typing Shift+key toggles permanent display of a layer", 0.0f, (overlays.length+2)*TEXT_HEIGHT);<br />
}<br />
}<br />
<br />
//Implementation<br />
static DebugOverlay[] overlays;<br />
<br />
private static class DebugOverlay {<br />
DebugOverlay(String name, int key, boolean defaultDisp){<br />
this.name = name;<br />
this.key = key;<br />
this.displayed = defaultDisp;<br />
}<br />
Vector renderables = new Vector();<br />
boolean displayed;<br />
int key; //Keycode to toggle display mode<br />
String name;<br />
}<br />
<br />
public static abstract class Renderable {<br />
public abstract void render(Graphics2D g);<br />
} <br />
<br />
private static class Circle extends Renderable {<br />
double x, y, radius;<br />
Color color;<br />
public Circle(double x, double y, double radius, Color color){<br />
this.x = x; this.y = y; this.radius = radius;<br />
this.color = color;<br />
}<br />
public void render(Graphics2D g) {<br />
g.setColor(color);<br />
g.drawOval((int)Math.round(x - radius), (int)Math.round(y - radius),<br />
(int)Math.round(2 * radius), (int)Math.round(2 * radius));<br />
}<br />
}<br />
<br />
private static class Dot extends Circle {<br />
public Dot(double x, double y, Color color){<br />
super(x, y, 2, color); //super(x, y, 2, colour);<br />
}<br />
}<br />
<br />
private static class Line extends Renderable {<br />
double x1, y1, x2, y2;<br />
Color color;<br />
public Line(double x1, double y1, double x2, double y2, Color color){<br />
this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2;<br />
this.color = color;<br />
}<br />
<br />
public void render(Graphics2D g) {<br />
g.setColor(color);<br />
g.drawLine((int)Math.round(x1), (int)Math.round(y1), (int)Math.round(x2), (int)Math.round(y2));<br />
}<br />
}<br />
<br />
private static class Text extends Renderable {<br />
String text;<br />
double x, y;<br />
Color color;<br />
public Text(String text, double x, double y, Color color){<br />
this.text = text;<br />
this.x = x; this.y = y;<br />
this.color = color;<br />
}<br />
public void render(Graphics2D g) {<br />
g.setColor(color);<br />
g.drawString(text, (float)x, (float)y);<br />
}<br />
}<br />
}</syntaxhighlight><br />
<br />
__NOTOC__<br />
<br />
[[Category:Source Code]]</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Nfwu/ELO_Sim&diff=16892User:Nfwu/ELO Sim2010-07-01T08:37:22Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{{User:Nfwu/Nav}}<br />
<br />
Used RR@H server code as reference. No licence - use and abuse.<br />
<br />
Running the code as-is outputs ratings of bots A, B and C for this scenario:<br><br />
A vs B = 25/75<br><br />
A vs C = 75/25<br><br />
B vs C = 25/75<br />
<br />
Code:<br />
<syntaxhighlight><br />
package roborumble;<br />
<br />
import java.util.*;<br />
<br />
// There are faster ways of doing this,<br />
// but I wanted to replicate the RR@H server as close as possible.<br />
// <br />
// So, here's an inefficent ELO simulator.<br />
<br />
class EnemyStat {<br />
double wins;<br />
int benemy; //Looks like "Number of Battles agains this enemy"<br />
}<br />
<br />
class RobotStats {<br />
<br />
RobotStats(String n){<br />
this(n, 1600);<br />
}<br />
RobotStats(String n, double r){<br />
scoremap = new HashMap<String, EnemyStat>();<br />
post = false;<br />
name = n;<br />
battles = 0;<br />
rating = r;<br />
}<br />
<br />
String name;<br />
int battles;<br />
double rating;<br />
boolean post;<br />
HashMap<String, EnemyStat> scoremap;<br />
}<br />
<br />
public class Test {<br />
private static final double min_score = 0.0;<br />
<br />
private static final double max_score = 1.0;<br />
<br />
private static final double rating_change = 3.0;<br />
<br />
static RobotStats[] stats;<br />
public static void main(String[] args){<br />
//stats = new RobotStats[4];<br />
stats = new RobotStats[3];<br />
<br />
stats[0] = new RobotStats("BotA 1.0");<br />
stats[1] = new RobotStats("BotB 1.0");<br />
stats[2] = new RobotStats("BotC 1.0");<br />
<br />
//POST EXPERIMENT<br />
//stats[3] = new RobotStats("Post", 2000);<br />
//stats[3].post = true;<br />
<br />
//A/B=25/75, A/C=75/25, BC=25/75<br />
int rand;<br />
for (int i=0;i<1000;i++){<br />
rand = (int)(Math.random() * 6.0);<br />
if (rand == 1){<br />
//battleResults(0, 24.5+Math.random(), 1, 74.5+Math.random());<br />
battleResults(0, 25, 1, 75);<br />
} else if (rand == 2){<br />
//battleResults(1, 74.5+Math.random(), 0, 24.5+Math.random());<br />
battleResults(1, 75, 0, 25);<br />
} else if (rand == 3){<br />
//battleResults(0, 74.5+Math.random(), 2, 24.5+Math.random());<br />
battleResults(0, 75, 2, 25);<br />
} else if (rand == 4){<br />
//battleResults(2, 24.5+Math.random(), 0, 74.5+Math.random());<br />
battleResults(2, 25, 0, 75);<br />
} else if (rand == 5){<br />
//battleResults(1, 49.5+Math.random(), 2, 49.5+Math.random());<br />
battleResults(1, 25, 2, 75);<br />
} else {<br />
//battleResults(2, 49.5+Math.random(), 1, 49.5+Math.random());<br />
battleResults(2, 75, 1, 25);<br />
}<br />
//battleResults((int)(Math.random()*3), 50, 3, 50); //FROM POST EXPERIMENT<br />
}<br />
<br />
for (int i=0;i<stats.length;i++){<br />
System.out.println(stats[i].name+" - Battles "+stats[i].battles+" - Rating "+stats[i].rating);<br />
}<br />
<br />
}<br />
static void battleResults(int fid, double fscore, int sid, double sscore){<br />
//Get stuff for first<br />
double real1 = fscore / (fscore + sscore);<br />
if (real1 == 1.0 || real1 == 0.0) return; //RR@H server does this<br />
EnemyStat es1 = null;<br />
es1 = stats[fid].scoremap.get(stats[sid].name); //First's enemy data of second<br />
double wins1 = real1; if (es1 != null) wins1 = es1.wins;<br />
int benemy1 = 0; if (es1 != null) benemy1 = es1.benemy;<br />
//Get stuff for second<br />
double real2 = 1.0 - real1;<br />
EnemyStat es2 = null;<br />
es2 = stats[sid].scoremap.get(stats[sid].name); //Second's enemy data of first<br />
double wins2 = real1; if (es2 != null) wins2 = es2.wins;<br />
int benemy2 = 0; if (es2 != null) benemy2 = es2.benemy;<br />
//Calculate EnemyStat differences<br />
wins1 = 0.7 * wins1 + 0.3 * real1;<br />
<br />
wins2 = 0.7 * wins2 + 0.3 * real2;<br />
benemy1++;<br />
benemy2++;<br />
//Store the EnemyStats away<br />
if (es1 == null) {<br />
es1 = new EnemyStat(); <br />
}<br />
es1.wins = wins1;<br />
es1.benemy = benemy1;<br />
stats[fid].scoremap.put(stats[sid].name, es1); //First's enemy data of second<br />
if (es2 == null) {<br />
es2 = new EnemyStat(); <br />
}<br />
es2.wins = wins2;<br />
es2.benemy = benemy2;<br />
stats[sid].scoremap.put(stats[fid].name, es2); //Second's enemy data of first<br />
<br />
//Calculate rating change, anchored to all the other bots.<br />
double change1 = 0;<br />
<br />
double change2 = 0;<br />
for (int i=0;i<stats.length;i++) {<br />
//selectedrating = stats[i].rating;<br />
<br />
//Do stuff for first<br />
if (fid != i){<br />
double expected = 1.0 / (1+Math.pow(20,(stats[i].rating-stats[fid].rating)/800)); <br />
expected = Math.max(Math.min(expected,max_score),min_score);<br />
if (stats[fid].scoremap.get(stats[i].name) != null){<br />
double selectedwins = stats[fid].scoremap.get(stats[i].name).wins;<br />
selectedwins = Math.max(Math.min(selectedwins,max_score),min_score);<br />
<br />
change1 += rating_change * (selectedwins - expected);<br />
}<br />
}<br />
//Do stuff for second<br />
if (sid != i){<br />
double expected = 1.0 / (1+Math.pow(20,(stats[i].rating-stats[sid].rating)/800)); <br />
expected = Math.max(Math.min(expected,max_score),min_score);<br />
if (stats[sid].scoremap.get(stats[i].name) != null){<br />
double selectedwins = stats[sid].scoremap.get(stats[i].name).wins;<br />
selectedwins = Math.max(Math.min(selectedwins,max_score),min_score);<br />
<br />
change2 += rating_change * (selectedwins - expected);<br />
}<br />
}<br />
}<br />
<br />
if (!stats[fid].post) stats[fid].rating += change1;<br />
if (!stats[sid].post) stats[sid].rating += change2;<br />
<br />
stats[fid].battles++;<br />
stats[sid].battles++;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
[[Category:Source Code]]</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Nat/TargetingProblem&diff=16891User:Nat/TargetingProblem2010-07-01T08:37:18Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Can anyone answer my question?<br />
<br />
I've some targeting system that I create it accidentally and it work well (for those nanobot):<br />
<br />
<syntaxhighlight><br />
double absBearing, vel;<br />
<br />
// find average velocity<br />
avgVelocity = (avgVelocity + Math.abs(vel = e.getVelocity())) / 2; // the avgVelocity is preloaded as 4<br />
<br />
// Targeting<br />
setTurnGunRightRadians(robocode.util.Utils.normalRelativeAngle(<br />
(e.getBearingRadians() + getHeadingRadians()) + <br />
Math.asin(<br />
// This is a magical line! at first it look like this:<br />
// Math.sin(e.getDistance()) * vel<br />
// but for hit StopNGo movement, I must assume a magic velocity in order to<br />
// hit it. I also need an average velocity in order to hit SittingDuck!<br />
Math.sin(e.getDistance()) * ((avgVelocity < 0.00001 || vel > 0.5) ? vel : 4.5 * ((vel > 0) ? 1 : -1))<br />
/ (20 - 3 * 2)<br />
)<br />
- getGunHeadingRadians()<br />
));<br />
<br />
// 2 is cheaper than 1.9!<br />
setFire(2D);<br />
</syntaxhighlight><br />
That code copy almost exactly from one of my robot using it (not yet released). Can anyone answer me how this gun hit so much, or it just one kind of [[RandomTargeting]]?<br />
<br />
Note: I don't have answer, this is not a joke!<br /><br />
Note: Please answer on this page, not a discussion page!<br />
<br />
----<br />
<br />
Well, having <code>Math.sin(e.getDistance())</code> is a huge randomizer, so I'd definitely call this a form of random targeting. As I'm understanding the code, it seems like <code>avgVelocity < 0.00001</code> will only be true if the enemy doesn't move for a while, and in that case vel = 0, so you'll be shooting head-on. Other than that special case, it looks like you're shooting at a random angle between Math.asin(4.5 / bullet speed) and its inverse; I don't think you'll ever hit a bot that just orbits you without ever stopping, though, because the max escape angle is Math.asin(8 / bullet speed). But I'm just giving this a quick look right now, sorry if I misunderstood something. --[[User:Voidious|Voidious]] 17:35, 14 January 2009 (UTC)<br />
<br />
No, the <code>((avgVelocity < 0.00001 || vel > 0.5) ? vel : 4.5 * ((vel > 0) ? 1 : -1))</code> is for hit the StopNGo movement, where the fire time its velocity is zero and it end up firing head-on so <code>vel > 0.5</code> check that it's moving or not, and <code>avgVelocity < 0.00001</code> check is enemy SittingDuck or not :)<br />
<br />
Well, I know that trig function are randomizer, but if distance and velocity are same then the firing angle is the same, too. I think I'd call it semi-random targeting.<br />
<br />
Thank you for your answer,[[User:Voidious|Voidious]] --[[User:Nat|Nat]] 12:16, 15 January 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Nat/WaveSurfingQuestion&diff=16890User:Nat/WaveSurfingQuestion2010-07-01T08:37:16Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Hi all, I have some questions about wave surfing.<br />
<br />
First, define some term I'll use in this question:<br />
* Surfer: all those surfer around today.<br />
* Wave Surfer: a surfer that log hit for every waves.<br />
* Hit Surfer: a surfer that log hit on only hit waves.<br />
* log hit: the operation that same as BasicSurfer's logHit function.<br />
<br />
; Question 1<br />
:What is the differnce between Wave Surfer and Hit Surfer? On first time I looked into surfing, the statement I found is "Surfing is exactly reverse of GuessFactor Targeting" so I understand surfer as Wave Surfer. But, when I looked into code of DussGT, Dookious, Horizona and PhonixOS, I found out that they are Hit Surfer (unless it enable its flattener which turn them into Wave Surfer). Only Butterfly I've recognize that it's Wave Surfer.<br />
<br />
:* Well, I know of NO surfer that logs non-hitting waves EXCEPT for flattener purposes. Bufferfly is included in this statement. As far as terminology, the "Wave" in "Wave Surfer" traditionally ''doesn't'' refer to the capture of the data, it refers to how you generate the movement from the stats. "Wave Surfing" is any movement which has a movement that attempts to get to specific 'low danger' [[GuessFactor|guessfactors]] as the wave passes, and by this definition does not specify whether 'low danger' is determined by hits or flattening stats, or even pattern matcher simulation. As far as the difference between surfing that logs hits verses logs one that logs non-hits equally? The difference is exactly the difference between a bullet-dodger and movement-flattener. That answer the question? --[[User:Rednaxela|Rednaxela]] 04:14, 22 February 2009 (UTC)<br />
<br />
:* Really? If that so, the statement on WaveSurfing/Tutorial should be wrong. It say like above. So now, my BlackHole will act like it always enabled its flattener, right? I am first confused by BasicSurfer code since it does not do exactly like reverse GF so I change that :) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:02, 22 February 2009 (UTC)<br />
<br />
::* Yep really. I'm not sure what you mean by "does not do exactly like reverse GF". --[[User:Rednaxela|Rednaxela]] 17:47, 22 February 2009 (UTC)<br />
<br />
::* Mean as the word. GF recorded every wave but surfer only recorded the HIT wave :) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 18:20, 22 February 2009 (UTC)<br />
<br />
:* The point of wave surfing is to dodge enemy bullets. We cannot make the assumption that they have a strong gun, because there are many bots in the rumble with simple linear/circular/headon guns. So to avoid their bullets, we avoid GFs where we have found their bullets before. One way of finding their bullets is being hit by them, another is from bullet-hit-bullet. The only reason that one would need to dodge places where we have been, and not where they are shooting, is if they are adapting their shooting faster than we are adapting our movement. --[[User:Skilgannon|Skilgannon]] 20:04, 22 February 2009 (UTC)<br />
<br />
:* OK, I understand the point now :) Thanks! &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:48, 23 February 2009 (UTC)<br />
<br />
;Question 2<br />
:How can I create a gradient color for wave like Phoenix does? My style of BlackHole are a bit ugly... :(<br />
<br />
:* You have to do math and work with the java.awt.Color class. For example:<br />
<syntaxhighlight><br />
Color rainbow = Color.getHSBColor(somenumber, 1, 1);<br />
Color gradient = new Color(255, somenumber*255, 255-somenumber*255);<br />
</syntaxhighlight><br />
::I suggest you experiment perhaps :) --[[User:Rednaxela|Rednaxela]] 04:27, 22 February 2009 (UTC)<br />
<br />
:* Whoop! I forgot about HSB! I've try your second way many times but I result in really bad color :( Thanks &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:02, 22 February 2009 (UTC)<br />
<br />
;Question 3<br />
:What will act faster and less memory consume?<br />
<br />
* Multiple buffers VCS stats with 16 segmentation.<br />
* One Kd-Tree but difference dimension calculator.<br />
<br />
:My new BlackHole v1 (not v2) will have around 1000 buffers and up to 16 segmentations. I ask here to develop my robot in right way.<br />
<br />
:* Compared to about 1000 VCS buffers? Definitely the Kd-Tree in that case. You could also consider an "interpolated VCS" approach like I explore in [[User:Rednaxela/SaphireEdge]], it's rarther non-traditional but I got it working quite strong, and I think it's better in both memory and cpu requirements than many VCS buffers or a Kd-Tree. --[[User:Rednaxela|Rednaxela]] 04:58, 22 February 2009 (UTC)<br />
<br />
:* Can you explain more? I currently not understand every thing you talk about :( &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:02, 22 February 2009 (UTC)<br />
<br />
::* What part do you want me to explain more? The interplated VCS thing? Also the statement "By default, a DC bot will slower but less memory consume, VCS usually faster but much more memory consume." on your page isn't really correct. A kd tree will not be faster than a ''small'' number of VCS buffers, only faster than a very ''large'' number. And as far as memory consumption whie the DC uses less at the very very start of the battle it can grow larger than memory use of a small number of VCS buffers in as short as one or two rounds. --[[User:Rednaxela|Rednaxela]] 17:47, 22 February 2009 (UTC)<br />
<br />
::* Yes, the interplated VCS. Actually, everything! I've read your [[User:Rednaxela/SaphireEdge]] page and get confused on what is interplated VCS? What is antialias? and many more. Also, I really mean a large VCS buffer on my user page. At nearly 100 buffers, up to 10 dimension each, containing 9999 bins a buffer. No ideas on how this run in time? I've no ideas, too<br />
<br />
:::* Interpolated means spread out. So interpolated VCS is where you 'smooth' not only into nearby bins but also into nearby dimensions. --[[User:Skilgannon|Skilgannon]] 20:04, 22 February 2009 (UTC)<br />
<br />
::::* Well, it's not quite 'smoothing', as 'smoothing' would imply spreading it over many diferent data points, when interpolation means to only mix it between ones that the actual values of dimensions are directly inbetween. --[[User:Rednaxela|Rednaxela]] 20:19, 22 February 2009 (UTC)<br />
<br />
:::* To explain in more detail: the interpolated VCS works like this: Let's say for sake of discussion you have 1 dimension with 2 segments, one segment is centered on a value of 0 and the other centered on a value of 1. What do you do if the actual value is 0.5? Pretty much all previous VCS implementations will either round up or down in that case. The point of my "interpolated VCS" is to in that case, write to BOTH segments in that case, with half the value as otherwise added to each bin. What if the actual value is 0.75? What I do then is I add 0.75 to the bin centered at '1' and add 0.25 to the bin centered at '0'. Similarly, if you want to read from your data, and the actual situation is not exactly on the center of a segment, I mix data between in the same way. Note that this mixed reading is basically 'antialiasing'. I then extend this principal to multiple different axis of segmentation, which means that for a given situation I'd be writing/reading as many as 2^n different sets of bins, where n is the number of segments. This makes for far far more accurate VCS, allowing me to with a '''single''' VCS buffer get scores comparable to DC or many VCS buffers. This does increase computation cost notably however takes no more memory than a single normal VCS buffer would, and the computation cost is still comparable to DC or multi-VCS-buffers that result in similar strength. --[[User:Rednaxela|Rednaxela]] 20:19, 22 February 2009 (UTC)<br />
<br />
::::* Thanks! I think I understand it. Quick question: Do your reading weight each bin using the difference? Or it do in other way. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:48, 23 February 2009 (UTC)<br />
<br />
;Question 4<br />
:What is the simple way to calculate bot width for surfing? DurssGT style is complicated. I'm now create 25px circle and calculate each bins it covered.<br />
<br />
:*The simple way? The 'simple' angular botwidth is just 2*arctan(18px/distance), convert to GF etc as you wish. Btw, "DrussGT style" was first used by [[Garm]], then independtly rediscovered in [[RougeDC]] (I made some explaination [http://robowiki.net/cgi-bin/robowiki?Rednaxela/SuperBotwidth] here), and then added in [[DrussGT]]. Other than those three however, EVERY bot I know essentially uses something like 2*arctan(18px/distance). Note, 36px is the width of the collision square of the bot. --[[User:Rednaxela|Rednaxela]] 04:58, 22 February 2009 (UTC)<br />
<br />
:* Is you formula return a radians? My way is as simple as you can think without any knowledge on trig :) I project current bot position front and back by 25px (the distance from center to corner of bot) and convert it to GF using BasicSurfer's getFactorIndex() function. Using these as covered GF. Much simpler. Or you have any more ideas? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:02, 22 February 2009 (UTC)<br />
<br />
::* Yep, that formula returns a value in radians. As far as the trig: Picture a right-angle triangle, the right angle is on the far side from you and you want to calculate the angle: The line from the measured angle to the right angle is called 'adjacent', and the one far from the measured angle is called the 'opposite', and arctan works like this: "radianangle = arctan(opposite / adjacent)" by definition. But anyways, the getFactorIndex() approach isn't really simpler than the 2*arctan(18/distance) approach in terms of quantity of code it takes, and it's also a bit slower for the computer. Really, they'd give the exact same final result, except that the arctan method has less redundant calculation. In any case though, the getFactorIndex() approach is perfectly fine. I would however suggest that when calculating the covered gfs for any purpose ''except'' surfing, not using 25px, because often the actual width is considerably less and I think that only in surfing is it best to err on the large side. --[[User:Rednaxela|Rednaxela]] 17:47, 22 February 2009 (UTC)<br />
<br />
::* OK, I have problem on converting between radians <-> GF <-> bin index. Does it use (radians/MEA * (BINS/2)) + MIDDLE_BIN? and ((INDEX-MIDDLE_BIN)/(BINS/2))*MEA? Also, I've seen many bot check their VB with 25px radius. Phoenix circle it's current target with radius 25px, too. (Not know in it's internal stats) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 18:20, 22 February 2009 (UTC)<br />
:::* Yep, those radian <-> GF <-> bin index calculations are correct I believe. --[[User:Rednaxela|Rednaxela]] 20:31, 22 February 2009 (UTC)<br />
<br />
:* If you want to be very precise, take the four corners of the bot (+-15 to x and y) and call getIndex on each. The reason I have a complicated method in DrussGT is because I have to account for the movement as the wave passes over the bot, since my precise prediction doesn't access the wave, or know where it is or what it does or anything. --[[User:Skilgannon|Skilgannon]] 20:04, 22 February 2009 (UTC)<br />
<br />
::* Erm... I'm very sure it's 18, not 15, but otherwise yeah, that's a good method. --[[User:Rednaxela|Rednaxela]] 20:31, 22 February 2009 (UTC)<br />
<br />
::* It's 18 actually... 13:48, 23 February 2009 (UTC)<br />
<br />
:* Then do max and min on these value to get covered guess factors, right? I've some idea on fancy bot-width using this now. Do this every turns that the wave intersect with bot, keep the old max/min in account, too. That shall result in the simplest of the fancy bot-width right now I think. Only one problem, it expensive :) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:48, 23 February 2009 (UTC)<br />
<br />
;Question 5<br />
: What is better:<br />
* Surf the wave until it pass rear edge of the robot.<br />
* Surf the wave until it pass middle of the robot.<br />
* Surf the wave until it reach front edge of the robot.<br />
:? <br />
<br />
:* Well, ideally, you use a mix. What I do in RougeDC, is I use the crazy precice botwidth calcuation, and as the wave passes through the bot, I set guessfactors that already would have ''already'' hit the bot to 0 danger, and keep surfing the remaining parts of the wave that aren't zero'ed out. If you're not using that kind of fancy botwidth though, I'd suggest near the middle, maybe leaning towards the front. --[[User:Rednaxela|Rednaxela]] 06:01, 22 February 2009 (UTC)<br />
<br />
:* Is that? I sometimes found that my robot stop at position that will not be hit by bullets, but when the the wave passed the center, it move again and finally hit! so I not sure. But that a good ideas, I'll try it out... &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 11:02, 22 February 2009 (UTC)<br />
<br />
::* Well, that can happen, however usually if the bot is so close to a bullet that it would move onto it sideways, then it didn't really have a good idea where it was to begin with. Also, consider this: If you surf until it reaches the rear edge, then your bot may not get the front edge out of the way in time. I don't know any bots that do this, but one solution to make this situation better without using fancy botwidth calculations, is to when the wave is far away, only consider how far the bot can move till the wave hits the front, BUT once the wave begins to intersect the bot, start making calcuations with regards to when it would pass the rear edge. --[[User:Rednaxela|Rednaxela]] 17:47, 22 February 2009 (UTC)<br />
<br />
::* Nice ideas! but really hard to implements :( I don't really understand what you mean by "calculations with regards to when it would pass the rear edge"? &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 18:20, 22 February 2009 (UTC)<br />
<br />
:* I surf until the wave hits the front edge, and then take into account what the danger would be for me to start decelerating once it hits me. Out of all the options I've tried it worked best, and I have no idea why. --[[User:Skilgannon|Skilgannon]] 20:04, 22 February 2009 (UTC)<br />
----<br />
== Round 2 ==<br />
; Question 1<br />
: If I create WS-GT bot that almost has 0 velocity at fire time, will it act like StopNGo for LT and CT? If do so, I'll implements this in [[Galaxy]]... &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 18:20, 22 February 2009 (UTC)<br />
<br />
*Unless you have complete stop an fire time it's not quite good enough. After all my tweaking the [[Stop And Go]] with [[Waylander]] and later [[Toolkild]] this is one thing that has stuck with me. --[[User:Skilgannon|Skilgannon]] 20:04, 22 February 2009 (UTC)<br />
<br />
*OK, that seem to be clear for me. I've test with your BasicGTSurfer. Instead of removing 1 points, I removed 3. Now, test with David's LinearTargetingNot and CircularTargetingBot result them firing HOT in almost situation :) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 13:48, 23 February 2009 (UTC)<br />
<br />
*When you have a velocity near 0 at fire time, it will act like [[Stop And Go]] for LT and CT (see for example [[Gruwel]]). However, the rigid and clean implementation of a real Stop And Go, like [[Skilgannon]] said, will be more effective. --[[User:GrubbmGait|GrubbmGait]] 22:24, 23 February 2009 (UTC)<br />
----<br />
== Round 3 ==<br />
; Question 1<br />
: Drive Protection is designed to avoid moving close to enemy, right? It is (mostly) implements by divide danger by distance. Now, I come up with some corner avoidance. if we divide danger by <code>Math.max(dist2wallN, dist2wallS) + Math.max(dist2wallE, dist2wallW)</code>. Will it avoid getting cornered? (PS. I'm writing the test bot now) &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 03:59, 2 April 2009 (UTC)<br />
::* Well I don't have any similar implementation for distance protection, so I pulling ideas out of my head only. But I would guess it makes more sense to use <code>Math.min(...)</code> instead of <code>Math.max(...)</code>.<br />
::* Another thing is that I usually don't like additions for something like that. But I have no ideas to help out there, try it and see. Tweak it using multiplication, or dividing danger against the North/South distance on one side and against West/East on the other and them add those results instead.<br />
::* I really have no idea what could be better, but maybe you can try some and see which gives you better results. But as you have it I believe the center of the field is more dangerous than the corners. In a 800x600 field, assuming danger as 1 always.<br />
:::* 1 / (400 + 300) = 0.001... for the center of the field.<br />
:::* 1 / (782 + 582) = 0.0007... for the lower left corner (18, 18)<br />
Hope it helps/ --[[User:Zyx|zyx]] 05:04, 2 April 2009 (UTC)<br />
<br />
*Oh wait! It should be min, not max :-) So lower left should have danger of 0.027.... I'm now think of multiply of each min dist squared. For that way distance protection, I believed it was first use in Dookious, then Komarious. Also DrussGT. Thanks for your comment. &raquo; <span style="font-size:0.9em;color:darkgreen;">[[User:Nat|Nat]] | [[User_talk:Nat|Talk]]</span> &raquo; 05:31, 2 April 2009 (UTC)<br />
:* Yes, with min it is better for sure :). But it will in my opinion it will avoid walls too much, and being close to a wall, but ''parallel'' to it isn't so bad I believe. Maybe using the angle to the wall can be helpful also, I would only divide if say both min wall distances are below some threshold, so it won't try to keep aways from a wall instead of corners. --[[User:Zyx|zyx]] 06:46, 2 April 2009 (UTC)</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Nat/DrawingBot&diff=16889User:Nat/DrawingBot2010-07-01T08:37:13Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>{{Nat/Navbar}}<br />
My new painter for [[BlackHole]]. It much like David's DrawingBot but feature more shapes and style. Note that this painter is untested now, if you see any exception, please let me know here.<br />
<br />
You can either make it a class within your robot or extend this class (of course, edit this class to extends AdvancedRobot).<br />
<br />
This code is a bit messy because it spent 2 hours wrote constructor for those shape classes and forget that they are private! <br />
<br />
<syntaxhighlight><br />
package nat.wiki;<br />
<br />
import java.awt.Color;<br />
import java.awt.Graphics2D;<br />
import java.awt.geom.Line2D;<br />
import java.awt.geom.Point2D;<br />
import java.awt.geom.Rectangle2D;<br />
import java.util.ArrayList;<br />
import java.util.List;<br />
<br />
import robocode.util.Utils;<br />
<br />
/**<br />
* Robocode Graphics Drawer<br />
* <br />
* This class provide a graphical interface to robocode internal drawer. You can<br />
* draw anything from simple dot to a modern ellipse.<br />
* <br />
* CREDIT: David Alves and his DrawingBot is father of this class. But it is<br />
* heavily modify by Nat.<br />
* <br />
* Currently support: Dot, Line, Circle, Ellipse, Arc, Rectangle and Text.<br />
* <br />
* @author Nat, David Alves<br />
*/<br />
public class BHDrawer {<br />
/**<br />
* Store all pending renders for this turn.<br />
*/<br />
public static List<Renderable> renderables;<br />
<br />
/**<br />
* Initialize a variable.<br />
*/<br />
public BHDrawer() {<br />
renderables = new ArrayList<Renderable>();<br />
}<br />
<br />
/**<br />
* Paint pending renders to screen.<br />
* <br />
* @param g<br />
* Context to paint to.<br />
*/<br />
public void onPaint(Graphics2D g) {<br />
for (Renderable r : renderables)<br />
r.render(g);<br />
renderables.clear();<br />
}<br />
<br />
public void drawDot(Point2D center) {<br />
renderables.add(new Renderable.Dot(center));<br />
}<br />
<br />
public void drawDot(Point2D center, Color color) {<br />
renderables.add(new Renderable.Dot(center, color));<br />
}<br />
<br />
public void drawCircle(Point2D center, double radius) {<br />
renderables.add(new Renderable.Circle(center, radius));<br />
}<br />
<br />
public void drawCircle(Point2D center, double radius, Color color) {<br />
renderables.add(new Renderable.Circle(center, radius, color));<br />
}<br />
<br />
public void fillCircle(Point2D center, double radius) {<br />
renderables.add(new Renderable.Circle(center, radius, true));<br />
}<br />
<br />
public void fillCircle(Point2D center, double radius, Color color) {<br />
renderables.add(new Renderable.Circle(center, radius, true, color));<br />
}<br />
<br />
public void drawEllipse(Point2D center, double width, double height) {<br />
renderables.add(new Renderable.Ellipse(center, width, height));<br />
}<br />
<br />
public void drawEllipse(Point2D center, double width, double height,<br />
Color color) {<br />
renderables.add(new Renderable.Ellipse(center, width, height, color));<br />
}<br />
<br />
public void fillEllipse(Point2D center, double width, double height) {<br />
renderables.add(new Renderable.Ellipse(center, width, height, true));<br />
}<br />
<br />
public void fillEllipse(Point2D center, double width, double height,<br />
Color color) {<br />
renderables.add(new Renderable.Ellipse(center, width, height, true,<br />
color));<br />
}<br />
<br />
public void drawArc(Point2D center, double startAngle, double arcAngle,<br />
double radius) {<br />
renderables<br />
.add(new Renderable.Arc(center, startAngle, arcAngle, radius));<br />
}<br />
<br />
public void drawArc(Point2D center, double startAngle, double arcAngle,<br />
double radius, Color color) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle,<br />
radius, color));<br />
}<br />
<br />
public void drawArc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle, width,<br />
height));<br />
}<br />
<br />
public void drawArc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height, Color color) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle, width,<br />
height, color));<br />
}<br />
<br />
public void fillArc(Point2D center, double startAngle, double arcAngle,<br />
double radius) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle,<br />
radius, true));<br />
}<br />
<br />
public void fillArc(Point2D center, double startAngle, double arcAngle,<br />
double radius, Color color) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle,<br />
radius, true, color));<br />
}<br />
<br />
public void fillArc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle, width,<br />
height, true));<br />
}<br />
<br />
public void fillArc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height, Color color) {<br />
renderables.add(new Renderable.Arc(center, startAngle, arcAngle, width,<br />
height, true, color));<br />
}<br />
<br />
public void drawRectangle(Rectangle2D rect) {<br />
renderables.add(new Renderable.Rectangle(rect));<br />
}<br />
<br />
public void drawRoundRectangle(Rectangle2D rect) {<br />
renderables.add(new Renderable.Rectangle(rect, false, true));<br />
}<br />
<br />
public void drawRectangle(Rectangle2D rect, Color color) {<br />
renderables.add(new Renderable.Rectangle(rect, color));<br />
}<br />
<br />
public void drawRoundRectangle(Rectangle2D rect, Color color) {<br />
renderables.add(new Renderable.Rectangle(rect, false, true, color));<br />
}<br />
<br />
public void fillRectangle(Rectangle2D rect) {<br />
renderables.add(new Renderable.Rectangle(rect, true));<br />
}<br />
<br />
public void fillRoundRectangle(Rectangle2D rect) {<br />
renderables.add(new Renderable.Rectangle(rect, true, true));<br />
}<br />
<br />
public void fillRectangle(Rectangle2D rect, Color color) {<br />
renderables.add(new Renderable.Rectangle(rect, true, color));<br />
}<br />
<br />
public void fillRoundRectangle(Rectangle2D rect, Color color) {<br />
renderables.add(new Renderable.Rectangle(rect, true, true, color));<br />
}<br />
<br />
public void drawLine(Line2D line) {<br />
renderables.add(new Renderable.Line(line));<br />
}<br />
<br />
public void drawLine(Line2D line, Color color) {<br />
renderables.add(new Renderable.Line(line, color));<br />
}<br />
<br />
public void drawLine(Point2D p1, Point2D p2) {<br />
renderables.add(new Renderable.Line(p1, p2));<br />
}<br />
<br />
public void drawLine(Point2D p1, Point2D p2, Color color) {<br />
renderables.add(new Renderable.Line(p1, p2, color));<br />
}<br />
<br />
public void drawText(String text, Point2D loc) {<br />
renderables.add(new Renderable.Text(text, loc));<br />
}<br />
<br />
public void drawText(String text, Point2D loc, Color color) {<br />
renderables.add(new Renderable.Text(text, loc, color));<br />
}<br />
<br />
public void drawText(String text, double x, double y) {<br />
renderables.add(new Renderable.Text(text, x, y));<br />
}<br />
<br />
public void drawText(String text, double x, double y, Color color) {<br />
renderables.add(new Renderable.Text(text, x, y, color));<br />
}<br />
<br />
/**<br />
* Abstract class Renderable, superclass for all render.<br />
*/<br />
private static abstract class Renderable {<br />
/**<br />
* Render the graphic.<br />
* <br />
* @param g<br />
* Context to render to.<br />
*/<br />
public abstract void render(Graphics2D g);<br />
<br />
/**<br />
* Default constant<br />
*/<br />
public static final Color DEFAULT_COLOR = Color.white;<br />
public static final boolean DEFAULT_FILLED = false;<br />
<br />
/**<br />
* For render Ellipse object (including Circle and Dot)<br />
*/<br />
private static class Ellipse extends Renderable {<br />
private Point2D center;<br />
private double width, height;<br />
private Color color;<br />
private boolean filled;<br />
<br />
public Ellipse(Point2D center, double radius) {<br />
this(center, radius * 2, radius * 2);<br />
}<br />
<br />
public Ellipse(Point2D center, double radius, Color color) {<br />
this(center, radius * 2, radius * 2, DEFAULT_FILLED, color);<br />
}<br />
<br />
public Ellipse(Point2D center, double radius, boolean filled) {<br />
this(center, radius * 2, radius * 2, filled, DEFAULT_COLOR);<br />
}<br />
<br />
public Ellipse(Point2D center, double radius, boolean filled,<br />
Color color) {<br />
this(center, radius * 2, radius * 2, filled, color);<br />
}<br />
<br />
public Ellipse(Point2D center, double width, double height) {<br />
this(center, width, height, DEFAULT_FILLED, DEFAULT_COLOR);<br />
}<br />
<br />
public Ellipse(Point2D center, double width, double height,<br />
boolean filled) {<br />
this(center, width, height, filled, DEFAULT_COLOR);<br />
}<br />
<br />
public Ellipse(Point2D center, double width, double height,<br />
Color color) {<br />
this(center, width, height, DEFAULT_FILLED, color);<br />
}<br />
<br />
public Ellipse(Point2D center, double width, double height,<br />
boolean filled, Color color) {<br />
this.center = center;<br />
this.width = width;<br />
this.height = height;<br />
this.color = color;<br />
this.filled = filled;<br />
}<br />
<br />
@Override<br />
public void render(Graphics2D g) {<br />
g.setColor(color);<br />
int x, y, w, h;<br />
x = (int) Math.round(center.getX() - width / 2);<br />
y = (int) Math.round(center.getY() - height / 2);<br />
w = (int) Math.round(width);<br />
h = (int) Math.round(height);<br />
if (filled)<br />
g.fillOval(x, y, w, h);<br />
else<br />
g.drawOval(x, y, w, h);<br />
}<br />
}<br />
<br />
/**<br />
* Circle is one of Ellipse object, but only define explicit<br />
* constructors for circle only!<br />
*/<br />
private static class Circle extends Ellipse {<br />
public Circle(Point2D center, double radius) {<br />
super(center, radius);<br />
}<br />
<br />
public Circle(Point2D center, double radius, Color color) {<br />
super(center, radius, color);<br />
}<br />
<br />
public Circle(Point2D center, double radius, boolean filled) {<br />
super(center, radius, filled);<br />
}<br />
<br />
public Circle(Point2D center, double radius, boolean filled,<br />
Color color) {<br />
super(center, radius, filled, color);<br />
}<br />
}<br />
<br />
/**<br />
* Dot is another one of Ellipse object, but only define explicit<br />
* constructors for dot only!<br />
*/<br />
private static class Dot extends Circle {<br />
public Dot(Point2D point, Color color) {<br />
super(point, 2, true, color);<br />
}<br />
<br />
public Dot(Point2D point) {<br />
super(point, 2, true);<br />
}<br />
}<br />
<br />
/**<br />
* Arc class render arc. The angle is automatically convert from<br />
* robocode's to java's.<br />
*/<br />
private static class Arc extends Renderable {<br />
private boolean filled;<br />
private double startAngle, arcAngle, width, height;<br />
private Point2D center;<br />
private Color color;<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double radius) {<br />
this(center, startAngle, arcAngle, radius * 2, radius * 2);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double radius, boolean filled) {<br />
this(center, startAngle, arcAngle, radius * 2, radius * 2,<br />
filled);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double radius, Color color) {<br />
this(center, startAngle, arcAngle, radius * 2, radius * 2,<br />
color);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double radius, boolean filled, Color color) {<br />
this(center, startAngle, arcAngle, radius * 2, radius * 2,<br />
filled, color);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height) {<br />
this(center, startAngle, arcAngle, width, height,<br />
DEFAULT_FILLED, DEFAULT_COLOR);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height, boolean filled) {<br />
this(center, startAngle, arcAngle, width, height, filled,<br />
DEFAULT_COLOR);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height, Color color) {<br />
this(center, startAngle, arcAngle, width, height,<br />
DEFAULT_FILLED, color);<br />
}<br />
<br />
public Arc(Point2D center, double startAngle, double arcAngle,<br />
double width, double height, boolean filled, Color color) {<br />
this.center = center;<br />
this.startAngle = startAngle;<br />
this.arcAngle = arcAngle;<br />
this.width = width;<br />
this.height = height;<br />
this.filled = filled;<br />
this.color = color;<br />
}<br />
<br />
@Override<br />
public void render(Graphics2D g) {<br />
int x, y, w, h, sa, a;<br />
x = (int) Math.round(center.getX() - width / 2);<br />
y = (int) Math.round(center.getY() - height / 2);<br />
w = (int) Math.round(width);<br />
h = (int) Math.round(height);<br />
<br />
// Convert from robocode angle to java angle<br />
// Only needed if using robocoder prior to 1.6.1.3<br />
//sa = (int) Math.round(Math.toDegrees(Utils<br />
// .normalAbsoluteAngle(-startAngle + Math.PI / 2)));<br />
// Otherwise use:<br />
sa = (int) Math.round(Math.toDegrees(Utils.normalAbsuluteAngle(startAngle)));<br />
<br />
a = (int) Math.round(arcAngle);<br />
<br />
g.setColor(color);<br />
<br />
if (filled)<br />
g.fillArc(x, y, w, h, sa, a);<br />
else<br />
g.drawArc(x, y, w, h, sa, a);<br />
}<br />
<br />
}<br />
<br />
/**<br />
* Rectangle class render Rectangle both sharp and rounded.<br />
*/<br />
private static class Rectangle extends Renderable {<br />
private static final boolean DEFAULT_ROUNDED = false;<br />
<br />
private Rectangle2D rect;<br />
private Color color;<br />
private boolean filled, rounded;<br />
<br />
public Rectangle(Rectangle2D rect) {<br />
this(rect, DEFAULT_FILLED);<br />
}<br />
<br />
public Rectangle(Rectangle2D rect, boolean filled) {<br />
this(rect, filled, DEFAULT_COLOR);<br />
}<br />
<br />
public Rectangle(Rectangle2D rect, Color color) {<br />
this(rect, DEFAULT_FILLED, DEFAULT_ROUNDED, color);<br />
}<br />
<br />
public Rectangle(Rectangle2D rect, boolean filled, Color color) {<br />
this(rect, filled, DEFAULT_ROUNDED, color);<br />
}<br />
<br />
public Rectangle(Rectangle2D rect, boolean filled, boolean rounded) {<br />
this(rect, filled, rounded, DEFAULT_COLOR);<br />
}<br />
<br />
public Rectangle(Rectangle2D rect, boolean filled, boolean rounded,<br />
Color color) {<br />
this.rect = rect;<br />
this.filled = filled;<br />
this.rounded = rounded;<br />
this.color = color;<br />
}<br />
<br />
@Override<br />
public void render(Graphics2D g) {<br />
int x, y, w, h, arc;<br />
x = (int) Math.round(rect.getX());<br />
y = (int) Math.round(rect.getY());<br />
w = (int) Math.round(rect.getWidth());<br />
h = (int) Math.round(rect.getHeight());<br />
<br />
arc = (int) Math.round(Math.min(15, Math.min(w / 5, h / 5)));<br />
<br />
g.setColor(color);<br />
if (rounded) {<br />
if (filled)<br />
g.fillRoundRect(x, y, w, h, arc, arc);<br />
else<br />
g.drawRoundRect(x, y, w, h, arc, arc);<br />
} else {<br />
if (filled)<br />
g.fillRect(x, y, w, h);<br />
else<br />
g.drawRect(x, y, w, h);<br />
}<br />
}<br />
<br />
}<br />
<br />
/**<br />
* Line class render line.<br />
*/<br />
private static class Line extends Renderable {<br />
private Color color;<br />
private Line2D line;<br />
<br />
public Line(Point2D p1, Point2D p2) {<br />
this(new Line2D.Double(p1, p2));<br />
}<br />
<br />
public Line(Line2D line) {<br />
this(line, DEFAULT_COLOR);<br />
}<br />
<br />
public Line(Point2D p1, Point2D p2, Color color) {<br />
this(new Line2D.Double(p1, p2), color);<br />
}<br />
<br />
public Line(Line2D line, Color color) {<br />
this.line = line;<br />
this.color = color;<br />
}<br />
<br />
public void render(Graphics2D g) {<br />
g.setColor(color);<br />
g.drawLine((int) Math.round(line.getX1()), (int) Math<br />
.round(line.getY1()), (int) Math.round(line.getX2()),<br />
(int) Math.round(line.getY2()));<br />
}<br />
}<br />
<br />
/**<br />
* Text class render String or text.<br />
*/<br />
private static class Text extends Renderable {<br />
private String text;<br />
private double x, y;<br />
private Color color;<br />
<br />
public Text(String text, double x, double y) {<br />
this(text, x, y, DEFAULT_COLOR);<br />
}<br />
<br />
public Text(String text, double x, double y, Color color) {<br />
this(text, new Point2D.Double(x, y), color);<br />
}<br />
<br />
public Text(String text, Point2D loc) {<br />
this(text, loc, DEFAULT_COLOR);<br />
}<br />
<br />
public Text(String text, Point2D loc, Color color) {<br />
this.text = text;<br />
this.x = loc.getX();<br />
this.y = loc.getY();<br />
this.color = color;<br />
}<br />
<br />
public void render(Graphics2D g) {<br />
g.setColor(color);<br />
g.drawString(text, (float) x, (float) y);<br />
}<br />
}<br />
}<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Exauge/snippets&diff=16888User:Exauge/snippets2010-07-01T08:36:58Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>== About ==<br />
These are just a few code snippets to help you get a robot up and going nice and fast :)<br />
== Movement ==<br />
=== Random Movement ===<br />
This is my strong (at least many small bots have a hard time hitting it), but small and easy to implement [[Random Movement]]. It tries to stay away from walls, but isn't perfect so it can still collide sometimes. It works fairly well in smaller bots (nanos and micros) but a stronger movement will probably be needed for largest bots (minis and megas). My robot [[GateKeeper]] uses an extremely lightweight version of this movement. You can see it from its source. Completely random = travels in random direction, normal random = travels in radians relative to enemy position.<br />
I'll start with '''The Bare Minimum''' as a completely [[Random Movement]] but you can use it as an normal random movement as well:<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
static double eEner;<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
if(eEner > (eEner = e.getEnergy())) {<br />
setTurnRight(Math.random()*360-180); // Delete this line if you use normal random<br />
setAhead(((Math.random()*700)-(350))*1.2);<br />
}<br />
//setTurnRightRadians(Math.cos(e.getBearingRadians())); // Uncomment this line for normal random movement<br />
}<br />
}<br />
</syntaxhighlight><br />
Next let's add a few more advanced features like changing velocity:<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
static double eEner;<br />
double backDir = 1;<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
if(eEner > (eEner = e.getEnergy())) {<br />
setMaxVelocity(16*Math.random()+5);<br />
setTurnRight(Math.random()*360-180); // Delete this line if you use normal random<br />
setAhead(((Math.random()*700)-(350))*1.2);<br />
}<br />
//setTurnRightRadians(Math.cos(e.getBearingRadians())); // Uncomment this line for normal random<br />
}<br />
}<br />
</syntaxhighlight><br />
Unfortunately, something like the above two will probably bump into walls a lot so lets add a little wall avoidance:<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
static double eEner;<br />
int backDir = 1;<br />
<br />
public void onHitWall(HitWallEvent event){<br />
backDir = backDir * -1;<br />
}<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
double mxMv = Math.min(Math.min((getBattleFieldWidth()-getX()), (getBattleFieldHeight()-getY())), Math.min(getX(), getY()));<br />
if(eEner > (eEner = e.getEnergy())) {<br />
setMaxVelocity(16*Math.random()+5);<br />
setTurnRight(Math.random()*360-180); // Delete this line if you use normal random<br />
setAhead(((Math.random()*700)-(350))*1.2);<br />
}<br />
if (mxMv < 30) {<br />
setBack(75 * backDir);<br />
}<br />
//setTurnRightRadians(Math.cos(e.getBearingRadians())); // Uncomment this line for normal random<br />
}<br />
}<br />
</syntaxhighlight><br />
Now for the entire thing with changed move amount on bullet hit.. Any of these can be used but obviously the fewer features the smaller the code size.<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
int moveNeg = 1;<br />
double randInt = 1;<br />
double randHit = 1;<br />
static double eEner;<br />
<br />
public void onHitWall(HitWallEvent event){<br />
backDir = backDir * -1;<br />
}<br />
<br />
public void onHitByBullet(HitByBulletEvent e) {<br />
moveNeg = moveNeg * -1;<br />
randInt = Math.random() + .5;<br />
randHit = randInt * randInt * moveNeg;<br />
}<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
double mxMv = Math.min(Math.min((getBattleFieldWidth()-getX()), (getBattleFieldHeight()-getY())), Math.min(getX(), getY()));<br />
double mvAmount = Math.max(getBattleFieldWidth(), getBattleFieldHeight());<br />
double mvAvg = (mxMv+mvAmount)/2;<br />
if(eEner > (eEner = e.getEnergy())) {<br />
setMaxVelocity(16*Math.random()+5);<br />
setTurnRight(Math.random()*360-180); // Delete this line if you use normal random<br />
setAhead(((Math.random()*mvAvg)-(mvAvg*.5))*.8*randHit);<br />
}<br />
if (mxMv < 45) {<br />
setBack(75 * backDir);<br />
}<br />
//setTurnRightRadians(Math.cos(e.getBearingRadians())); // Uncomment this line for normal random<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Targeting ==<br />
=== Pattern Matching Gun ===<br />
<code>Approx Codesize: 130 bytes</code><br />
<br />
This is a pattern matching gun which is a slightly altered version of the one on Robar's Blackwidow. Again, it is a small pattern matcher intended for small bots. A more advanced code will probably work better with larger bots. If you look at the source code of almost every nano and micro, their pattern matcher will look almost exactly like this. That is because the lighter version of the pattern matchers were all for the most part based on FunkyChicken's pattern matcher.<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
static final double bPow = 2.2; // Bullet Power - change it to whatever you like.<br />
static final double bVel = 20-3*bPow;<br />
static final int patDep = 30;<br />
static String eLog = "00000000000000000000000000888888";<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
int i;<br />
double absB;<br />
int mLen = patDep;<br />
int indX;<br />
setTurnRightRadians((Math.cos(absB = e.getBearingRadians())));<br />
eLog = String.valueOf( (char)Math.round(e.getVelocity() * Math.sin(e.getHeadingRadians() - ( absB+=getHeadingRadians() )))).concat(eLog);<br />
while((indX = eLog.indexOf(eLog.substring(0, mLen--), (i = (int)((e.getDistance())/bVel)))) < 0);<br />
do{<br />
absB += Math.asin(((byte)eLog.charAt(indX--))/e.getDistance());<br />
}<br />
while(--i > 0);<br />
setTurnGunRightRadians(Utils.normalRelativeAngle(absB-getGunHeadingRadians()));<br />
setFire(bPow);<br />
}<br />
}<br />
</syntaxhighlight><br />
=== Linear Targeting ===<br />
<code>Approx Codesize: 50 bytes</code><br />
<br />
[[Linear targeting]] is just a step ahead of [[Head-On Targeting]]. Most robots don't just stay in one point - they move. The idea behind linear targeting is that you can easily predict exactly where the enemy will be if they continue to move in a strait line at the same velocity. It is fairly effective against some robots with basic movement but usually isn't used outside the [[NanoBots|nanobot]] class and it is less-commonly used in the [[MicroBots|microbot]] class. The major advantage of [[Linear Targeting]] is that is has a small code size and it is better than [[Head-On Targeting]]. Think of linear targeting as a triangle with one vertex being your robot, another being the enemy robot, and the third being the point that the bullet will hit them. The angle at your robot's vertex will be the angle that your radar would need to turn if it were going to hit the enemy.<br />
<br />
[[File:Lin_targ.jpg]]<br />
<br />
So how can that angle be found? It's quite simple.<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
int bPow = 2; // change as you wish, but note if you use a decimal you must change int to double, which takes more codesize<br />
int bVel = 20 - (bPow * 3); // again, if you make bPow a decimal (such as 2.5) you much change this from int to double as well<br />
double absoluteBearing = getHeadingRadians() + e.getBearingRadians();<br />
setTurnGunRightRadians(Utils.normalRelativeAngle(absoluteBearing - <br />
getGunHeadingRadians() + (e.getVelocity() * Math.sin(e.getHeadingRadians() - <br />
absoluteBearing) / bVel)));<br />
setFire(bPow);<br />
}<br />
}<br />
</syntaxhighlight><br />
Basically, this tells your robot to fire at the spot where the enemy will be when your bullet hits if it continues to move at the same heading and velocity. More thorough explanation / better code for it can be found in the [[Linear Targeting]] article.<br />
<br />
== Radar ==<br />
=== Infinity Radar Lock ===<br />
<code>Approx Codesize: 15 bytes</code><br />
<br />
The [[Radar#The_infinity_lock|infinity lock]] is very easy to implement and has a very small code size which is why I chose it for my first robot. For other radar locks see [[radar]]. **NOTE TO MAKE THE PATTERN MATCHER OR RANDOM MOVEMENT ABOVE WORK PROPERLY, YOU WILL NEED A RADAR LOCK OF SOME TYPE**<br />
<br />
It's really quite simple to use. In your public void run, insert setTurnRadarRight(Double.POSITIVE_INFINITY); so that it will look something like this:<br />
<syntaxhighlight><br />
public void run() {<br />
setTurnRadarRight(Double.POSITIVE_INFINITY); // Radar Lock<br />
}<br />
</syntaxhighlight><br />
Then at the end of your onscannedrobot, insert setTurnRadarLeft(getRadarTurnRemaining()); so that it will look something like this:<br />
<syntaxhighlight><br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
// Your movement code... bla bla<br />
// Your gun code... bla bla<br />
setTurnRadarLeft(getRadarTurnRemaining());<br />
}<br />
</syntaxhighlight><br />
And there you have it. You have just implemented a radar lock.<br />
<br />
== Other ==<br />
=== Multi-mode Movement ===<br />
<code>Approx Codesize: 65 bytes for each movement used</code><br />
<br />
Multi-mode movement is very common in most bots in the micro class or above. There are several ways to implement it.<br />
<syntaxhighlight><br />
public class YOURROBOTNAME extends AdvancedRobot {<br />
<br />
static double bestMove1 = 0;<br />
static double bestMove2 = 0;<br />
static int moveNum = 0;<br />
static int changeMove = 1;<br />
static int winCount = 0;<br />
double eEner;<br />
<br />
// some other code...<br />
<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
eEner = e.getEnergy(); // store the enemy energy<br />
if(moveNum < 1){ // if we use movement 1,<br />
// Movement code for first movement<br />
}<br />
if(moveNum >= 1 && moveNum < 2){ // if we use movement 2,<br />
// Movement code for second movement<br />
}<br />
if(moveNum >= 2){ // if we've used both movements, let's decide which worked better<br />
changeMove = 0; // don't change our movement any more.<br />
if(bestMove2 > bestMove1){ // if movement 2 did better than movement 1,<br />
moveNum = 1; // use movement 2<br />
}<br />
if(bestMove1 >= bestMove2){ // else if movement 1 did better than movement 2,<br />
moveNum = 0; // use movement 1<br />
}<br />
}<br />
// gun code might go here...<br />
// radar code...<br />
}<br />
<br />
public void onDeath(DeathEvent event){ // if we die<br />
if (winCount < 4){ // if we've 4 battles with the movement before it changes, we'll assume it's working<br />
moveNum += ((1/4)*changeMove); // every 4 losses, switch movements<br />
}<br />
if(moveNum < 1){ // if we used movement 1 when we died<br />
bestMove1 -= eEner; // subtract how much energy the enemy had left<br />
}<br />
if(moveNum >= 1){ // if we used movement 2 when we died<br />
bestMove2 -= eEner; // subtract how much energy the enemy had left<br />
}<br />
}<br />
<br />
public void onWin(WinEvent event){ // if we win and<br />
if(moveNum < 1){ // if we are using movement 1<br />
bestMove1 += getEnergy(); // add the energy we had left to the movement 1 counter<br />
winCount += 1; // add a win to the victory counter<br />
}<br />
if(moveNum >= 1){ // and if we are using movement 2<br />
bestMove2 += getEnergy(); // add the energy we had left to the movement 2 counter<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
[[Category:Code Snippets]]</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:Axe/RoboLeague_Analyser&diff=16887User:Axe/RoboLeague Analyser2010-07-01T08:36:50Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>I allways suffered a lot running [[RoboLeague]], something like 5 seasons of 35 rounds match in a TestBed of 20 bots or how. And also suffered after, trying to excel the results of those many tables.<br><br />
In order to to help me analyse the results of RoboLeague, i built this modest analyser.<br> <br />
It reads the .xml file resulting of running RoboLeague division mode, focused in your bot, against a TestBed of n bots in m seasons. Process<br />
The info of the xml and give me an output as a table with this kind of colums:<br />
<pre><br />
dos.writeBytes("Opponent" + sep + "PBI(%)" + sep + "My score" + sep<br />
+ "Opp Score" + sep + "My bull.dmg." + sep<br />
+ "Opp bull.dmg." + "\r\n");<br />
</pre> <br />
Averaged by the seasons quantity.<br><br />
That means that i have now a single table with the results averaged.<br />
This by itself is usefull to me, but the real reason that made me post this, is that it is a very simple code accessing the output .xml file of RoboLeague, and demontrates the basic manipulation of xml structures with Java APIs. Its very crude and simple, but I prefer that way, it is (i think) easier to understand and adapt/use. Feel u all free to use this code ([[RWPCL]]).<br><br />
<br />
Usage: axe.LeagueAnalyser <RoboLeague_xml_file> <bot_name_with_underscore_in_spaces><br><br />
<br />
----<br />
=== The Code: ===<br />
[http://robowiki.net/robocode/uploads/axe/LeagueAnaliser.zip Download it]<br />
<br />
LeagueAnalyser.java:<br />
<syntaxhighlight><br />
package axe;<br />
<br />
import java.io.*;<br />
import java.text.DecimalFormat;<br />
import java.util.*;<br />
<br />
import javax.xml.parsers.*;<br />
import javax.xml.parsers.DocumentBuilderFactory;<br />
<br />
import org.w3c.dom.*;<br />
/** <br />
* LeagueAnalyser - 10/06/2004<br />
* @author Axe<br />
* <br />
* This code is released under the RoboWiki Public Code Licence (RWPCL),<br />
* datailed on:<br />
* http://robowiki.net/?RWPCL<br />
* (Basically it means you must keep the code public if you base any code on<br />
* it.)<br />
* Not basically, i think it means that the knowledge should not be <br />
* retained, but shared. We must all remember that the veins of the Knowledge <br />
* must flow. Quoting(or some) PEZ´s comment about OpenSouce: "At least is a <br />
* good Karma".<br />
*/<br />
public class LeagueAnalyser {<br />
<br />
private Document document;<br />
private String bot;<br />
private HashMap matches = new HashMap();<br />
<br />
public LeagueAnalyser(String srcFile, String robot) {<br />
super();<br />
this.bot = robot.replaceAll("_", " ");<br />
System.out.println("processing file " + srcFile + " for bot "<br />
+ this.bot);<br />
setXML(srcFile);<br />
Node root = document.getDocumentElement();<br />
ArrayList seasons = getChilds(root, "SEASON");<br />
System.out.println("Seasons:" + seasons.size());<br />
BotPair pair = new BotPair();<br />
String sep = "\u0009";<br />
for (int i = 0; i < seasons.size(); i++) {<br />
<br />
Node season = (Node) seasons.get(i);<br />
ArrayList groupings = getChilds(season, "GROUPING");<br />
System.out<br />
.println("Season " + i + " groupings " + groupings.size());<br />
for (int j = 0; j < groupings.size(); j++) {<br />
Node grouping = (Node) groupings.get(j);<br />
ArrayList results = getChilds(grouping, "RESULTS");<br />
BotReg myReg = null;<br />
BotReg oppReg = null;<br />
<br />
for (int k = 0; k < results.size(); k++) {<br />
Element result = (Element) results.get(k);<br />
<br />
BotReg reg = new BotReg(result);<br />
if (reg.getBot().equals(bot)) {<br />
myReg = reg;<br />
} else {<br />
oppReg = reg;<br />
}<br />
}<br />
if (myReg != null && oppReg != null) {<br />
pair = new BotPair();<br />
if (matches.containsKey(oppReg.getBot())) {<br />
pair = (BotPair) matches.get(oppReg.getBot());<br />
<br />
myReg = pair.getMe().add(myReg);<br />
oppReg = pair.getHim().add(oppReg);<br />
}<br />
pair.setHim(oppReg);<br />
pair.setMe(myReg);<br />
matches.put(oppReg.getBot(), pair);<br />
<br />
}<br />
}<br />
}<br />
DecimalFormat forma = new DecimalFormat("0.00");<br />
<br />
ArrayList keys = new ArrayList(matches.keySet());<br />
Collections.sort(keys);<br />
File output = new File(bot + ".results");<br />
try {<br />
FileOutputStream fos = new FileOutputStream(output);<br />
DataOutputStream dos = new DataOutputStream(fos);<br />
dos.writeBytes("Results for " + bot + " " + seasons.size()<br />
+ " seasons\r\n");<br />
dos.writeBytes("Opponent" + sep + "PBI(%)" + sep + "My score" + sep<br />
+ "Opp Score" + sep + "My bull.dmg." + sep<br />
+ "Opp bull.dmg." + "\r\n");<br />
<br />
System.out.println("performing results for " + keys.size()<br />
+ " matches.");<br />
for (int i = 0; i < keys.size(); i++) {<br />
<br />
pair = (BotPair) matches.get(keys.get(i));<br />
BotReg me = pair.getMe();<br />
BotReg he = pair.getHim();<br />
<br />
double percent = (me.getScore() * 100D)<br />
/ (he.getScore() + me.getScore());<br />
System.out.println(he.getBot() + ":" + forma.format(percent));<br />
System.out.println(he.getBot() + ": " + forma.format(percent)<br />
+ "% " + me.getScore() + "/" + he.getScore());<br />
dos.writeBytes(he.getBot() + sep + forma.format(percent) + sep<br />
+ me.getScore() + sep + he.getScore() + sep<br />
+ me.getBullet_damage() + sep + he.getBullet_damage()<br />
+ "\r\n");<br />
}<br />
dos.close();<br />
fos.close();<br />
<br />
} catch (IOException e) {<br />
// TODO Auto-generated catch block<br />
e.printStackTrace();<br />
}<br />
<br />
}<br />
<br />
/**<br />
* LeagueAnalyser main vm method<br />
* Usage: axe.LeagueAnalyser <RoboLeague_xml_file> <bot_name_with_underscore_in_spaces><br />
*/<br />
public static void main(String[] args) {<br />
new LeagueAnalyser(args[0], args[1]);<br />
}<br />
<br />
public void setXML(String xmlFile) {<br />
try {<br />
File src = new File(xmlFile);<br />
<br />
DocumentBuilderFactory factory = DocumentBuilderFactory<br />
.newInstance();<br />
DocumentBuilder builder = factory.newDocumentBuilder();<br />
document = builder.parse(src);<br />
} catch (Exception e) {<br />
e.printStackTrace();<br />
}<br />
<br />
}<br />
<br />
private ArrayList getChilds(Node localRoot, String childName) {<br />
ArrayList groupings = new ArrayList();<br />
<br />
NodeList childs = localRoot.getChildNodes();<br />
for (int i = 0; i < childs.getLength(); i++) {<br />
Node child = childs.item(i);<br />
if (child.getNodeName().equals(childName)) {<br />
groupings.add(child);<br />
}<br />
}<br />
return groupings;<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
BotReg.java:<br />
<syntaxhighlight><br />
package axe;<br />
<br />
import org.w3c.dom.Element;<br />
/** <br />
* BotReg - 10/06/2004<br />
* @author Axe<br />
* <br />
* This code is released under the RoboWiki Public Code Licence (RWPCL),<br />
* datailed on:<br />
* http://robowiki.net/?RWPCL<br />
* (Basically it means you must keep the code public if you base any code on<br />
* it.)<br />
* Not basically, i think it means that the knowledge should not be <br />
* retained, but shared. We must all remember that the veins of the Knowledge <br />
* must flow. Quoting(or some) PEZ´s comment about OpenSouce: "At least is a <br />
* good Karma".<br />
*/<br />
public class BotReg {<br />
<br />
private String bot = null;<br />
private int score = 0;<br />
private int survival = 0;<br />
private int last_survivor_bonus = 0;<br />
private int bullet_damage = 0;<br />
private int bullet_damage_bonus = 0;<br />
private int ram_damage = 0;<br />
private int ram_damage_bonus = 0;<br />
private int n_first_rank = 0;<br />
private int n_second_rank = 0;<br />
private int n_third_rank = 0;<br />
<br />
public BotReg() {<br />
super();<br />
}<br />
<br />
public BotReg(Element reg) {<br />
super();<br />
bot = reg.getAttribute("id");<br />
score = Integer.parseInt(reg.getAttribute("total_score"));<br />
survival = Integer.parseInt(reg.getAttribute("survival"));<br />
last_survivor_bonus = Integer.parseInt(reg<br />
.getAttribute("last_survivor_bonus"));<br />
bullet_damage = Integer.parseInt(reg.getAttribute("bullet_damage"));<br />
bullet_damage_bonus = Integer.parseInt(reg<br />
.getAttribute("bullet_damage_bonus"));<br />
ram_damage = Integer.parseInt(reg.getAttribute("ram_damage"));<br />
ram_damage_bonus = Integer.parseInt(reg<br />
.getAttribute("ram_damage_bonus"));<br />
n_first_rank = Integer.parseInt(reg.getAttribute("n_first_rank"));<br />
n_second_rank = Integer.parseInt(reg.getAttribute("n_second_rank"));<br />
n_third_rank = Integer.parseInt(reg.getAttribute("n_third_rank"));<br />
}<br />
<br />
public BotReg add(BotReg reg) {<br />
if (!reg.equals(this)) {<br />
System.err.println("BotReg.add(), bots don´t match:" + reg.getBot()<br />
+ "," + this.getBot());<br />
return null;<br />
}<br />
BotReg ret = new BotReg();<br />
ret.bot = this.bot;<br />
ret.score = this.score + reg.score;<br />
ret.survival = this.survival + reg.survival;<br />
ret.last_survivor_bonus = this.last_survivor_bonus<br />
+ reg.last_survivor_bonus;<br />
ret.bullet_damage = this.bullet_damage + reg.bullet_damage;<br />
ret.bullet_damage_bonus = this.bullet_damage_bonus<br />
+ reg.bullet_damage_bonus;<br />
ret.ram_damage = this.ram_damage + reg.ram_damage;<br />
ret.ram_damage_bonus = this.ram_damage_bonus + reg.ram_damage_bonus;<br />
ret.n_first_rank = this.n_first_rank + reg.n_first_rank;<br />
ret.n_second_rank = this.n_second_rank + reg.n_second_rank;<br />
ret.n_third_rank = this.n_third_rank + reg.n_third_rank;<br />
return ret;<br />
}<br />
<br />
public String getBot() {<br />
return bot;<br />
}<br />
public int getScore() {<br />
return score;<br />
}<br />
public boolean equals(Object o) {<br />
if (!(o instanceof BotReg)) {<br />
return false;<br />
}<br />
return ((BotReg) o).getBot().equals(this.getBot());<br />
}<br />
public int hashCode() {<br />
return getBot().hashCode();<br />
}<br />
public int getBullet_damage() {<br />
return bullet_damage;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
BotPair.java:<br />
<syntaxhighlight><br />
package axe;<br />
<br />
/** <br />
* BotPair - 10/06/2004<br />
* @author Axe<br />
* <br />
* This code is released under the RoboWiki Public Code Licence (RWPCL),<br />
* datailed on:<br />
* http://robowiki.net/?RWPCL<br />
* (Basically it means you must keep the code public if you base any code on<br />
* it.)<br />
* Not basically, i think it means that the knowledge should not be <br />
* retained, but shared. We must all remember that the veins of the Knowledge <br />
* must flow. Quoting(or some) PEZ´s comment about OpenSouce: "At least is a <br />
* good Karma".<br />
*/<br />
public class BotPair {<br />
<br />
private BotReg me;<br />
private BotReg him;<br />
<br />
public BotPair() {<br />
super();<br />
}<br />
public BotPair(BotReg me, BotReg him) {<br />
super();<br />
this.me = me;<br />
this.him = him;<br />
}<br />
public BotReg getHim() {<br />
return him;<br />
}<br />
public void setHim(BotReg him) {<br />
this.him = him;<br />
}<br />
public BotReg getMe() {<br />
return me;<br />
}<br />
public void setMe(BotReg me) {<br />
this.me = me;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
[[Category:Source Code]]<br />
[[Category:Utilities]]</div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:AaronR/Utility_Bots&diff=16886User:AaronR/Utility Bots2010-07-01T08:36:45Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Sometimes, you write a bot whose only purpose in life is to test some tiny little detail of another bot's implementation. Some of the [[sample bots]] that come with Robocode fit into this category; for example, [[Walls (robot)|Walls]] is well known as a sanity check for movement (tests avoidance of [[GuessFactor]] 0.0) and targeting (tests hitting GF 1.0).<br />
<br />
Here are some other bots like this.<br />
<br />
<br />
== WallsReverser ==<br />
WallsReverser is a bot that can be used for finding bugs in [[lateral velocity]] calculations in targeting systems. For the first five rounds, it moves like the sample bot Walls; on the sixth round, it switches to moving in the opposite direction. This bot helped to find a bug in [[Horizon]]'s gun.<br />
<br />
<syntaxhighlight><br />
import java.awt.Color;<br />
import robocode.*;<br />
<br />
public class WallsReverser extends Robot {<br />
public void run() {<br />
if (getRoundNum() < 5) {<br />
// Set colors<br />
setBodyColor(Color.black);<br />
setGunColor(Color.black);<br />
setRadarColor(Color.orange);<br />
setBulletColor(Color.cyan);<br />
setScanColor(Color.cyan);<br />
} else {<br />
// These are the opposite colors. Clever, huh?<br />
setBodyColor(Color.white);<br />
setGunColor(Color.white);<br />
setRadarColor(Color.blue);<br />
setBulletColor(Color.magenta);<br />
setScanColor(Color.magenta);<br />
}<br />
<br />
// turnLeft to face a wall.<br />
// getHeading() % 90 means the remainder of <br />
// getHeading() divided by 90.<br />
turnLeft(getHeading() % 90);<br />
<br />
while (true) {<br />
// Move up the wall<br />
ahead(Double.POSITIVE_INFINITY);<br />
// Turn to the next wall<br />
if (getRoundNum() < 5) {<br />
turnRight(90);<br />
} else {<br />
turnLeft(90);<br />
}<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
== SelfDisablingBot ==<br />
Many robots have a special case for dealing with [[disabled]] opponents. This is important, because a gun that ignores the fact that the opponent is disabled could assume that it will continue acting normally and ''miss'', or worse yet, record data based on the opponent being a [[sitting duck]]. This utility bot tests your bot's reaction to a disabled opponent.<br />
<br />
<syntaxhighlight><br />
import robocode.*;<br />
<br />
public class SelfDisablingBot extends AdvancedRobot {<br />
@Override<br />
public void run() {<br />
setTurnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
}<br />
<br />
@Override<br />
public void onScannedRobot(ScannedRobotEvent e) {<br />
// Generic random movement.<br />
setAhead((Math.random() - 0.5) * 200);<br />
setTurnRightRadians((Math.random() - 0.5) * 2);<br />
}<br />
<br />
@Override<br />
public void onStatus(StatusEvent e) {<br />
if (e.getTime() > 100) {<br />
// Stupid self disabling trick.<br />
while (true) {<br />
getX();<br />
}<br />
}<br />
}<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=User:AaronR/HatLeagueRobot&diff=16885User:AaronR/HatLeagueRobot2010-07-01T08:36:42Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>Yet another base class for robots participating in the [[Hat League]].<br />
<br />
== Version history ==<br />
* '''0.2''' ''The "I didn't even expect it to work this well" release.''<br />
** '''Release: 2008-01-15'''<br />
** Bugfix: the enemy-scanned event didn't bother to check whether the scanned robot was actually an enemy...<br />
** The API has been changed to pass bullet power instead of bullet speed as the parameter to the partner-bullet-fired and enemy-wave-fired events.<br />
** The internal implementation now properly handles multiple messages that are merged into a single string (separated by "\n"). It will also ignore blank messages.<br />
** Added hlGetRadarTarget() and hlGetBulletTarget() methods that return the values previously supplied through the corresponding hlSetRadarTarget() and hlSetBulletTarget() methods.<br />
<br />
* '''0.1''' ''The "This should save some time" release.''<br />
** '''Release: 2008-01-14'''<br />
** A largely untested and probably buggy robot framework.<br />
<br />
== What's next ==<br />
* Debugging, probably.<br />
* Make it sort out duplicate enemy-scanned and enemy-fired-wave events registered by both robots.<br />
* Better enemy wave detection.<br />
<br />
== Source code ==<br />
=== Usage rules ===<br />
# If a method begins with "<code>hl</code>", use it instead of the normal Robocode method.<br />
# See rule 1.<br />
<br />
=== The HatLeagueRobot class ===<br />
<syntaxhighlight><br />
package wiki.hat;<br />
<br />
import static java.lang.Math.*;<br />
import static robocode.Rules.*;<br />
<br />
import java.awt.geom.Point2D;<br />
import java.io.IOException;<br />
import java.util.*;<br />
<br />
import robocode.*;<br />
<br />
public abstract class HatLeagueRobot extends TeamRobot {<br />
// OVERRIDE THESE IN SUBCLASSES, NOT THE NORMAL ROBOCODE METHODS! //<br />
<br />
/**<br />
* Don't:<br />
* <br />
* public void hlRun() {<br />
* // ...<br />
* <br />
* do {<br />
* // ...<br />
* execute();<br />
* } while (true);<br />
* }<br />
* <br />
* Do:<br />
* <br />
* public void hlRun() {<br />
* // ...<br />
* }<br />
* <br />
* public void hlOnTickEnd() {<br />
* // ...<br />
* }<br />
*/<br />
public void hlRun() {<br />
}<br />
<br />
public void hlOnTickBegin() {<br />
}<br />
<br />
public void hlOnTickEnd() {<br />
}<br />
<br />
public void hlOnCustomEvent(CustomEvent e) {<br />
}<br />
<br />
public void hlOnPartnerDataReceived(long time, Point2D.Double location,<br />
double heading, double velocity, double energy) {<br />
}<br />
<br />
/**<br />
* Note that this method is called both when this robot scans an enemy and<br />
* when the partner scans one.<br />
*/<br />
public void hlOnEnemyDataReceived(long time, Point2D.Double location,<br />
double heading, double velocity, double energy, String name) {<br />
}<br />
<br />
public void hlOnPartnerBulletOriginReceived(long time,<br />
Point2D.Double location, double heading, double power) {<br />
}<br />
<br />
/**<br />
* Note that this method is called both when this robot scans an enemy that<br />
* fired a wave and when the partner scans one.<br />
*/<br />
public void hlOnEnemyWaveOriginReceived(long time, Point2D.Double location,<br />
double power) {<br />
}<br />
<br />
public void hlOnPartnerRadarTargetReceived(String target) {<br />
}<br />
<br />
public void hlOnPartnerBulletTargetReceived(String target) {<br />
}<br />
<br />
public void hlOnSuggestedRadarTargetReceived(String target) {<br />
}<br />
<br />
public void hlOnSuggestedBulletTargetReceived(String target) {<br />
}<br />
<br />
public void hlOnCustomMessageReceived(String message) {<br />
}<br />
<br />
// SPECIAL HAT LEAGUE ACTION METHODS. //<br />
<br />
private static class HatLeagueMessage {<br />
private String name;<br />
private String[] values;<br />
<br />
public HatLeagueMessage(String name, String... values) {<br />
this.name = name;<br />
this.values = values;<br />
}<br />
<br />
public String getName() {<br />
return name;<br />
}<br />
<br />
public String[] getValues() {<br />
return values;<br />
}<br />
}<br />
<br />
/**<br />
* Use this everywhere you would normally use setFire().<br />
*/<br />
public final Bullet hlSetFireBullet(double bulletPower) {<br />
// Copied from robocode.peer.RobotPeer.java. =)<br />
if (getGunHeat() > 0 || getEnergy() == 0) {<br />
return null;<br />
}<br />
<br />
double realBulletPower = min(getEnergy(), min(max(bulletPower,<br />
Rules.MIN_BULLET_POWER), Rules.MAX_BULLET_POWER));<br />
<br />
broadcastHatLeagueMessage(new HatLeagueMessage("BO",<br />
Long.toString(getTime()), Double.toString(getX()),<br />
Double.toString(getY()),<br />
Double.toString(getGunHeadingRadians()),<br />
Double.toString(getBulletSpeed(realBulletPower))));<br />
return setFireBullet(realBulletPower);<br />
}<br />
<br />
private String radarTarget = null;<br />
private String bulletTarget = null;<br />
<br />
public final String hlGetRadarTarget() {<br />
return radarTarget;<br />
}<br />
<br />
public final void hlSetRadarTarget(String target) {<br />
broadcastHatLeagueMessage(new HatLeagueMessage("MR", target));<br />
radarTarget = target;<br />
}<br />
<br />
public final String hlGetBulletTarget() {<br />
return bulletTarget;<br />
}<br />
<br />
public final void hlSetBulletTarget(String target) {<br />
broadcastHatLeagueMessage(new HatLeagueMessage("MB", target));<br />
bulletTarget = target;<br />
}<br />
<br />
public final void hlSuggestRadarTarget(String target) {<br />
broadcastHatLeagueMessage(new HatLeagueMessage("TR", target));<br />
}<br />
<br />
public final void hlSuggestBulletTarget(String target) {<br />
broadcastHatLeagueMessage(new HatLeagueMessage("TB", target));<br />
}<br />
<br />
public final void hlBroadcastCustomMessage(String message) {<br />
broadcastHatLeagueMessage(new HatLeagueMessage("NA", message));<br />
}<br />
<br />
private void broadcastHatLeagueMessage(HatLeagueMessage message) {<br />
StringBuilder buffer = new StringBuilder();<br />
buffer.append(message.getName());<br />
for (String value : message.getValues()) {<br />
buffer.append(",");<br />
buffer.append(value);<br />
}<br />
<br />
try {<br />
broadcastMessage(buffer.toString());<br />
} catch (IOException ex) {<br />
throw new RuntimeException(ex);<br />
}<br />
}<br />
<br />
private HatLeagueMessage[] decodeHatLeagueMessages(String receivedBroadcast) {<br />
String[] messages = receivedBroadcast.split("\n");<br />
List<HatLeagueMessage> decodedMessages = new ArrayList<HatLeagueMessage>();<br />
for (String message : messages) {<br />
if (!message.equals("")) {<br />
String[] messageParts = message.split(",");<br />
// Dang it! Why did they have to wait until Java 1.6 to<br />
// introduce Arrays.copyOfRange()?<br />
String[] valueParts = new String[messageParts.length - 1];<br />
for (int i = 1; i < messageParts.length; i++) {<br />
valueParts[i - 1] = messageParts[i];<br />
}<br />
<br />
decodedMessages.add(new HatLeagueMessage(messageParts[0],<br />
valueParts));<br />
}<br />
}<br />
<br />
return decodedMessages.toArray(new HatLeagueMessage[decodedMessages.size()]);<br />
}<br />
<br />
// CLASS INTERNALS START HERE. //<br />
<br />
private static class TickCondition extends Condition {<br />
public TickCondition(String name, int priority) {<br />
super(name, priority);<br />
}<br />
<br />
public boolean test() {<br />
return true;<br />
}<br />
}<br />
<br />
private static final String TICK_BEGIN_NAME = "onTickBegin";<br />
private static final String TICK_END_NAME = "onTickStart";<br />
<br />
private Map<String, Double> enemyEnergies = new HashMap<String, Double>();<br />
<br />
@Override<br />
public final void run() {<br />
addCustomEvent(new TickCondition(TICK_BEGIN_NAME, 99));<br />
addCustomEvent(new TickCondition(TICK_END_NAME, 1));<br />
hlRun();<br />
}<br />
<br />
@Override<br />
public final void onCustomEvent(CustomEvent e) {<br />
String name = e.getCondition().getName();<br />
if (name.equals(TICK_BEGIN_NAME)) {<br />
broadcastHatLeagueMessage(new HatLeagueMessage("PD",<br />
Long.toString(getTime()), Double.toString(getX()),<br />
Double.toString(getY()),<br />
Double.toString(getHeadingRadians()),<br />
Double.toString(getVelocity()),<br />
Double.toString(getEnergy())));<br />
hlOnTickBegin();<br />
} else if (name.equals(TICK_END_NAME)) {<br />
hlOnTickEnd();<br />
} else {<br />
hlOnCustomEvent(e);<br />
}<br />
}<br />
<br />
@Override<br />
public final void onScannedRobot(ScannedRobotEvent e) {<br />
String name = e.getName();<br />
if (!isTeammate(name)) {<br />
long time = getTime();<br />
double distance = e.getDistance();<br />
Point2D.Double location = project(<br />
new Point2D.Double(getX(), getY()), e.getBearingRadians(),<br />
distance);<br />
double heading = e.getHeadingRadians();<br />
double velocity = e.getVelocity();<br />
double energy = e.getEnergy();<br />
<br />
HatLeagueMessage scannedMessage = new HatLeagueMessage("ES",<br />
Long.toString(time), Double.toString(location.getX()),<br />
Double.toString(location.getY()), Double.toString(heading),<br />
Double.toString(velocity), Double.toString(energy), name);<br />
passHatLeagueMessage(scannedMessage);<br />
broadcastHatLeagueMessage(scannedMessage);<br />
<br />
if (enemyEnergies.containsKey(name)) {<br />
double lastEnergy = enemyEnergies.get(name);<br />
double difference = lastEnergy - energy;<br />
if (difference > 0.09 && difference < 3.01) {<br />
HatLeagueMessage waveMessage = new HatLeagueMessage("EW",<br />
Long.toString(time),<br />
Double.toString(location.getX()),<br />
Double.toString(location.getY()),<br />
Double.toString(getBulletSpeed(difference)));<br />
passHatLeagueMessage(waveMessage);<br />
broadcastHatLeagueMessage(waveMessage);<br />
}<br />
}<br />
<br />
enemyEnergies.put(name, energy);<br />
}<br />
}<br />
<br />
@Override<br />
public final void onMessageReceived(MessageEvent e) {<br />
HatLeagueMessage[] messages = decodeHatLeagueMessages(e.getMessage().toString());<br />
for (HatLeagueMessage message : messages) {<br />
passHatLeagueMessage(message);<br />
}<br />
}<br />
<br />
private void passHatLeagueMessage(HatLeagueMessage message) {<br />
String messageType = message.getName();<br />
String[] messageValues = message.getValues();<br />
if (messageType.equals("PD")) {<br />
hlOnPartnerDataReceived(Long.parseLong(messageValues[0]),<br />
new Point2D.Double(Double.parseDouble(messageValues[1]),<br />
Double.parseDouble(messageValues[2])),<br />
Double.parseDouble(messageValues[3]),<br />
Double.parseDouble(messageValues[4]),<br />
Double.parseDouble(messageValues[5]));<br />
} else if (messageType.equals("ES")) {<br />
hlOnEnemyDataReceived(Long.parseLong(messageValues[0]),<br />
new Point2D.Double(Double.parseDouble(messageValues[1]),<br />
Double.parseDouble(messageValues[2])),<br />
Double.parseDouble(messageValues[3]),<br />
Double.parseDouble(messageValues[4]),<br />
Double.parseDouble(messageValues[5]), messageValues[6]);<br />
} else if (messageType.equals("BO")) {<br />
hlOnPartnerBulletOriginReceived(<br />
Long.parseLong(messageValues[0]),<br />
new Point2D.Double(Double.parseDouble(messageValues[1]),<br />
Double.parseDouble(messageValues[2])),<br />
Double.parseDouble(messageValues[3]),<br />
getBulletPowerFromSpeed(Double.parseDouble(messageValues[4])));<br />
} else if (messageType.equals("EW")) {<br />
hlOnEnemyWaveOriginReceived(<br />
Long.parseLong(messageValues[0]),<br />
new Point2D.Double(Double.parseDouble(messageValues[1]),<br />
Double.parseDouble(messageValues[2])),<br />
getBulletPowerFromSpeed(Double.parseDouble(messageValues[3])));<br />
} else if (messageType.equals("MR")) {<br />
hlOnPartnerRadarTargetReceived(messageValues[0]);<br />
} else if (messageType.equals("MB")) {<br />
hlOnPartnerBulletTargetReceived(messageValues[0]);<br />
} else if (messageType.equals("TR")) {<br />
hlOnSuggestedRadarTargetReceived(messageValues[0]);<br />
} else if (messageType.equals("TB")) {<br />
hlOnSuggestedBulletTargetReceived(messageValues[0]);<br />
} else if (messageType.equals("NA")) {<br />
// This is so that we correctly parse custom messages containing<br />
// commas.<br />
StringBuilder joinedMessage = new StringBuilder();<br />
for (int i = 0; i < messageValues.length; i++) {<br />
joinedMessage.append(messageValues[i]);<br />
if (i < messageValues.length - 1) {<br />
joinedMessage.append(",");<br />
}<br />
}<br />
<br />
hlOnCustomMessageReceived(joinedMessage.toString());<br />
} else {<br />
throw new RuntimeException("Unrecognized message type: "<br />
+ messageType);<br />
}<br />
}<br />
<br />
private static double getBulletPowerFromSpeed(double bulletSpeed) {<br />
return (20.0 - bulletSpeed) / 3;<br />
}<br />
<br />
private static Point2D.Double project(Point2D.Double sourceLocation,<br />
double angle, double distance) {<br />
return new Point2D.Double(<br />
sourceLocation.x + Math.sin(angle) * distance, sourceLocation.y<br />
+ Math.cos(angle) * distance);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
=== Example robot ===<br />
<syntaxhighlight><br />
package wiki.hat;<br />
<br />
import java.awt.Color;<br />
import java.awt.geom.*;<br />
<br />
public class HatLeagueTestRobot extends HatLeagueRobot {<br />
@Override<br />
public void hlRun() {<br />
setColors(Color.RED, Color.ORANGE, Color.RED);<br />
setTurnRadarRightRadians(Double.POSITIVE_INFINITY);<br />
}<br />
<br />
@Override<br />
public void hlOnPartnerBulletOriginReceived(long time,<br />
Point2D.Double location, double heading, double velocity) {<br />
out.println(time + " - partner fired bullet: location " + location<br />
+ ", heading " + heading + ", velocity " + velocity);<br />
}<br />
<br />
@Override<br />
public void hlOnTickEnd() {<br />
hlSetFireBullet(0.5);<br />
}<br />
}<br />
</syntaxhighlight></div>RednaxelaBothttp://robowiki.net/w/index.php?title=Talk:Zoom_Radar&diff=16884Talk:Zoom Radar2010-07-01T08:36:38Z<p>RednaxelaBot: Using <syntaxhighlight>.</p>
<hr />
<div>There seems to be a lot of errors regarding rendering LaTeX. Is there a way to resolve this?<br />
--[[User:Frolicking Zombie|Frolicking Zombie]] 17:53, 26 February 2010 (UTC)<br />
<br />
Ok, I'm looking into it... --[[User:Voidious|Voidious]] 18:08, 26 February 2010 (UTC)<br />
<br />
Fixed:<br />
:<math><br />
it = {{works - now} \over {\Delta Friday}}<br />
</math><br />
Enjoy. =) --[[User:Voidious|Voidious]] 18:33, 26 February 2010 (UTC)<br />
<br />
== Some comments ==<br />
<br />
Heh, actually, inspired by what you had on your talk page, though doing the math a bit different, I've already implemented something along these lines in Glaicer. Take a look at [http://homepages.ucalgary.ca/~agschult/robocode/ags.Glacier_0.2.7.jar Glacier]'s "ags.muse.radar.MeleeRadar" class, which IMO is much cleaner. It also looks really spiffy in action. Also, the math here is wrong, in that one gets the most change in angle by moving along a '''chord''' of the circle created by the distance to the enemy bot, and that fact also simplifies the math to calculate the uncertainty in angle to the following:<br />
<syntaxhighlight><br />
double maxMoved = rules.MAX_VELOCITY*bot.getDataAge();<br />
double uncertainty;<br />
if (distance * 2 > maxMoved) {<br />
uncertainty = 2*Math.asin(maxMoved/(2*distance));<br />
}<br />
else {<br />
uncertainty = Math.PI;<br />
}<br />
</syntaxhighlight> Essentially a single arcsine with a special condition for when they haven't been seen in so long that their angle is completely unknown (i.e. could be PI radians different in either direction).<br />
<br />
Another note, is that in order to be accurate enough to ensure you don't slip when being this precise, it's also necessary to count the change in radar origin position caused by one's own movement.<br />
<br />
Also, why the name "Zoom Radar"? I don't see any "zooming". --[[User:Rednaxela|Rednaxela]] 17:54, 26 February 2010 (UTC)<br />
<br />
The triangle formed in your equation would be the equivalent as if the robot traveled along the tangent created by the targetDistance circle. This creates slightly less of an angle (which promotes slip) than if you calculate the intercept of the targetError and targetDistance circles. BTW, why would you use (2*distance) as the hypotenuse of your triangle? --[[User:Frolicking Zombie|Frolicking Zombie]] 18:13, 26 February 2010 (UTC)<br />
<br />
I think you're mis-visualizing the geometry of my equation, but I think that's my fault. (2*distance) isn't a hypotenuse, and it's made of two triangles, not one. I probably should have wrote it as "<code>uncertainty = 2*Math.asin((maxMoved/2)/distance);</code>" but I was silly and didn't (I really need to get out of my habit of pointless premature micro-optimizations (in this case to do with how multiplication is faster than division)). To get a better idea what it means, see the following diagram that I quickly whipped up:<br />
<br/>[[File:RednaxelaRoughAngularErrorSketch.png]]<br/><br />
Moving across the chord of the circle is truly the fastest way to for the enemy to change angles. After all, what's the quickest way for an enemy bot to change it's angle by 180 degrees? Just drive straight to the other side of you. --[[User:Rednaxela|Rednaxela]] 19:18, 26 February 2010 (UTC)<br />
<br />
I understand your method better with the picture. Both methods will end up with the same result, but yours is less computationally intensive to retrieve the bearing. /me bows. Mind if I update the code to reflect your method? --[[User:Frolicking Zombie|Frolicking Zombie]] 19:26, 26 February 2010 (UTC)<br />
<br />
Feel free to... but just now I realized that the assumption of the chord being the most efficient path to change angle is incorrect. It's typical, so works well in practice as Glacier shows, but the real uncertainty factor is actually larger. To change angle, it's actually more efficiency to dive towards the enemy, plus if one drives straight towards the enemy, the angle will change by 180 degrees after traveling (distance) not (2*distance) right through where the bot is. It should be follows I now realize:<br />
<syntaxhighlight><br />
double maxMoved = rules.MAX_VELOCITY*bot.getDataAge();<br />
double uncertainty;<br />
if (distance >= maxMoved) {<br />
uncertainty = Math.asin(maxMoved/distance);<br />
}<br />
else {<br />
uncertainty = Math.PI;<br />
}<br />
</syntaxhighlight> to be really safe... in order to tighten it any further than that, and give any guarantees, requires relying on acceleration limits of bots or that they must be at least 'botWidth' distance from you currently. --[[User:Rednaxela|Rednaxela]] 19:42, 26 February 2010 (UTC)<br />
<br />
<br />
I can see now that both of our methods assumed that the target would be orbiting and maintaining itself perpendicular. If you looked at the graphic, the presence of a chord clearly indicates that there are places that the target could travel that would result in greater bearings. The max bearing would be the angle that is tangent, which the angle for is asin(targetError/targetDistance). --[[User:Frolicking Zombie|Frolicking Zombie]] 21:31, 26 February 2010 (UTC)<br />
<br />
: Yes, that's what I was trying to say. I'm now working on an improved version to be able to narrow the uncertainty further by considering that you only need to see the edge of the robot rather than the center of it in order to detect it. This should give an even more efficient result in most circumstances, than the old one that used the bad assumptions we made, but still safe in the extreme conditions our old methods were not safe for. --[[User:Rednaxela|Rednaxela]] 00:53, 27 February 2010 (UTC)<br />
<br />
I may be talking out my ass here, not having followed your entire conversation closely, but you may need to double your expected angles, and here is why:<br />
Let's say for the sake of argument that your opponent is somewhere above you. Turn 105, you move, he moves, and you sweep your radar over him counterclockwise. You are told his position in turn 106. You anticipate that the furthest he can move to the right places him just left of true north, so you sweep to 0 radians, minimizing the width of your sweep and looking really slick with your narrow beam. Turn 106 is processed: you move, he moves, you sweep right, and now he is just left of your radar. So.. do you sweep left, or right? Left seems obvious .. he's to the left. But before you turn your radar, he is going to move. If he moves to the right of your radar beam, then you sweep left, your radar lock just slipped. If you sweep right and he slows down enough (possibly with the help of a solid object), your radar lock may slip to the right. If you instead sweep twice as far as he could move at full speed, there will never be a question of slipping due to anticipating velocity. It's not as absolutely cool as it could be, but honestly radar just needs to work. How many people watch battles with the radar graphic enabled anyway? --[[User:Pedersen|Martin]] 23:58, 26 February 2010 (UTC)<br />
<br />
: The details of Glacier's radar fully consider this issue I believe. Also about the usefulness of fancy radar... Glacier currently is able to keep a better don't-miss-a-tick lock on two widely separated bots better than any other melee bot currently in the field, and a barely-miss-any-ticks lock on two even wider separated bots by taking advantage of boosting the max radar rotation using the gun turret when gunheat is high. It's not worth much score, but it should really help bullet detection for melee surfing and such. Also, I always watch with radar graphics personally, even when I'm not experimenting with it :P --[[User:Rednaxela|Rednaxela]] 00:53, 27 February 2010 (UTC)</div>RednaxelaBot