Difference between revisions of "Talk:Saving"
(Robobot 0.1 : correcting user page links) |
|||
Line 115: | Line 115: | ||
That can be a tough question. My opinion is that you should probably at least store your VG stats and your info for guns that aren't particularly expensive to save (like your guess-factor gun probably). The problem that leaves you with is if you test a bot and you run long matches, the pattern-matcher might get pretty good, but then in real competition, it will remember that the PM was good but forget that it doesn't have much saved on the pattern-matcher. Something on FloodHT's todo list is adding a pattern-matcher that 'rates' the matches I get (either by how close they are or how long, depending on the nature of the PM) and then stores VG stats for each possible strength (so say I find a pattern of length 20, I'll use that instead of the Guess-factor gun, but if I find a match of length 4, I won't, regardless of how much pattern I know). -- [[User:Kawigi|Kawigi]] | That can be a tough question. My opinion is that you should probably at least store your VG stats and your info for guns that aren't particularly expensive to save (like your guess-factor gun probably). The problem that leaves you with is if you test a bot and you run long matches, the pattern-matcher might get pretty good, but then in real competition, it will remember that the PM was good but forget that it doesn't have much saved on the pattern-matcher. Something on FloodHT's todo list is adding a pattern-matcher that 'rates' the matches I get (either by how close they are or how long, depending on the nature of the PM) and then stores VG stats for each possible strength (so say I find a pattern of length 20, I'll use that instead of the Guess-factor gun, but if I find a match of length 4, I won't, regardless of how much pattern I know). -- [[User:Kawigi|Kawigi]] | ||
+ | |||
+ | == Saving without zip == | ||
+ | I'd really like it if someone wrote an article or comment about reading/saving objects without zip. :) I can't find or solve it. I've tried the following, but get an IOException when writing (and I guess loadData function won't work either): | ||
+ | |||
+ | <pre> | ||
+ | private static final String statisticsFile = "statistics.dat"; | ||
+ | private static StatisticalInfo statisticalInfo = | ||
+ | new StatisticalInfo(); | ||
+ | public static void loadDataFromFile(Portia b) | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | FileInputStream file = | ||
+ | new FileInputStream(b.getDataFile(statisticsFile)); | ||
+ | ObjectInputStream in = new ObjectInputStream(file); | ||
+ | statisticalInfo = (StatisticalInfo)in.readObject(); | ||
+ | in.close(); | ||
+ | } | ||
+ | catch (FileNotFoundException e) | ||
+ | { | ||
+ | System.out.println("FileNotFoundException"); | ||
+ | } | ||
+ | catch (IOException e) | ||
+ | { | ||
+ | System.out.println("IOException"); | ||
+ | } | ||
+ | catch (ClassNotFoundException e) | ||
+ | { | ||
+ | System.out.println("ClassNotFoundException"); | ||
+ | } | ||
+ | } | ||
+ | public static void saveDataToFile(Portia b) | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | RobocodeFileOutputStream rfos = | ||
+ | new RobocodeFileOutputStream(b.getDataFile(statisticsFile)); | ||
+ | ObjectOutputStream out = new ObjectOutputStream(rfos); | ||
+ | out.writeObject(statisticalInfo); | ||
+ | out.flush(); | ||
+ | out.close(); | ||
+ | } | ||
+ | catch (IOException e) | ||
+ | { | ||
+ | System.out.println("IOException"); | ||
+ | } | ||
+ | } | ||
+ | private static class StatisticalInfo | ||
+ | { | ||
+ | public int totalNumberOfMatchesFought = 0; | ||
+ | public int totalNumberOfMatchesTurnSkipped = 0; | ||
+ | public int totalNumberOfMatchesException = 0; | ||
+ | public int totalNumberOfRoundsFought = 0; | ||
+ | public int totalNumberOfRoundsTurnSkipped = 0; | ||
+ | public int totalNumberOfRoundsException = 0; | ||
+ | public int totalNumberOfRounds1st = 0; | ||
+ | public int totalNumberOfRounds2nd = 0; | ||
+ | public int totalNumberOfRounds3rd = 0; | ||
+ | } | ||
+ | </pre> | ||
+ | --[[User:Positive|Positive]] 00:21, 29 August 2009 (UTC) |
Revision as of 01:21, 29 August 2009
Contents
Old Wiki: SavingDataHowTo or Saving/How
I am struggling with adding persistence to my robot. Now I don't know a good way to see when the MatchIsOver. -- PEZ
static variables
The easiest way to save data between rounds is to make your variables static. There is no need to save data to a file and retrieve it. You usually store the enemy information you collected in previous rounds (if you need it later) or information stored in files that you need to read only once. -- Albert
As far as I know static variables in a Java class is shared among all instances of that class. Robocode creates a new instance of your bot for each round (and then calls the run() method), but since static variables are shared among all instances, your bot still has access to the data that was saved in the static variables last round. I'm not sure what this means if you have multiple instances of the same bot on the field though? --Zeb
In principle, multiple instances of the bot work OK. I'm not sure why (because they are the same class, they should share the data). My guess is that it is OK because they execute in different threads. -- Albert
I've found the answer in an old posting by Mat: http://www.alphaworks.ibm.com/forum/robocode.nsf/archived/5F86B09EE7DCA3E682798BC09C4B0950?OpenDocument It says that each robot is created by separate ClassLoaders, with the purpose being that they should not share static variables. -- PEZ
I'm still a bit confused about what Robocode does between rounds. I have a static collection of enemies, each which get an instance of my robot when they are created. How come this robot reference is still valid between rounds? Isn't it a new instance of the Robot then? Or why would you need static variables for this otherwise? -- PEZ
Pondering and discussing with my colleagues I now think I know the the answer to this question: Calls like getHeading() are accessing static variables in the robot. My static collection holds a reference to an old and dead robot, but it shares those static variables with each new and fresh instance, which make it work. It's when you try calls like ahead() that things stop to work. -- PEZ
Serialization
Serializable means that a class can be converted into an array of bytes which can then be written to disk, sent over a network, etc. For a class to be Serializable it must (a) have no member variables which hold non-serializable classes and (b) implement the Serializable interface. The only real problem you can run into is if you have an object with a lot of references to other objects: when you serialize it, youll also be serializing and all of those objects, any objects that they have references to, etc. In an early version of Duelist I couldn't understand why my datafiles were about 40k per bot - turned out that one of the things I was serializing had a reference to my bot in it, so I was serializing EVERY object my bot used! :-P --David Alves
You use the transient keyword to indicate that a member variables aren't part of the persistant object. As long as you know how to reconstruct an "incomplete" deserialized object you just put transient in front of the variable declaration and it won't get serialized along with the rest of the object. Beware though that if you initialize a transient variable upon declaration you won't have the initialized value on that variable after deserialization. Like:
transient double largestX = getBattleFieldHeight() - getWidth() / 2;
The variable 'largestX' will have the value of 0 (zero) after deserialization. Now this particular variable you might want to serialize anyway. =) But you get the drift I hope. -- PEZ
You can also compress the serialized files. Kawigi shows how in CompressedSerialization.
Other
If you have your data in simple, primitive type, arrays you can store and retrieve that data compressed by using a variant of the serialization thingy above: WritingArraysToFile. -- PEZ
TIP:
if you want to increase your file quata in your local machine, add the robocode.robot.filesystem.quota=2000000 in your robocode.propoerties file. It will set the file quata to 2MB. --SSO
If you are having problems saving data under 1.4.2, look here: JRE 1.4.2 SecurityException Bug
Old Wiki: Reducing File Size or Saving/Size
I'd like to know how other people reduce the size of the data they save per robot. I was thinking about using the zip stream thing, but didn't have a clue about how to use it. Anyone help? -Wolfman
In my bot Parakeet, I store two arrays of floats instead of two arrays of doubles.. It cuts the filesize in half... I didn't need the precision of doubles anyway. --Dummy
Hrm ... what format do you save as Dummy? I just save as a text file currently. So Im not sure how saving as a float instead of a double will help in that circumstance! -- Wolfman
What are the limits of this file anyway? I was considering just serializing my Enemy objects, but I guess that's out of the question? -- PEZ
Serializing Enemy objects works, but if you find yourself running out of space, you can do better. You don't need to store things like last position, heading, velocity, etc. which are probably in your enemy class. What DuelistMini does is to store an array of doubles in a GZipOutputStream. Remember that arrays are java Objects, so you can write an entire array by using:
myObjectOutputStream.writeObject(myArray);
and read an entire array from an input stream by using:
myArray = (double[][]) myObjectInputStream.readObject();
Parakeet saves one integer and two arrays per datafile (one datafile for each opponent it meets in 1-on-1. No data-storage in melee battles). The source of Parakeet is included in the .jar file on the RoboCodeRepository. Actually, I looked in TheArtOfWar's source code to see how writing to files worked. Which reminds me... forgot to add credits in Parakeet's description and source. --Dummy
Object Streams consume a lot of space. Take a look inside a file written using ObjectOutputStream. If I remember correctly, each field is identified by its name and type, as well as the field's value. The signatures of the object's methods might also be written to the file. On the other hand, these files should compress very well with Zip Streams.
If you are really want to reduce file size, you might want to look at Data Streams. Write only the fields you absolutely need. If you still need to reduce the file size, try cramming larger fields into smaller ones where possible (ie: double into int). Sure, you will lose some precision, but if file size is a real issue for you, you have to be willing to make some sacrifices.
TheArtOfWar's Bot class uses Data Streams, and the Reaction class crams two double fields (heading and speed) into two byte fields. The source is available at the RobocodeRepository. I should have used Zip Streams for further file size reduction, but I never got around to it -- Ray_Vermette
Using Zip Streams is demonstrated, with code, on the CompressedSerialization page. -- PEZ
Old Wiki: Saving/What
What info to Save
More than one opinion here-
Dave Mold says to collect acceleration and change in heading.
Plenty say to collect velocity and change in heading (these could be equivalent for good data)
Paul Evans says to collect what firing angle should have been used based on distance and last direction of motion.
A good circular aimer might collect only the velocity for several turns and the change in heading for several turns (to average them).
Other ideas? Is it worthwhile to save information about your opponent's offense? --Kawigi
This depends heavily on what aiming methods and movement system you are using. Heading change and velocity is good for playback when PatternMatching. 0.9.9.x versions of Marshmallow used to keep information on what dodging angles it had used and how they had worked. Is that what you mean by "opponent's offense"? -- PEZ
That's the general idea, although I was thinking in a more advanced sense - if you try and track their bullets, store the powers the opponent tends to use, and when you got hit, if it appears he used direct, linear, circular, pattern, statistical, or other aiming techniques. Just a thought that probably goes under DodgingBullets. -- Kawigi
Well, I think that might be a bit too much work for a rather slow learning process. Few bots rely on linear or circular aim alone, but instead use them if it seems you are moving in a particular pattern. If you have a good pattern matcher yourself you might use it to neutralise any pattern matcher the enemy might have by making sure you don't go where your own pattern matcher guesses you'll go. Same thing with statistical aim (which is what those 0.9.9.x version of Marshmallow tried to do). But you'll need something along the lines of AntiGravityMovement to do the "avoid" part of the plan. (Which is where Marshmallow failed since it doesn't use anti-grav...). Indeed, if it seems the enemy relies in HeadOnTargeting you might shift to a particular movement strategy where direct aim never hits. (Like moving like Walls or some such). -- PEZ
It's certainly easy to shift to a movement that beats HeadOnTargeting. One thing I toyed with was a bullet dodging technique that wasn't quite perfect, and I had it just print "AM I HIT?" every time it got hit by a defensive virtual bullet. Then it would print "I'M HIT" in onHitByBullet. Virtually all the time, the "I'M HIT" message came amidst a few "AM I HIT" messages. It seems like one could figure out what's hitting me most of the time when I get hit, and use that to my advantage. Pattern-matching yourself is a good idea, too, sometimes, I think I've noticed MogBot doing it. It may be even better to implement multiple pattern-matchers (an acceleration-change in heading one, a velocity-change in heading one, one that just looks for the frequency in changes in direction, etc), to have good defense against any of them (of course, after awhile, there's just a bullet everywhere.
The avoid part can be done without antigravity, antigravity is just a convenient way to do it that doesn't take much processor time if it's done right. SpareParts has a Bullet-dodging movement that works well in general (dodges just HeadOnTargeting, LinearTargeting, and CircularTargeting, both with velocity averaging and without). It just searches for the closest point that it can be at that doesn't intersect any "Virtual Lasers" that I create for each projected bullet. -- Kawigi
Yes, it is because avoiding direct aim is so easy I thought it might be worth it to implement a check for it and the antidote. And while few bots rely on circular or linear aim some does rely on direct aim. Try using direct aim only against Marshmallow and you might find that it is quite effective... The problem with pattern matching is that it is time consuming. Though you can of course record lots of parameters and empirically try to figure what works best. Your search for "safe" points is something like what I mean when I speak about WantedTerrain. -- PEZ
But collecting info doesn't cost anything so you could collect just about anything. Marshmallow certainly does... It's when it comes to using the info where you might pay a price (like with PatternMatching) and certainly when you want to save data between matches, which is where WhatToSaveBetweenRounds (and matches) comes in. -- PEZ
What to save Between Rounds
You can save pretty much everything and anything you collect. You shouldnt variable things between battles (positions, time, etc) but beyond that, keep all important info in static variables and they will stay between rounds.
What to save Between Battles
Ok, I am currently porting various guns from testbots into Raven and his Virtual gun array, but i'm struggling to decide what to store between battles. Although there will probably be more, the key guns i'm looking to port are PatternMatcher, GuessFactorTargetting, VirtualBullets. The question is do i store the stats for each of the individual guns between battles, the stats for the virtual guns, or both???
Also, how many bot's should i leave capacity to store?? -- Brainfade
That can be a tough question. My opinion is that you should probably at least store your VG stats and your info for guns that aren't particularly expensive to save (like your guess-factor gun probably). The problem that leaves you with is if you test a bot and you run long matches, the pattern-matcher might get pretty good, but then in real competition, it will remember that the PM was good but forget that it doesn't have much saved on the pattern-matcher. Something on FloodHT's todo list is adding a pattern-matcher that 'rates' the matches I get (either by how close they are or how long, depending on the nature of the PM) and then stores VG stats for each possible strength (so say I find a pattern of length 20, I'll use that instead of the Guess-factor gun, but if I find a match of length 4, I won't, regardless of how much pattern I know). -- Kawigi
Saving without zip
I'd really like it if someone wrote an article or comment about reading/saving objects without zip. :) I can't find or solve it. I've tried the following, but get an IOException when writing (and I guess loadData function won't work either):
private static final String statisticsFile = "statistics.dat"; private static StatisticalInfo statisticalInfo = new StatisticalInfo(); public static void loadDataFromFile(Portia b) { try { FileInputStream file = new FileInputStream(b.getDataFile(statisticsFile)); ObjectInputStream in = new ObjectInputStream(file); statisticalInfo = (StatisticalInfo)in.readObject(); in.close(); } catch (FileNotFoundException e) { System.out.println("FileNotFoundException"); } catch (IOException e) { System.out.println("IOException"); } catch (ClassNotFoundException e) { System.out.println("ClassNotFoundException"); } } public static void saveDataToFile(Portia b) { try { RobocodeFileOutputStream rfos = new RobocodeFileOutputStream(b.getDataFile(statisticsFile)); ObjectOutputStream out = new ObjectOutputStream(rfos); out.writeObject(statisticalInfo); out.flush(); out.close(); } catch (IOException e) { System.out.println("IOException"); } } private static class StatisticalInfo { public int totalNumberOfMatchesFought = 0; public int totalNumberOfMatchesTurnSkipped = 0; public int totalNumberOfMatchesException = 0; public int totalNumberOfRoundsFought = 0; public int totalNumberOfRoundsTurnSkipped = 0; public int totalNumberOfRoundsException = 0; public int totalNumberOfRounds1st = 0; public int totalNumberOfRounds2nd = 0; public int totalNumberOfRounds3rd = 0; }
--Positive 00:21, 29 August 2009 (UTC)