[Home]RooseveltPMC

Robo Home | Changes | Preferences | AllPages

Brainfade's belated entry to the pattern matcher challenge. I needed an extra gun for Roosevelt and decided a pattern matcher was as good as any.

Currently Using:

Current performance:
1st: challenge.PatternBot 1.0 26302 3850 770 18280 3052 350 0 86 23 0
2nd: brainfade.newton.Newton 20678 1150 230 18110 1188 0 0 29 77 0

Ratio: 99.07%

i'll post the code here once i've beaten pattern bot.


Currently trying to balance skipped turns against accuracy. Think i must have a bug in there somewhere as it's not quite improving as i'd hoped. For projection i'm using:

        int startIndex = findStartIndex?();

        if (startIndex == -1) return there;
        int time = 0;
        double bulletTime = here.getDistance(there)/bulletSpeed;

        there.xpos += ((Math.sin(currentHeading))*velocity);
        there.ypos += ((Math.cos(currentHeading))*velocity);

        while ((time < bulletTime)&&(startIndex<10000))
        {
            currentHeading += (historyArr[0][startIndex]);
            there.xpos += ((Math.sin(currentHeading))*historyArr[1][startIndex]);
            there.ypos += ((Math.cos(currentHeading))*historyArr[1][startIndex]);

            time++;
            startIndex++;
            bulletTime = here.getDistance(there)/bulletSpeed;
        }

        return there;

anyone see any problems there?? -- Brainfade

I can't see a bug here..., but I like small code so try this:

        double bulletWay=0;
        int startIndex;

        if ((startIndex=findStartIndex?()) == -1) return there;

        do {
            currentHeading += historyArr[0][startIndex];
            there.xpos += Math.sin(currentHeading)*historyArr[1][startIndex];
            there.ypos += Math.cos(currentHeading)*historyArr[1][startIndex];
        } while((bulletWay+=bulletSpeed)<here.getDistance(there) && ++startIndex<10000);

        return there;

I feel better now. I just removed things I couldn't find in GlowBlow's code :). So you might have a bug somewhere else. -- rozu

Cheers rozu, i tried your code and although it made me realise 1 bug (startIndex<10000 should be 15000, this actually lowered my average). I must have a bug in my matching. Although it made no difference i subbed in your code for mine because it looks better than mine. I have this lovely tendency to make my code really wooly. If you ever get really bored then just ask and i'll send over all my code and you can reduce it for me. Trust me, there's alot..... :) --Brainfade

And of course, we all know that rozu loves to find our bugs for us! (lol) He found a wall-avoidance bug I had that caused the re-release of 4 different robots :-p -- Kawigi

It's a matter of taste. I would have kept the original code. Because it better describes what's going on. -- PEZ

I'm not a programmer. but I like things to be as compact as possible. If there is medium amount of "things to do" I'd be lost in the code if I wouldn't do it this way. however I started my first mega bot this weak and I seem to come away from this style of programming a little bit. but just a little... Brainfade, if you want me to help you searching bugs, you can send me some code (zuestro@student.ethz.ch). I might have time even though I should learn :) -- rozu

My MegaBot code does a lot of the same things as my MiniBot code, I just split things up a little more so I can document my logic better sometimes. And then I also create a lot more methods in my MegaBot code. -- Kawigi

Where's "currentHeading" initialized Brainfade? Could it be that you are using a global variable shared by the scanned robot event? That might cause strange results. Maybe you could try something like "double projectedHeading = enemyHeading" and then use "projectedHeading" in the rest of the function. -- PEZ

Might be. I once had the same but with the position of the target (used here as "there"). -- rozu

Yep, and the initialization of "there" is also a mystery in the code snippet so it might be a bug candidate here too. -- PEZ

Yeah, i passed you the entirity of a method except for the start, all the mysterious variables are passed as parameters to the method. As we speak the method is (inclusive of rozu's code):

    public Coordinate predict(Coordinate here, Coordinate there, double currentHeading, double velocity, double bulletSpeed)
    {
        double bulletWay=0;
        int startIndex;

        if ((startIndex=findStartIndex?()) == -1) return there;

        while((bulletWay+=bulletSpeed)<here.getDistance(there) && ++startIndex<counter)
        {
            currentHeading += historyArr[0][startIndex];
            there.xpos += Math.sin(currentHeading)*historyArr[1][startIndex];
            there.ypos += Math.cos(currentHeading)*historyArr[1][startIndex];
        } 

        return there;
    }

and it is called in my robot class by;

    PM.predict(here, target.position, target.heading, target.velocity, bulletSpeed);

Where any time a coordinate is mentioned, it is just a point2D with a different name, and the target.blahblahblah are updated the same way as in SnippetBot. -- Brainfade

Since "there" is a reference to "target.position" all changes you do to "there" (like updating positions and such) are also done to "target.position" which might be causing troubles. Try calling the method like this instead:

PM.predict(here, new Coordinate(target.position.xpos, target.position.ypos), target.heading, target.velocity, bulletSpeed);
Or make the copy inside the predict() method, whichever you fancy. (Thinking about it, I would maybe prefer the latter.) -- PEZ

I decided that tonight was the night to sort out my pattern matcher and after a fair bit of midnight oil, i think i have just found the bug that causing all my problems. When trying to match the pattern, i was doing number1 + (number2/2) rather than (number1+number2)/2. Fixing this has caused my PMC index to double to a reasonable 70% (ignore the name, i just stuck the pattern matcher class in testbot i had lying around to avoid the messy structure i have in roosevelt):

1st: challenge.PatternBot 1.0 21875 4900 980 13091 2552 268 83 99 2 0
2nd: brainfade.newton.Newton 9517 100 20 9281 115 0 0 3 98 0

I'm hoping that with a bit of tweaking i'll be able to up it a bit more. Big thanks go out to Pez and rozu who have gently nursed me along the way. Only problem now is that it's a bit to slow to stick in my virtual guns array, but i won't let that bother me for a while... --Brainfade

Do you run the matching every tick? If so you can speed up the gun some by checking your gun heat before matching. Something like:

if (getGunHeat() / getGunCoolingRate() < 4) {
    // match
}
On a further note, you might (or might not) be able to improve your hit rate if you tweak with how you build the pattern. Frankie builds the pattern keys inside its Frame class, like so:
    char getKey() {
        int key = 3;
        key = key + 11 * (int)((10.0 + Math.toDegrees(headingDelta)));
        key = key + (int)((Frankie.MAX_VELOCITY + velocity));
        return (char)(key);
    }
I add a constant to both values to make the pattern consist of positive values only. Also I use degrees for the heading delta to get more granularity. -- PEZ

I've been playing with similar things in order to try and get shorter but more accurate matches, and have managed to find around 7% so far. My problems seem to occur in the early rounds when my buffers are empty or nearly empty. I dont knwo hwo other peopel do it, but i fill a short string that stores recent values, then fill the history string from this (so i don't just match the current movement) this seems to work in the long run but causes it to be very slow at learning.I also think i have an occasional bug that occurs when i discard old data to try and speed up the system and skip less turns. I reccon i have to rectufy this to actually beat PatternBot. I am however curious as to why you make sure you have to have positive values?? As far as i'm aware, you can cast a negative value to a char without problem. Anyway, back to the tweaking..... --Brainfade

ahhhhhhhhh, i have just worked out why you want a positive value. You are forming a single character and adding it to the search string, where as i am dealing with pair of characters in a string (hence the divide by 2 in the bug i found above). I will try tweaking my dual character method for a bit and depending on how it goes i might switch over to a single character method... --Brainfade

You will probably speed your matching up considerably using a single character approach. About shorter, more accurate, matches I also thought along those lines a while. But at least against PatternBot this is not the way to go. LeachPMC (from where Frankie got its gun) finds very long, very accurate, matches against PatternBot. Often 1000+ characters and about 300+ on average. When it comes to disposing old data, I just remove the first frame when adding a frame on a movie of full length. -- PEZ

Yeah, i had already decided to make the changes you suggest. I was storing my data in arrays (which is a bad thing as arrays suck) and have decided to use an arraylist instead (easy to add and delete specific items). the reason i'm changing over to a single character approach is that robocode doesn't seem to like use of the lastIndexOf?() method on long strings (skips turns like it's going out of style), so i had to keep them shorter than i'd like. this way i can double the length of the string i keep with no performance problems. Hopefully i'm just a few minor changes from jumping above the dotted line... --Brainfade

Cool. Then you can rid yourself of using parallell arrays (or lists) as well, while you're at it. Make something like my Frame class instead and you'll have less bug prone code. Remember to use the List interface as type specifier for your ArrayList. Likse so:

List movie = new ArrayList(MOVIE_SIZE);
-- PEZ

Robo Home | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited July 13, 2003 22:52 EST by PEZ (diff)
Search: