The highlighted comment was created in this revision.
This looks really cool! The only problem I can see is if the bullet power is below 1, it won't react to fire in the oscillate mode. I also fixed a tiny problem in the number of values in the REVERSE_ON_ENEMY_FIRE block.
Interesting. Is this functionally different or just for the codesize?
If so how much is it saving?
I remember trying something similar to remove a conditional and replace it with a formula and it came out larger so I ditched the idea. Admittedly I was doing something a little different, but cool if you have gotten it to work for you and gained codesize.
I noticed the problem with casting the energy drop to an
int, but I figured that if an enemy was firing power 1s at a distance of around two hundred pixels, we would be able to get a score of 80+%, even with RM.
This method saves two bytes over the conditional method (just enough to fit
setAdjustGunForRobotTurn(true)). I don't think it is functionally different from a conditional check. If it is, I probably did something wrong.
Off Topic: I don't understand how your new Adept movement works. What's the point of
moveMode ^= 1? Wouldn't that just return
The old neophyte movement changed moveMode from 1 to -1 and back on every bullet hit. Then used direction *= moveMode to flip between orbit mode and oscillate mode whenever we get hit.
The new adept movement keeps that, but combines it with a yatagan style onDeath lookup table. However note that in adept onDeath uses moveMode += 2. ^ is the XOR operator, so on every bullet hit we toggle the low bit. This allows it to combine pure orbit, switch on death to pure oscillate. Do that a few times as yatagan does, then after several deaths it will go back to toggling between orbit and oscillate on every hit.
D'oh! I thought that carets were exponentiation operators. Your movement makes much more sense to me now that I realize they are inequality checks.
Sorry for being all pedantic about it, but I just wanted to make sure you understood that XOR isn't an inequality check.
if you have two numbers say:
then c=a^b; sets each bit of c to 1 iff that bit in a is one or that bit in b is 1 but not both. Otherwise the bit is set to 0. So c==0011011 is true.
Again. Sorry for being pedantic but I wanted to make sure that this was clear.
I ran some tests, and it looks like we'd only get a score in the sixties. I'm not worried though, because I don't know of a single bot in the rumble that would fire bullets less than power 1.0 at close range, except in the endgame. And even if there was one, it would likely have a HOT gun, which would be dodged by orbit movement anyway.
Hmm, apparently not quite as good as 119. The scores may not have quite stabilised yet, but it has dropped down to second with 78.06 APS, about -1.2 IIRC :(
On the plus side I briefly get to retake the lead :)
Not to worry though, I have the superlatively evil (nasty, unpleasant, dishonourable, cheating or the insult of your choice) version 1.2 of PralDeGuerre under development. Now if only it performs up to the statistical predictions...
By the way, how much space is that move change saving? I think Sheldor said 2 bytes.
An alternative that might perform better (can't say for sure, you would have to benchmark it) would be to use the old move, but change the "... - (1.1 - 1e-8) ) <= 1)" to "... - 1) <= 2)".
This is slightly less accurate as the energy detect is .001..3.999 rather than .001..3.001, but it could work better.
You would also need to update the rand chance to be "4 / 0.6*Math.sqrt(..." rather than "3.0/(0.6*Math.sqrt(.." to account for the wider window.
The drop in score is due to two problems with the table. I just fixed both of them.
Yep, this method of enemy fire detection is two bytes smaller than the previous. The other
char based check you just posted would be (going by memory here) only one byte smaller than the original, which would be one byte bigger than my new method.
It may be compiler dependent, I am just using standard jdk 1.6, but every time I have sized that it has been 2 bytes different.
1 is dconst_1, size 1 byte.
Any other double constant (except zero and possibly stuff that can be cast from an int constant) is
ldc2_w, indexbyte1, indexbyte2, size 3 bytes.
As to which is functionally superior I am not sure, I haven't done extensive benchmarking on that variant of Yatagan movement as those extra 2 bytes were not enough for me to add anything else, so I didn't use/test it much.
In Jikes that also saves 2 bytes. I think this would be a interesting one to try out after 1.2.1 stabilises.
Ah well, I had a few hours at the top, but it was not to last.
It has only had 1000 battles, but this version looks to have lost half a point from 1.1.9.
So I was testing some other stuff and decided while I was at it to bung some yatagan variants through my benchmarks.
Note, take the figures with a grain of salt as there can be up to 1% jitter and these are all quite close. Also my figures often show .5 to 1% higher than the rumble, but what I got was:
- jk.sheldor.nano.Yatagan 1.1.7 79.6%
- jk.sheldor.nano.Yatagan 1.2.1 78.8%
- nz.jdc.nano.Yatagan117a 1.0.0 79.4%
- nz.jdc.nano.Yatagan117b 1.0.0 79.0%
1.1.7 and 1.2.1 are your released versions, both scores align reasonably with the rumble and show 1.2.1 being down a little.
117a is a copy of 1.1.7 with the movement code change suggested above.
117b is a copy of 117a, but with the addition of setAdjustGunForRobotTurn(true);
Not sure what is causing the (relative) weakness in 1.2.1, it could be the change in energy detection, or it could be putting oscillate first in the table, or another table bug. Another possibility is the gun adjust. I have varying results with that and often find it hurts rather than helps the score. The result of the otherwise identical 117b being worse than 117a leads me to believe the gun adjust is a factor.