/* Group 2
 *
 * Modified from OldGroup3Player300, used some code from Group7Player6
 */

package Rectangles;

import ui.*;
import java.util.*;
import java.io.*;
import java.awt.Color;

public final class Group6Player2f implements IFCPlayer {
    // Global vars
    // Constants for game engine operation
    final Color  _CCOLOR = new Color(1.0f, 0.5f, 1.0f);  // purple color
    final boolean DEBUG = false;                         // for surpressing debugging output
    final boolean DEBUG2 = false;                        // more of the same
    final boolean DEBUG3 = false;                         // ... and some more.
    // Constants for player operation
    static final int TOPRIGHT = 0;            // Start at the top right corner
    static final int TOPLEFT = 1;             // Start at the top left corner
    static final int BOTRIGHT = 2;            // Start at the bottom right corner
    static final int BOTLEFT = 3;             // Start at the bottom left corner
    static final int LOW = 4;       // what's a "low" number of robots?
    boolean doneRect = false;
    int numRounds = 0;
    private Robot [] _robots;
    String name;                   // name variable
    Rectangles _rect;              // game variable
    static Random _random;         // Mostly used in version 0.1
    OldG3Point[] positions;
    char [] currentDirection;       //From Group7Player6
    char[] directions;             // for remembering what directions to move in
    char vertTendency;             // remember which vertical direction we're moving in
    boolean endMarch = false;      // Know when to turn around
    int numVertical;    // remember how many consec. moves were vertical
    int numRobots;
    int size;           // game board size
    int cornerPicked;   // What corner do we start at?
    int numPlayers;     // How many players are in the game?

    // Methods

    // Register the player with the game engine, and initialize local vars
    public Robot[] register(Rectangles __rectangles) throws Exception {
                _rect=__rectangles;
                numRobots = _rect.numRobots();
	        currentDirection = new char [numRobots];
		Robot[] returnVals;
		numVertical = 0;

		// Initialize the randomizer - but ONLY if it's necessary!
		if (_random  == null) {
		  _random = new Random();
		}

		// initialize everything else
		numPlayers = _rect.numPlayers();

		size = _rect.size();
		returnVals = new Robot[numRobots];
		directions = new char[numRobots];
		positions = new OldG3Point[numRobots];

                cornerPicked = _random.nextInt(4);
		  if (numRobots <= LOW) {
		    returnVals = strategy1_init(cornerPicked);
		    name = "Bite and Fight";  // renaming the player
		  }
		// Otherwise, use the traditional army algorithm
		  else {
		    returnVals = strategy2_init(cornerPicked);
		    name = "Window Washer";      // again, renaming
		  }
                return returnVals;
    }//end register

    // Strategy_init to use for few robots
    // This uses a specific algorithm to systematically place the robots
    // together in corners.
private Robot[] strategy1_init (int corner) throws Exception {
		  _robots = new Robot[numRobots];
		  int rectborder = size/4;
		  if (numRobots == 1)
			_robots[0] = new Robot(size/2, size/2);
		  else {
			if (corner == TOPLEFT) {
			  _robots[0] = new Robot(0,0);
			  _robots[1] = new Robot(rectborder, rectborder);
			}
			else if (corner == TOPRIGHT) {
			  _robots[0] = new Robot(size-(rectborder-1), 0);
			  _robots[1] = new Robot(size-1, rectborder);
			}
			else if (corner == BOTRIGHT) {
			  _robots[0] = new Robot(size-(rectborder-1), size-(rectborder-1));
			  _robots[1] = new Robot(size-1, size-1);
			}
			else if (corner == BOTLEFT) {
			  _robots[0] = new Robot(0, size-(rectborder-1));
			  _robots[1] = new Robot(rectborder, size-1);
			}
			if (numRobots > 2) {
			  if (corner == TOPLEFT)
				_robots[2] = new Robot(rectborder, 0);
			  if (corner == TOPRIGHT)
				_robots[2] = new Robot(size-1, 0);
			  if (corner == BOTRIGHT)
				_robots[2] = new Robot(size-1, size-(rectborder-1));
			  if (corner == BOTLEFT)
				_robots[2] = new Robot(rectborder, size-(rectborder-1));
			}
			if (numRobots > 3) {
			  if (corner == TOPLEFT)
				_robots[3] = new Robot(0, rectborder);
			  if (corner == TOPRIGHT)
				_robots[3] = new Robot(size-(rectborder-1), rectborder);
			  if (corner == BOTRIGHT)
				_robots[3] = new Robot(size-(rectborder-1), size-1);
			  if (corner == BOTLEFT)
				_robots[3] = new Robot(0, size-1);
			}
		  }
		  return _robots;
}//end strategy1_init

    // Strategy for a moderate number of robots
    // AKA: The "Army" algorithm
    private Robot[] strategy2_init(int corner) throws Exception {
			Robot[] returns = new Robot[numRobots];

			// The idea: Line up the robots, let them march together
			// As they march, a continuous rectangle is formed
			// If the rectangle is broken, a new one is easily formed in two moves!

			if (corner == TOPLEFT) {
				vertTendency = _CSOUTH;
				for (int i = 0; i < numRobots; i++) {
				returns[i] = new Robot(0, i);  // the domination starts in the corner!
				directions[i] = _CEAST;
				positions[i] = new OldG3Point(0, i);
				}
			}
			else if (corner == TOPRIGHT) {
				vertTendency = _CSOUTH;
				for (int i = 0; i < numRobots; i++) {
				returns[i] = new Robot(size - 1, i);
				directions[i] = _CWEST;
				positions[i] = new OldG3Point(size - 1, i);
				}
			}
			else if (corner == BOTLEFT) {
				vertTendency = _CNORTH;
				for (int i = 0; i < numRobots; i++) {
				returns[i] = new Robot(0, (size - (numRobots - i)));
				directions[i] = _CEAST;
				positions[i] = new OldG3Point(0, size - (numRobots - i));
				}
			}
			else {   // corner == BOT_RIGHT
				vertTendency = _CNORTH;
				for (int i = 0; i < numRobots; i++) {
				returns[i] = new Robot(size - 1, size - (numRobots - i));
				directions[i] = _CWEST;
				positions[i] = new OldG3Point(size - 1, size - (numRobots - i));
				}
			}
			return returns;
    }//end strat init2

    // returns a 90 degree move right
    private char move90Right(char direction) {
			if (direction == _CEAST)
				return _CSOUTH;
			else if (direction == _CSOUTH)
				return _CWEST;
			else if (direction == _CWEST)
				return _CNORTH;
			else return _CEAST;
    }

    // returns a 90 degree move left
    private char move90Left(char direction) {
			if (direction == _CEAST)
				return _CNORTH;
			else if (direction == _CNORTH)
				return _CWEST;
			else if (direction == _CWEST)
				return _CSOUTH;
			else return _CEAST;
    }

    // returns a 180 degree turn
    private char move180(char direction) {
			if (direction == _CEAST)
				return _CWEST;
			else if (direction == _CWEST)
				return _CEAST;
			else if (direction == _CNORTH)
				return _CSOUTH;
			else return _CNORTH;
    }

    //  Moving strategy for strategy1
    //  Strategy is as follows:
    //      For 1 robot: Starting near bottom right corner, make a series of n x n squares
    //                   by moving first all left, then all right, then straight, etc.
    //      For 2 robots: Start on opposite corners, and make criss-crosses along board.
    //      For 3 robots: Same as 2 robot strategy, but more ambitious...
    //                    It will send a third robot to try and secure the bottom 1/3
    //                    portion of the board (for x = 2, it will get the bottom 1/2)
    //      For 4 robots: Same as 3, but a fourth robot will try to get the middle 1/3.

		//andy
	private char[] strategy1() throws Exception {

	if (DEBUG)
	    System.out.println("Entering strategy 1");
	char[] returns = new char[numRobots];

	switch (numRobots) {

		case 1:
				//CHASE
				//returns[0] = _CNORTH;
                                returns = chaser(returns);
		break;

		case 4:
			// 4 robot code goes here

			if (numRounds < size/4 ) {
					returns[0] = _CEAST;
					returns[1] = _CWEST;
					returns[2] = _CSOUTH;
					returns[3] = _CNORTH;
			}
			if (numRounds >= size/4 ) {
				doneRect = true;
			}
			break;

		case 3:
			if (numRounds < size/2)
			{
					if (numRounds < size/4 ) {
						returns[0] = _CEAST;
						returns[1] = _CWEST;
						returns[2] = _CSOUTH;

					}
					else {
						if (numRounds < size/2) {
							returns[0] = _CSOUTH;
							returns[1] = _CNORTH;
							returns[2] = _CWEST;
						}
					}
			}
			if (numRounds == size/2 ) {
				doneRect = true;
			}
			break;

		case 2:

			if (numRounds < size/2)
			{
					if (numRounds < size/4 ) {
						returns[0] = _CEAST;
						returns[1] = _CWEST;

					}
					else {
						 if (numRounds < size/2) {
							returns[0] = _CSOUTH;
							returns[1] = _CNORTH;
						 }
					}
			}
			if (numRounds == size/2 ) {
				doneRect = true;
			}
			break;
	}//end switch



	//first rect is made doing this now
	//shin
	if (doneRect) {

          returns = chaser(returns);
        }
        return returns;

      }


    // Here it is: the traditional Army strategy
    // After you've lined up the robots in a corner, march them to the other side,
    // then move the line up (or down), repeat in the other direction, et. al.
    private char[] strategy2() throws Exception {
	if (DEBUG) {
	    System.out.println("Entering strategy 2");
	    	}
	char[] returns = directions;
	if (DEBUG)
	    System.out.println("returns array now of length " + returns.length);
	final char curDirection = directions[0];
	switch (curDirection) {
	case _CEAST:
	    if (DEBUG)

	    // Here, keep going east until we hit the end...
	    // ...then move the whole line south/north (if we can), and move back west
	    if (positions[0].x == size - 1) {
		if (DEBUG)

		if (vertTendency == _CSOUTH) {
		    if ((positions[numRobots - 1].y != size - 1) && (numVertical != numRobots)) {
			numVertical++;
			for (int i = 0; i < numRobots; i++) {
			    if (DEBUG)

			    returns[i] = _CSOUTH;
			    positions[i].y++;
			    directions[i] = _CSOUTH;
			}
		    }
		    else if ((positions[numRobots - 1].y != size - 1) &&
			     (numVertical == numRobots)) {
			// OK, move the robots west now
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CWEST;
			    positions[i].x--;
			    directions[i] = _CWEST;
			}
		    }
		    else if (positions[numRobots - 1].y == size - 1) {
			// OK, we're at the corner now.
			if (DEBUG)

			vertTendency = _CNORTH;
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CWEST;
			    positions[i].x--;
			    directions[i] = _CWEST;
			}
		    }
		}
		else {  // vertTendency is north
		    if (DEBUG)

		    if ((positions[0].y != 0) && (numVertical != numRobots)) {
			numVertical++;
			for (int i = 0; i < numRobots; i++) {
			    if (DEBUG)

			    returns[i] = _CNORTH;
			    positions[i].y--;
			    directions[i] = _CNORTH;
			}
		    }
		    else if ((positions[0].y != 0) && (numVertical == numRobots)) {
			// OK, move the robots west now
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CWEST;
			    positions[i].x--;
			    directions[i] = _CWEST;
			}
		    }
		    else if (positions[0].y == 0) {
			// OK, we're at the corner now. ABOUT FACE!
			if (DEBUG)

			endMarch = true;
			vertTendency = _CSOUTH;
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CWEST;
			    positions[i].x--;
			    directions[i] = _CWEST;
			}
		    }
		}
	    }
	    else {
		returns = directions;  // not at right wall; move east
		if (DEBUG)

		for (int i = 0; i < numRobots; i++) {
		    positions[i].x++;
		}
	    }
	    break;

	case _CWEST:
	    if (DEBUG)

	    // Here, keep going west until we hit the end...
	    // ...then move the whole line south/north (if we can), and move back west
	    if (positions[0].x == 0) {
		if (DEBUG)

		if (vertTendency == _CSOUTH) {
		    if ((positions[numRobots - 1].y != size - 1) && (numVertical != numRobots)) {
			numVertical++;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CSOUTH;
			    positions[i].y++;
			    directions[i] = _CSOUTH;
			}
		    }
		    else if ((positions[numRobots - 1].y != size - 1) &&
			     (numVertical == numRobots)) {
			// OK, move the robots east now
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CEAST;
			    positions[i].x++;
			    directions[i] = _CEAST;
			}
		    }
		    else if (positions[numRobots - 1].y == size - 1) {
			// OK, we're at the corner now.
			vertTendency = _CNORTH;
			if (DEBUG)

			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CEAST;
			    positions[i].x++;
			    directions[i] = _CEAST;
			}
		    }
		}
		else {  // vertTendency is north
		    if ((positions[0].y != 0) && (numVertical != numRobots)) {
			numVertical++;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CNORTH;
			    positions[i].y--;
			    directions[i] = _CNORTH;
			}
		    }
		    else if ((positions[0].y != 0) && (numVertical == numRobots)) {
			// OK, move the robots east now
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CEAST;
			    positions[i].x++;
			    directions[i] = _CEAST;
			}
		    }
		    else if (positions[0].y == 0) {
			// OK, we're at the corner now. ABOUT FACE!
			if (DEBUG)

			vertTendency = _CSOUTH;
			numVertical = 0;
			for (int i = 0; i < numRobots; i++) {
			    returns[i] = _CEAST;
			    positions[i].x++;
			    directions[i] = _CEAST;
			}
		    }
		}
	    }
	    else {
		returns = directions;  // not at right wall; move west
		if (DEBUG)

		for (int i = 0; i < numRobots; i++) {
		    positions[i].x--;
		}
	    }
	    break;

	case _CNORTH:
	    if (DEBUG)

	    // If in a corner, move away from it...
	    // otherwise, keep going.
	    if ((positions[0].y != 0) && (numVertical != numRobots)) {
		vertTendency = _CNORTH;
		numVertical++;
		for (int i = 0; i < numRobots; i++) {
		    returns[i] = _CNORTH;
		    directions[i] = _CNORTH;
		    positions[i].y--;
		}
	    }
	    else if ((positions[0].y != 0) && (numVertical == numRobots)) {
		// OK, now move the army away
		if (positions[0].x == 0) {  // on left wall
		    numVertical = 0;
		    vertTendency = _CNORTH;
		    for (int l = 0; l < numRobots; l++) {
			returns[l] = _CEAST;
			directions[l] = _CEAST;
			positions[l].x++;
		    }
		}
		else {  // on right wall
		    vertTendency = _CNORTH;
		    numVertical = 0;
		    for (int m = 0; m < numRobots; m++) {
			returns[m] = _CWEST;
			directions[m] = _CWEST;
			positions[m].x--;
		    }
		}
	    }
	    else if (positions[0].x == 0) {
		if (DEBUG)

		numVertical = 0;
		vertTendency = _CSOUTH;
		for (int j = 0; j < numRobots; j++) {
		    returns[j] = _CEAST;
		    directions[j] = _CEAST;
		    positions[j].x++;
		}
	    }
	    else {
		numVertical = 0;
		vertTendency = _CSOUTH;
		for (int k = 0; k < numRobots; k++) {
		    returns[k] = _CWEST;
		    directions[k] = _CWEST;
		    positions[k].x--;
		}
	    }
	    break;

	case _CSOUTH:
	    if (DEBUG)

	    // If in a corner, move away from it...
	    // otherwise, keep going.
	    if ((positions[numRobots - 1].y != size - 1) && (numVertical != numRobots)) {
		vertTendency = _CSOUTH;
		numVertical++;
		for (int i = 0; i < numRobots; i++) {
		    returns[i] = _CSOUTH;
		    directions[i] = _CSOUTH;
		    positions[i].y++;
		}
	    }
	    else if ((positions[numRobots - 1].y != size - 1) && (numVertical == numRobots)) {
		// OK, now move the army away
		if (positions[0].x == 0) {  // on left wall
		    numVertical = 0;
		    vertTendency = _CSOUTH;
		    for (int l = 0; l < numRobots; l++) {
			returns[l] = _CEAST;
			directions[l] = _CEAST;
			positions[l].x++;
		    }
		}
		else {  // on right wall
		    vertTendency = _CSOUTH;
		    numVertical = 0;
		    for (int m = 0; m < numRobots; m++) {
			returns[m] = _CWEST;
			directions[m] = _CWEST;
			positions[m].x--;
		    }
		}
	    }
	    else if (positions[0].x == 0) {
		if (DEBUG)

		vertTendency = _CNORTH;
		numVertical = 0;
		for (int j = 0; j < numRobots; j++) {
		    returns[j] = _CEAST;
		    directions[j] = _CEAST;
		    positions[j].x++;
		}
	    }
	    else {
		numVertical = 0;
		vertTendency = _CNORTH;
		for (int k = 0; k < numRobots; k++) {
		    returns[k] = _CWEST;
		    directions[k] = _CWEST;
		    positions[k].x--;
		}
	    }
	    break;
	default:
	    /* Not reached! */
	    break;
	}
    	return returns;
    }

    //return the oppDir
    public char oppDir(char dir)
    {
        switch ( dir )
        {
            case _CNORTH:
                return _CSOUTH;
            case _CSOUTH:
                return _CNORTH;
            case _CEAST:
                return _CWEST;
            case _CWEST:
                return _CEAST;
            default:
                return 'Y';
        }
    } //end oppDr

	//find direction
    public char findDirection( int xdist, int ydist ) throws Exception
    {
        char RET = 'Y';
        int axdist = (xdist >= 0) ? xdist : -xdist;
        int aydist = (ydist >= 0) ? ydist : -ydist;

        if ( axdist > aydist )
        {
            if ( xdist > 0 )
                RET = _CWEST;
            else if ( xdist < 0 )
                RET = _CEAST;
            else
                RET = 'Y';
        }
        else
        {
            if ( ydist > 0 )
                RET = _CNORTH;
            else if ( ydist < 0 )
                RET = _CSOUTH;
            else
                RET = 'Y';
        }

        return RET;
    }//end finddirection

	//just returns mostDistant
    public int[] findMostDistant( Robot[] playerA, Robot[] playerB ) throws Exception
    {
        if ( playerA.length != playerB.length )
        {
            throw new Exception("2 players do not have the same number of robots.");
        }

        int length = playerA.length;
        double[][] distances = new double[length][length];
        int[] mostDistant = new int[length];

        ArrayList enemyBots = new ArrayList(length);

        for ( int i = 0; i < length; i++ )
        {
            enemyBots.add( new Integer(i) );
            for ( int j = 0; j < length; j++ )
            {
                distances[i][j] = Math.abs( playerA[i].xpos() - playerB[j].xpos() ) + Math.abs( playerA[i].ypos() - playerB[j].ypos() );
            }
        }

        double[] values = new double[length];
        Iterator itr = null;
        double val = 0.0;
        int index = 0;
        for ( int i = 0; i < length; i++ )
        {
            itr = enemyBots.iterator();
            while ( itr.hasNext() )
            {
                index = ((Integer)(itr.next())).intValue();
                val = distances[i][index];
                if ( val > values[i] )
                {
                    mostDistant[i] = index;
                    values[i] = val;
                }
            }
            enemyBots.remove( new Integer( mostDistant[i] ) );
        }

        return mostDistant;
    } //end find most distant




    public char[] move() throws Exception {
        numRounds++;
        if (numRobots > LOW)
          return strategy2();
        else
          return strategy1();
    }
    //code taken from Group7Player6.java
    //simple chaser, finds closest, keeps on its heels
    private char[] chaser(char[] returns) throws Exception {
        int rounds = _rect.rounds();
	int players = _rect.numPlayers();
        Robot [][] allRobots = _rect.allRobots();
	int ourIndex = _rect.indexOf(this);

	Robot [] opponentRobots = new Robot[( numRobots * (_rect.numPlayers()-1)) ];
	int tempRobotCount = 0;

	/* Store all the other robots into one array
	 * from which we can choose close ones to chase
	 */
	for(int i=0;i<_rect.numPlayers();i++)
	    {
		if( i!=ourIndex)
		    {
			for( int j=0;j<numRobots;j++ )
			    opponentRobots[tempRobotCount++] = allRobots[i][j];
		    }
	    }

	int [][] distance = new int [numRobots][opponentRobots.length];
	for(int i=0;i<numRobots;i++)
	    for(int j=0;j< opponentRobots.length ;j++)
		{
		    Robot robot1 = _robots[i];
		    Robot robot2 = opponentRobots[j];
		    int tempDistance = Math.abs(robot1.xpos() - robot2.xpos()) + Math.abs(robot1.ypos() - robot2.ypos());
		    distance[i][j] = tempDistance;
		}
	//a robot is "used" once it has been matched up with one of
	//our chaser robots
	boolean [] ourUsed = new boolean [numRobots];
	boolean [] opponentUsed = new boolean [opponentRobots.length];
	int [] closestOpponent = new int [numRobots];

	for(int n=0;n<numRobots;n++) {
	    for(int i=0;i<numRobots;i++) {
		if(!ourUsed[i])  {
		    closestOpponent[i] = -1;
		    for(int j=0;j<opponentRobots.length;j++)  {
			if(!opponentUsed[j]) {
			    if(closestOpponent[i] == -1)
				closestOpponent[i] = j;
			    else
				if(distance[i][j] < distance[i][closestOpponent[i]])
				    closestOpponent[i] = j;
			}
		    }
		}
	    }

	    int index1 = -1;
	    int index2 = -1;
	    int smallestDistance = -1;
	    for(int i=0;i<numRobots;i++)
		{
		    if(!ourUsed[i])
			{
			    if(smallestDistance == -1)
				{
				    smallestDistance = distance[i][closestOpponent[i]];
				    index1 = i;
				    index2 = closestOpponent[i];
				}
			    else if(distance[i][closestOpponent[i]] < smallestDistance)
				{
				    smallestDistance = distance[i][closestOpponent[i]];
				    index1 = i;
				    index2 = closestOpponent[i];
				}
			}
		}

	    ourUsed[index1] = true;
	    opponentUsed[index2] = true;
	    Robot robot1 = _robots[index1];
	    Robot robot2 = opponentRobots[index2];

	    int dely = robot2.ypos() - robot1.ypos();
	    int delx = robot2.xpos() - robot1.xpos();
	    if((dely == 0) && (delx == 0))
		currentDirection[index1] = _CSTAY;
	    else if(Math.abs(dely) > Math.abs(delx))
		{
		    if(dely > 0)
			currentDirection[index1] = _CSOUTH;
		    else
			currentDirection[index1] = _CNORTH;
		}
	    else
		{
		    if(delx > 0)
			currentDirection[index1] = _CEAST;
		    else
			currentDirection[index1] = _CWEST;
		}
	}

	return currentDirection;
    }

    public String name() throws Exception {
        return name;
    }

    public Color color() throws Exception {
        return _CCOLOR;
    }

    public boolean interactive() throws Exception {
        return false;
    }
}
