On the one hand you may want to save everything you have learnt about the enemy. On the other hand it might be too much and result in too large files. In Robocode you only have 200K to save data. Schemes where you try to figure if you really need the learnt data next time you meet this enemy are tricky. In the RoboRumble@Home rankings you need to be tough against the tough and even tougher against the weak. Which might lead to a descision that you should try to remember each and every opponenet you meet. In RR@H currently that means you have aorund 1K per enemy.
1K per enemy means you might not be able to save the full segmented data you have collected on the enemy during the battle. Paul Evans suggested you might get away with saving only a "crib sheet". I have tried implementing this on top of GloomyDark's segmentation and do it the very brutest way. I iterate over each bucket in each segment to find what guess factor is the most visited. Then I zero out all other factors and set the most visited factor's count to a low number. This means I still save the whole array structure and can restore it the same way as before. This will make this scheme work in a MiniBot, but for a MegaBot I think there are much better ways.
-- PEZ
Please help updating this list of bots using CribSheet methods:
Please also use this page to discuss various approaches to crib sheet save/restore.
void doit(boolean how){ int k=0; do { int[] curr=GFactors[k/54][(k/3)%6][k%3][(k/18)%3]; if (how) curr[mx[k]]=15; else { int i=0; int max=31; do { if (curr[i]>curr[max]) max=i; i++; } while(i<31); mx[k]=(byte)max; } k++; } while (k<6*3*3*9); }-- Frakir
I have stared at it for a while now... Can you maybe explain what's going on a bit more? -- PEZ
I think he posted some C code by mistake. --Wolfman
=) Nah, it's certainly C style, but valid Java code as far as I can see. -- PEZ
It looks like he's compressing all his segmentation dimensions into a single dimension. Looks like it should work quite well, assuming you don't have so many dimensions that the 6*3*3*9 bit would be more than max_int. -- Tango
Sorry for being unclear... The idea was to fit it in mini, so the line:
int[] curr=GFactors[k/54][(k/3)%6][k%3][(k/18)%3];replaces 4 loops by each array dimension. Then depending on boolean parameter best offset number is saved to one-dimensional byte array, or it is reseeded with some arbitrary number (15 in my case is 5 hits, forgot to mention that). And yes, my variable naming is definitely far from java-style :( I posted the code because it is rather compact, and it illustrates how to avoid many nested loops... -- Frakir
Interesting. Can you explain the magic numbers some as well? I think you would gain claratity by making the outer loop a for loop... And if you're worried about code size you probably should replace the 6*3*3*9 calculation with the result only. Or maybe the compiler takes care of that? -- PEZ
Just got back home... answering Tango: if you have more segments then max_int, you better make sure your bot/Java? VM runs on 64bit machines (you'll need more then 8Gb ram) :)
To further clarify 'magic numbers': I think I'll make an example (pseudo-code):
//3 nested loops, 'classic way': int k=0; for (i0=0; i0<2;i0++) for (i1=0; i1<4;i1++) for (i2=0; i2<3;i2++) { //in this section you can always be sure //that i2==k%3, i1==(k/3)%4 and i0==k/(3*4); //now do something with myArray[i0][i1][i2]; k++; }
.....
//now lets get rid of loops, same functionality: int k=0; do { // do something with myArray[k/(3*4)][(k/3)%4][k%3]; k++; } while (k<2*3*4);
About numeric constants: AFIK compiler reduces constant expressions during compilation; so writing Math.PI/4 don't take any more space then 0.785398 Not sure if function calls with constant parameters are resolved during compile in Java (like Math.sin(1)) -- Frakir
Many thanks! As always, I need an example to understand. I hope you never do this kind of obfuscation unless the codesize constraint calls for it. =) And I insist on that this is clearer:
for (int k=0; k<2*3*4; k++) { // do something with myArray[k/(3*4)][(k/3)%4][k%3]; }Not only is it clearer, it makes "k" local to the loop scope. I think it's of equal codesize since the compiler will probably rewrite it as a "do {} while" for you.
-- PEZ
The compiler doesn't resolve things like Math.sin(1) at compile time - for awhile I was dividing things in FloodMini by funny constants that were just the sine of some number. It also will rewrite all for loops as while loops, not do-while loops (which is why you don't see very many for loops in nanobots). -- Kawigi
Some optimizations depend on the compiler. Jim and I noted that Griffon often got smaller when compiled on Jim's machine. But of course the compiler can't assume a function always returns the same given the same arguments. That would make the compiler pre-calculate a call like Math.random() (or a wrapper around it taking the boundaries as arguments) which is probably not what you want. =) -- PEZ