PD,time,x,y,h,v,e // personal data ES,time,x,y,h,v,e,name // enemy scan BO,time,x,y,h,v // bullet (origin) EW,time,x,y,v // enemy wave origin MR,name // my radar target MB,name // my bullet target TR,name // suggested radar target TB,name // suggested bullet target NA,message // custom message-- Martin
I like the messages you have laid out there. So were you thinking of just sending strings for each thing? Alternatively, we could create a base class for everyone to extend, with (Serializable) classes for each message type, and methods for sending the messages that are customizable (i.e., not personal data or enemy scan); then create the onMessageReceived method that passes off the message types to handler methods, which you'd override like with the built in event methods. I hope I'm making sense... No other message types come to mind that you don't already have listed, but I'll rack my brain a bit. -- Voidious
In my second attempt at making a team robot, I had a serializable structure that had some doubles in it, but when I tried to send it to the message broadcaster it choked. I ended up having to break the same data into a comma delimeted string manually and reinterpreting it on the other end. If there is some magic thing I overlooked then it would certainly be easier to send it as a structure. Otherwise we / I can provide a complete class to compose and translate messages. I do mostly batch processing lately so I've got routines for doing the CSV stuff already. -- Martin
Sending serializable structures (with doubles) worked in my last 5 team attempts :) --Krabb
Just FYI, I found that internal classes wouldn't serialize even if they extended Serializable. The moment I made the class external, problem solved. -- Skilgannon
public static String[] parseCSV( String line, int count ) { final char delimeter = ','; final char textWrapper = '\"'; return parseDelimetedValues( line, count, delimeter, textWrapper ); } private static String[] parseDelimetedValues( String delimetedValues, int count, final char delimeter, final char textWrapper ) { String value[] = new String[ count ]; int startIndex = 0; int endIndex = 0; try { for( int i = 0; ( ( i < count ) && ( endIndex != -1 ) && startIndex < delimetedValues.length( ) ); i++ ) { if( delimetedValues.charAt( startIndex ) == textWrapper ) { startIndex++; endIndex = delimetedValues.indexOf( textWrapper, startIndex ); value[ i ] = delimetedValues.substring( startIndex, endIndex ); startIndex = delimetedValues.indexOf( delimeter, endIndex ) + 1; } else { endIndex = delimetedValues.indexOf( delimeter, startIndex ); if( endIndex == -1 ) { value[ i ] = delimetedValues.substring( startIndex ); } else { value[ i ] = delimetedValues.substring( startIndex, endIndex ); startIndex = endIndex + 1; } } } } catch( Exception ex ) { ExceptionHandler.getInstance().log( ex ); ExceptionHandler.getInstance().log( "line: " + delimetedValues ); } return value; }Above is some code I've written for a batch processing application. I am sure it could stand some optimization. The ExceptionHandler class is just a log file recorder. You could also use this to process tab delimeted (not shown) or some other delimeter. Writing out comma separated values is much simpler, so I didn't bother writing any example code.
Possible beginning of a "base class":
import robocode.*; import robocode.Bullet; import java.io.*; // // "Base Class" to share information, every bot must extend "CustomTeamRobot" // and call the setCustomTeamRobot(this) function // public class CustomTeamRobot extends TeamRobot { CustomTeamRobot robot; public void setCustomTeamRobot(CustomTeamRobot robot) { this.robot=robot; } public Bullet setFireBullet(double p) { Bullet b = super.setFireBullet(p); if(b==null) return b; MessageBullet mb = new MessageBullet(b, p, this); if(getTeammates()!=null) { try{ broadcastMessage(mb);} catch(IOException ex){ System.out.println(ex);} } return b; } public final void onMessageReceived(MessageEvent ev){ if(ev.getMessage().getClass()==MessageBullet.class) { robot.newTeamBullet(new TeamBullet((MessageBullet)ev.getMessage(),this)); } } public void newTeamBullet(Bullet b){ } } //class to send Bullet data class MessageBullet implements Serializable { double heading; double power; double velocity; double x_start,y_start; long time_start; public MessageBullet(Bullet b, double power, CustomTeamRobot robot) { heading=robot.getGunHeadingRadians(); this.power=power; velocity=20-3*power; x_start=robot.getX(); y_start=robot.getY(); time_start=robot.getTime(); } public double getHeading(){ return heading;} } // simulates a real robocode "Bullet" class TeamBullet extends Bullet { CustomTeamRobot robot; MessageBullet mb; public TeamBullet(MessageBullet mb, CustomTeamRobot robot) { super(null); this.robot=robot; this.mb=mb; } public double getY() { return mb.y_start+Math.cos(mb.heading)*mb.velocity*(robot.getTime()-mb.time_start); } public double getX() { return mb.x_start+Math.sin(mb.heading)*mb.velocity*(robot.getTime()-mb.time_start); } } //============================================================================================= ///////////////// //Test Robot: ///////////////// import java.awt.*; import java.util.*; import robocode.Bullet; public class TeamTestBot extends CustomTeamRobot { ArrayList<Bullet> bullets = new ArrayList<Bullet>(); public void run() { setCustomTeamRobot(this); setTurnRadarRightRadians(Double.POSITIVE_INFINITY); setTurnLeft(Double.POSITIVE_INFINITY); setAhead(Double.POSITIVE_INFINITY); while(true) { Bullet b = setFireBullet(3); if(b!=null) bullets.add(b); System.out.println("size: "+bullets.size()); execute(); } } public void newTeamBullet(Bullet b){ bullets.add(b); } public void onPaint(java.awt.Graphics2D g) { g.setColor(Color.RED); for(int i=0; i<bullets.size(); i++) g.fillOval((int)bullets.get(i).getX()-2, (int)bullets.get(i).getY()-2, 5, 5); } }
This could be the beginning of a "base class" for all competitors, we could implement the same for ScannedRobotEvents and Bullet Missed(/Hit)Events. With this kind of implementation the bots don't have to differentiate between their own or mate bullets and events, but it might be a bit slow :/ Suggestions? --Krabb
Would the 2000 byte limit still apply? Cause this code doesn't exactly look optimized for size... ---David Alves
I was under the impression there would be no CodeSize limit for this... ? -- Voidious
I'm mentioning this prematurely, as I don't have the JavaDoc written and am not really competent at packaging JAR files (which seems odd since I've done Java since 2000), but I've written a set of classes to support team communication. They don't do automatic serialization, but rather read and write comma-separated value Strings. I'm open to do some beta testing with anyone interested in making the Hat Tourney a reality. -- Martin
(discussion migrated to new wiki)
I'm running into some issues with packaging the JAR file. All of my traditional tank code is packaged under pedersen.*, but the new communication code is packaged as wiki.team.communication.*. I launched Robocode from within Eclipse and started getting errors about one of the communication class files being duplicated. Doing a clean and rebuild did not change this. I started a new project and moved the communication package to it, linking robocode.jar (for MessageEvent?). I packaged the contents as a JAR file under F:\robocode\libs\communication.jar, linked to it from my main tank project, and added the jar to the VM arguments for launching Robocode within Eclipse. Launching Robocode within Eclipse again I got NoClassDefFound? errors for the communication classes. Anyone know what I am doing wrong? -- Martin