AI Client Guide

Submitted by yuz on Sun, 2005-09-11 23:37.

It's very easy to implement a simple AI player for TOS, but centainly not easy to implement a smart AI team player. In this section, we describe how to implement a simple AI player in Java, whose only strategy is to chase the ball and kick the ball to the goal. Readers may also implement the client in any other language.

Parsing and Networking Java APIs

TOS provides parsing and networking APIs in Java Package soccer.common.

Source Code of a Simple AI Program

The complete source code of a simple AI program called AI.java is listed in this section.
To compile it, type:
javac -classpath .:soccer.jar AI.java
To run it, type:
java -cp .:soccer.jar AI

/* AI.java
* A simple AI program for TOS. The only strategy is to chase ball 
* and kick the ball to opponent's goal.
*  
* Yu Zhang, Copyright (C) 2001
*
*/

import java.io.*;
import java.util.*;
import java.net.*;
import java.util.StringTokenizer;
import soccer.common.*;

public class AI
{
  // default soccer server address settings
  static InetAddress address;
  static String      host = "localhost";
  static int         port = 7777;
       
  private Transceiver transceiver = null;
  private Packet      packet      = null;
       
  private InitData       init = null; // Initialization information from server.
  private SeeData        see  = null; // Visual information from server.
  private static int     side = 2;    // the side that the AI wants to join. 0 -> left, 
                                      // 1-> right, 2 ->anyside

  private boolean  IHaveBall  = false;
  
  // Constructs a simple AI player
  public AI()
  {
    // sets the server address.
    try
    {
      address = InetAddress.getByName(host);
    }
    catch(Exception e)
    {
      System.out.println("Network error:" + e);
      System.exit(1);
    }
             
    // sets up UDP networking utility;
    transceiver = new Transceiver(false);
  }     
      
  // establishs the connection to server, if it's sucessful, return true. 
  private boolean init()
  {
    try
    {

      // sends the connect packet to server
      ConnectData connect;
      if(side == 0) connect = new ConnectData(ConnectData.PLAYER, ConnectData.LEFT);
      else if(side == 1) connect = new ConnectData(ConnectData.PLAYER, ConnectData.RIGHT);
      else connect = new ConnectData(ConnectData.PLAYER, ConnectData.ANYSIDE);
               
      packet = new Packet(Packet.CONNECT, connect, address, port);
      transceiver.send(packet);
             
      // wait for the initialization message from server
      transceiver.setTimeout(1000);
      int limit = 0;
      packet = null;
      while(limit<60) try
      {
        packet = transceiver.receive();
        break;
      }
      catch(Exception e) {limit++;}
      transceiver.setTimeout(0);
      if(packet == null) 
      {
        System.out.println("waiting for server: Timeout.");
        return false;
      }
               
      if(packet.packetType == Packet.INIT)
      {
        init = (InitData) packet.data;
        return true;
      }
      else
      {
        System.out.println("Error: Packet type wrong. Can not INIT:-(");
        return false;
      }
    }
    catch(Exception e)
    {
      System.out.println("Error during start up: " + e);
      return false;
    }

  }  

  // an endless loop of observing and reacting.
  private void react() throws IOException
  {
    while(true)
    {
      sensing(transceiver.receive());
      if(IHaveBall) shootGoal();
      else chaseBall();
    }
  }      

  private void sensing(Packet info)
  {
    IHaveBall = false;
    // process the info
    if(info.packetType == Packet.SEE)
    {
      see = (SeeData)info.data;
      // Do I have the ball?
      if(see.ball.controllerType == see.player.side
         && see.ball.controllerId == see.player.id) IHaveBall = true;
    }
  }
              
  private void chaseBall() throws IOException
  {
    double force;
    if(see.player.position.distance(see.ball.position) >= 10) force = 100;
    else force = 50;

    DriveData driver = new DriveData(see.player.position.direction(see.ball.position), force);
    packet = new Packet(Packet.DRIVE, driver, address, port);
    transceiver.send(packet);
  }  

  private void shootGoal() throws IOException
  {
    Vector2d goal = null;

    if(see.player.side == 'l')
      goal = new Vector2d(50, 0);
    else goal = new Vector2d(-50, 0);

    double dir = see.player.position.direction(goal);
             
    KickData kicker = new KickData(dir, 100);
    packet = new Packet(Packet.KICK, kicker, address, port);
    transceiver.send(packet);
  }    
             
  public static void main(String argv[]) throws IOException
  {
    try
    {                                       
      // First look for parameters
      for( int c = 0 ; c < argv.length ; c += 2 )
      {
        if( argv[c].compareTo("-h") == 0 )
        {
          host = argv[c+1];
        }
        else if( argv[c].compareTo("-p") == 0 )
        {
          port = Integer.parseInt(argv[c+1]);
        }
        else if( argv[c].compareTo("-s") == 0 )
        {
          side = Integer.parseInt(argv[c+1]);
        }
        else
        {
           throw new Exception();
        }
      }
    }
    catch(Exception e)
    {
      System.err.println("");
      System.err.println("USAGE: AI [-parameter value]");
      System.err.println("");
      System.err.println("Parameters              value              default");
      System.err.println("--------------------------------------------------");
      System.err.println("h                      host_name         localhost");
      System.err.println("p                     port_number             7777");
      System.err.println("s         the side that the AI wants to join     0");     
      System.err.println("");
      System.err.println("Example:");
      System.err.println("AI -h lcivs2 -p 7777");
      System.err.println("or");
      System.err.println("AI -s 1");
      return;
    }

    AI ai = new AI();

    if(ai.init()) ai.react();

  }      
}