[Home]HatTourney/MessageFormat

Robo Home | HatTourney | Changes | Preferences | AllPages

Showing revision 22
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

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


Robo Home | HatTourney | Changes | Preferences | AllPages
Edit revision 22 of this page | View other revisions | View current revision
Edited January 15, 2008 19:46 EST by trill.lib.fit.edu (diff)
Search: