Forward.java

The three forwards communicate with each other by sending their relative distances to the ball. Whichever Forward is closest chases after the ball; the others line up parallel to the ball.

Each Forward player keeps an estimate of the ball's velocity with respect to itself by noting the ball's relative location every 6 frames and subtracting from the old relative location. This is used to chase after the ball more accurately.

Once the Forward is in possesion of the ball, it attempts to dribble the ball into the center of the opponent's goal.

package Riddler.Flash;

import sockey.SoccerClient;
import java.awt.*;

public final class Forward extends SoccerClient {
    
    final int DRIBBLING=2;
    final int RECEIVING=3;
    final int SENDFWDS= 7;

    int state= RECEIVING;          // are we DRIBBLING or RECEIVING?
    int dist[]= new int[3];        // relative distances of the 3 forwards
    Point loc= new Point(0,0);     // scratch Point for general use
    int me;                        // ID of this player's position
    int closest;                   // ID of Forward closest to the ball
    int radius;                    // radius of the player
    int ballradius;                // radius of the ball
    Point oldball= new Point();    // where the ball was last time we looked
    Point ballvel= new Point();    // how fast ball is going (pix/sec)
    int balltime= 0;               // when to look at the ball again
    int maxvel= 10;                // maximum velocity of this Forward

    /**
     * Values you'd like to initialize for this player go here
     */
    public void init() {
        super.init();
        radius= getRadius();
        ballradius= getBallRadius();
    }
    
    /**
     * The only message we receive is the distance from the ball of the
     * forwards.  Save the info away in an array.
     */
    public void receiveMessage(int from, String msg, int a, int b, int c) {
        dist[from]= a;
    }
    
    /**
     * Move to the absolute field position (x,y) at full speed
     * (like wannabe, except not PID controller)
     */
    public void moveTo(int x, int y) {
        // -loc is where we are.  (x,y) is where we want to be.
        ping(ID_CENTER, loc, false);  
        loc.translate(x, y);
        cart2polar(loc, loc);
        accelerate(loc.y, 100);
    }

    public void regroup() {
        super.regroup();
        // Really all we're trying to do here is figure out how fast our
        // player can go.
        getVel(v);
        if (v.x*v.x+v.y*v.y >= maxvel*maxvel) {
            maxvel= (int)Math.sqrt(v.x*v.x+v.y*v.y)+1;
            debugMsg("maxvel is now: "+maxvel);
        }
    }
    
    
    public void step() {
        ping(ID_BALL, pt, true);
        int bang= pt.y;
        me= getPosition();
        // tell the other players how far away the ball is from me.
        sendMessage(SENDFWDS, null, pt.x, 0, 0);
        // which forward player is closest to the ball?
        closest= (dist[0]<dist[1]) ? ((dist[0]<dist[2]) ? 0 : 2) :
                                      ((dist[1]<dist[2]) ? 1 : 2);
        
        ping(ID_BALL, pt, false);

        // check for ball velocity: check every 6 frames (1/10 second)
        int frameno= getTime();
        if (frameno>balltime) {
            if (frameno-balltime>12) {
                // we've lost some time... reset everything
                ballvel.x= 0;
                ballvel.y= 0;
            } else {
                // find ball velocity:
                ballvel.x= (pt.x-oldball.x)*60/(frameno-(balltime-6));
                ballvel.y= (pt.y-oldball.y)*60/(frameno-(balltime-6));
            }
            oldball.x= pt.x;
            oldball.y= pt.y;
            balltime= frameno+6;
        }

        ping(ID_CENTER, loc, false);
        pt.x-= loc.x;
        pt.y-= loc.y;
        switch (state) {
            case RECEIVING: {
                // If we're the closest to the ball, go for the ball
                if (closest==me) {
                    // where will the ball be by the time we get there?
                    // time to get there is dist[me]/maxvel
                    moveTo(pt.x+ballvel.x*dist[me]/maxvel,
                           pt.y+ballvel.y*dist[me]/maxvel);
                } else {
                // otherwise, move parallel to the ball, along a
                // field longitude line.
                    if (me== ID_PCTR) {
                        moveTo(pt.x, 0);
                    } else if (me== ID_PFWDL) {
                        moveTo(pt.x, -size.height/3);
                    } else {
                        moveTo(pt.x, size.height/3);
                    }
                }
                // Set angle so that the ball would bounce off our face
                // into the center of the goal
                ping(ID_THEIR_GOAL, loc, true);
                // angle to goal is loc.y, angle to ball is bang.
                // Angle halfway between is loc.y+(bang-loc.y)/2
                int pointoff= anglesub(bang, loc.y);
                if (pointoff<-135 || pointoff>135) {
                    setAngGoal(bang+((pointoff<0)?30:-30));
                } else {
                    setAngGoal(loc.y+pointoff/2);
                }
                // if ball is really close (ready to kick), start dribbling.
                if (dist[me]<radius+ballradius && pointoff<50 && pointoff>-50) {
                    state= DRIBBLING;
                    debugMsg("I got it!");
                }
                break;
            }
            case DRIBBLING: {
                ping(ID_THEIR_GOAL, loc, true);
                // diff is relative angle to the ball: + is to left, - to right
                int diff= anglesub(bang, getAng());
                // we want to face the goal, but angle to dribble the ball
                // closer to the center of our face.
                int goal= loc.y-diff/3;
                // if we lost the ball (not kickable), we need to chase the ball
                if (dist[me]>radius+ballradius) {
                    // angle to kick the ball into the goal
                    diff= anglesub(bang, loc.y);
                    goal= loc.y+diff/2;
                    moveTo(pt.x, pt.y);
                } else {
                // othewise, dribble the ball into the goal
                    moveTo(size.width/2, 0);
                }
                setAngGoal(goal);
                // if ball is too far away, we've lost it.  Go back to receiving
                if (dist[me]>radius*2 || closest!=me) {
                    state= RECEIVING;
                    debugMsg("Chasing...");
                }
                break;
                
            }
        }
    }
    
}