Talk:Hat League/Message Format
Here's my draft suggestion for a common message format. Each line in a message is a different message, prefixed by the message type, followed by comma-seperated-values:
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.
The result of this code is a String array containing the number of elements specified by a parameter. If there are fewer elements in the CSV string, the remaining elements in the array will be null strings. This will not be a problem since we know by the first element what type of message it is, and how many elements we are looking for. -- Martin
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
- That is also my understanding. -- Martin
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
- The implementation covers all message types listed at the top of the page (hence the CSV approach), as well as a "CommuniqueNotAvailable" representing something that was unparseable. They are packaged as wiki.team.communication.* -- Martin
I wrote an implementation at User:AaronR/HatLeagueRobot. It is a fairly standard event-delegating framework, but I haven't tested it very much. « AaronR « Talk « 01:23, 15 January 2008 (UTC)
- [View source↑]
- [History↑]
You cannot post new threads to this discussion page because it has been protected from new threads, or you do not currently have permission to edit.