//***********************************************************
//*
//* File:           Group7Player5.java
//* Author:         Prakash, Jason, Alexis
//* Contact:        jw2183@columbia.eud
//* Update:         9/18/2003
//*
//* Description:    Constructive Chaser
//*
//***********************************************************

package Rectangles;

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

public final class Group7Player8 implements IFCPlayer {

    Rectangles _rect;
    static final String _CNAME = "Discovery Channel";
    static final Color  _CCOLOR = new Color(1.0f * 0.9f, 0.8f * 0.9f, 0.3f * 0.9f);

    //Army constants and globals
    static final int TOPRIGHT = 0;
    static final int TOPLEFT = 1;
    static final int BOTRIGHT = 2;
    static final int BOTLEFT = 3;
    static final int _ARMY_SIZE = 3;
    private boolean _endMarch;
    private char _vertTendency;
    private int _numVertical;

    private int rectangleSize;
    private char [] currentDirection;
    private Robot [] robots;
    private boolean [] chasing;
    private int [][] chasee;
    
    public Robot[] register(Rectangles __rectangles) throws Exception
    {
	_rect = __rectangles;

	//initialize global variables to safe values
	robots = new Robot [_rect.numRobots()];
	currentDirection = new char [robots.length];
	chasing = new boolean [robots.length];
	chasee = new int [robots.length][2];
	
	for(int i=0;i<robots.length;i++)
	    {
		robots[i] = new Robot(0, 0);
		currentDirection[i] = _CSTAY;
		chasing[i] = false;
		chasee[i] = null;
	    }
	
	//doLadderInitialization();
	if(_rect.numPlayers() > _ARMY_SIZE)
	    doArmyInitialization();
	else
	    doGridInitialization();

        return robots;
    }
    
    public char[] move() throws Exception
    {
	//doLadderMovement();
	if(_rect.numPlayers() > _ARMY_SIZE)
	    {
		//pause one turn
		if(_rect.rounds() == 0)
		    {
			char [] tempMoves = new char [_rect.numRobots()];
			for(int i=0;i<tempMoves.length;i++)
			    tempMoves[i] = _CSTAY;
			return tempMoves;
		    }
		else
		    doArmyMovement();
	    }
	else
	    {
		doGridMovement();

		if(_rect.numPlayers() == 1)
		    doSinglePlayerChaserMovement();
		else
		    doChaserMovement();
	    }
		
        return currentDirection;
    }

    public void doGridInitialization()
    {
	try
	    {
		int numRobots = _rect.numRobots();
		int size = _rect.size();
		int xpos = 0, ypos = 0, i = 0, j = 0, k = 0, l = 0;

		rectangleSize = size / 6;
		
		boolean [] unused = new boolean [numRobots];

		for(i=0;i<numRobots / 2;i++)
		    {
			xpos = i * rectangleSize;
			if(xCoordWithinGrid(xpos))
			    robots[i] = new Robot(xpos, 0);
			else
			    unused[i] = true;
			currentDirection[i] = _CSOUTH;
		    }

		i = 0;
		for(j = numRobots / 2;j < numRobots;j++)
		    {
			ypos = (i++) * rectangleSize;
			if(yCoordWithinGrid(ypos))
			    robots[j] = new Robot(0, ypos);
			else
			    unused[j] = true;
			currentDirection[j] = _CEAST;
		    }

		k = 0;
		for(i=0;i<numRobots / 2;i++)
		    {
			if(unused[i])
			    {
				xpos = (k++) * (rectangleSize - 2);
				if(xCoordWithinGrid(xpos))
				    robots[i] = new Robot(xpos, size - 1);
				else
				    {
					chasing[i] = true;
					robots[i] = new Robot(size / 2, size / 2);
				    }
				unused[i] = false;
				currentDirection[i] = _CNORTH;
			    }
		    }

		i = 0;
		for(j = numRobots / 2; j < numRobots;j++)
		    {
			if(unused[j])
			    {
				ypos = (i++) * (rectangleSize - 2);
				if(yCoordWithinGrid(ypos))
				    robots[j] = new Robot(size - 1, ypos);
				else
				    {
					robots[j] = new Robot(size / 2, size / 2);
					chasing[j] = true;
				    }
				unused[j] = false;
				currentDirection[j] = _CWEST;
			    }
		    }
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public void doArmyInitialization()
    {
	try
	    {
		int corner = (int) (Math.random() * 4);
		int numRobots = _rect.numRobots();
		int size = _rect.size();

		if(corner == TOPLEFT)
		    {
			_vertTendency = _CSOUTH;
			for(int i=0;i<numRobots;i++)
			    {
				robots[i] = new Robot(0, i);
				currentDirection[i] = _CEAST;
			    }
		    }
		else if(corner == TOPRIGHT)
		    {
			_vertTendency = _CSOUTH;
			for(int i=0;i<numRobots;i++)
			    {
				robots[i] = new Robot(size - 1, i);
				currentDirection[i] = _CWEST;
			    }
		    }
		else if(corner == BOTLEFT)
		    {
			_vertTendency = _CNORTH;
			for(int i=0;i<numRobots;i++)
			    {
				robots[i] = new Robot(0, size - (numRobots - i));
				currentDirection[i] = _CEAST;
			    }
		    }
		else
		    {
			_vertTendency = _CNORTH;
			for(int i=0;i<numRobots;i++)
			    {
				robots[i] = new Robot(size - 1, size - (numRobots - i));
				currentDirection[i] = _CWEST;
			    }
		    }
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public void doLadderInitialization()
    {
	try
	    {
		int numRobots = _rect.numRobots();
		int size = _rect.size();
		int xpos=0,ypos=0;
		int tempxpos=0,tempypos=0;
	
		rectangleSize = size / 5;
	
		//int orgn = rectangleSize;
		int orgn = 0;
		int inter_diag_orgn = size;
		int [][] displacements = {{orgn, orgn}, {orgn, orgn}, {rectangleSize, orgn}, {orgn, rectangleSize}};
		int [][] inter_diag_displacements = {{size, size}, {size, size}, {size-rectangleSize, size}, {size,size-rectangleSize}};
		//char [] directions = {_CEAST, _CSOUTH, _CEAST, _CSOUTH};
		char [] directions = {_CWEST, _CNORTH, _CWEST, _CNORTH};
		char [] inter_diag_directions = {_CWEST,_CNORTH,_CWEST,_CNORTH};
		for (int i=0; i < numRobots; i++) 
		    {
			if( i>= numRobots/2 )
			    {
				//System.out.println("I is now ::"+i);
				i -= numRobots / 2;
				ypos = (i / 4) * rectangleSize; //--- use this for 2 parallel diagonals
				xpos = ((i/4)+1) * rectangleSize; //-- use this for 2 parallel diagonals
				//ypos = ((i / 4)+1) * rectangleSize; -- for intersectiong diagonals
				//xpos = ((i/4) * rectangleSize); -- for intersectiong diagonals
				//System.out.println("xpos ::"+xpos);
				//System.out.println("ypos ::"+ypos);
				tempxpos = xpos + displacements[i % 4][0]; //-- parallel
				tempypos = ypos + displacements[i % 4][1]; //-- parallel
				//tempxpos = Math.abs( xpos - inter_diag_displacements[i % 4][0] );
				//tempypos = Math.abs( ypos - inter_diag_displacements[i % 4][1] );
				//System.out.println("Disp x ::"+displacements[i%4][0]);
				//System.out.println("Disp y ::"+displacements[i%4][1]);
				currentDirection[i + numRobots / 2] = directions[i % 4]; //-- use this for parallel diagonals
				//currentDirection[i + numRobots / 2] = inter_diag_directions[i % 4];
				i += numRobots / 2;
			    }
			else
			    {
				xpos = (i / 4) * rectangleSize;
				ypos = ((i/4)+1) * rectangleSize;
				//System.out.println("xpos ::"+xpos);
				//System.out.println("ypos ::"+ypos);
				tempxpos = xpos + displacements[i % 4][0];
				tempypos = ypos + displacements[i % 4][1];
				//System.out.println("Disp x ::"+displacements[i%4][0]);
				//System.out.println("Disp y ::"+displacements[i%4][1]);
				currentDirection[i] = directions[i % 4];
			    }	
		
			try
			    {
				if( xCoordWithinGrid(tempxpos) == true && yCoordWithinGrid(tempypos) == true )
				    {
					//place in lower right hand corner
					robots[i] = new Robot(_rect.size() - 1 - tempxpos,_rect.size() - 1 - tempypos);
					//robots[i] = new Robot(tempxpos, tempypos);
					//System.out.println(tempxpos);
					//System.out.println(tempypos);
					//System.out.println("Placed robot::"+i);
				    }
				else
				    {
					//get this one to chase
					robots[i] = new Robot(size / 2, size / 2);
					chasing[i] = true;
					currentDirection[i] = _CSTAY;
				    }
			    }
			catch( Exception e)
			    {
			
			    }
		    }
	    }
	catch(Exception e)
	    {
		//System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public boolean xCoordWithinGrid(int x) throws Exception
    {
	if( x>=0 && x<= (_rect.size()-1) ) return true;
	return false;
    }
    
    public boolean yCoordWithinGrid( int y)throws Exception
    {
	if( y>=0 && y<= (_rect.size()-1 ) ) return true;
	return false;
    }

    public void doGridMovement()
    {
	try
	    {
		int rounds = _rect.rounds();
		char [] tempDirection = new char [currentDirection.length];
		for(int i=0;i<tempDirection.length;i++)
		    tempDirection[i] = currentDirection[i];
		doLadderMovement();
		if(rounds < _rect.size())
		    {
			for(int i=0;i<tempDirection.length;i++)
			    if(!chasing[i])
				currentDirection[i] = tempDirection[i];
		    }
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public void doArmyMovement()
    {
	try
	    {
		char curDirection = currentDirection[0];
		int size = _rect.size();
		int numRobots = _rect.numRobots();
		switch (curDirection) {
		case _CEAST:

		    /* Move east until either: 
		     * 1) hit the wall 
		     * 2) hit a section that is more than half black 
		     *  (from where our army hits to the end)
		     *
		     * then move the whole line south/north 
		     * (if we can), and move back west
		     */
		    if (robots[0].xpos() == size - 1 || tooMuchBlack()) {
			if (_vertTendency == _CSOUTH) {
			    if ((robots[numRobots - 1].ypos() != size - 1) && (_numVertical != numRobots)) {
				_numVertical++;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CSOUTH;
			    }
			    else if ((robots[numRobots - 1].ypos() != size - 1) &&
				     (_numVertical == numRobots)) {
				// OK, move the robots west now
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CWEST;
			    }
			    else if (robots[numRobots - 1].ypos() == size - 1) {
				// OK, we're at the corner now.
				_vertTendency = _CNORTH;
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CWEST;
			    }
			}
			else {  // _vertTendency is north
			    if ((robots[0].ypos() != 0) && (_numVertical != numRobots)) {
				_numVertical++;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CNORTH;
			    }
			    else if ((robots[0].ypos() != 0) && (_numVertical == numRobots)) {
				// OK, move the robots west now
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CWEST;
			    }
			    else if (robots[0].ypos() == 0) {
				// OK, we're at the corner now. ABOUT FACE!

				_endMarch = true;
				_vertTendency = _CSOUTH;
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CWEST;
			    }
			}
		    }
		    else {
			//continue in same direction
		    }
		    break;
	    
		case _CWEST: 
		    // Here, keep going west until we hit the end...
		    // ...then move the whole line south/north (if we can), and move back west
		    if (robots[0].xpos() == 0 || tooMuchBlack()) {
			if (_vertTendency == _CSOUTH) {
			    if ((robots[numRobots - 1].ypos() != size - 1) && (_numVertical != numRobots)) {
				_numVertical++;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CSOUTH;
			    }
			    else if ((robots[numRobots - 1].ypos() != size - 1) &&
				     (_numVertical == numRobots)) {
				// OK, move the robots east now
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CEAST;
			    }
			    else if (robots[numRobots - 1].ypos() == size - 1) {
				// OK, we're at the corner now.
				_vertTendency = _CNORTH;
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CEAST;
			    }
			}
			else {  // _vertTendency is north
			    if ((robots[0].ypos() != 0) && (_numVertical != numRobots)) {
				_numVertical++;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CNORTH;
			    }
			    else if ((robots[0].ypos() != 0) && (_numVertical == numRobots)) {
				// OK, move the robots east now
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CEAST;
			    }
			    else if (robots[0].ypos() == 0) {
				// OK, we're at the corner now. ABOUT FACE!
				_vertTendency = _CSOUTH;
				_numVertical = 0;
				for (int i = 0; i < numRobots; i++)
				    currentDirection[i] = _CEAST;
			    }
			}
		    }
		    else {
			//continue in same direction
		    }
		    break;
	    
		case _CNORTH:
		    // If in a corner, move away from it...
		    // otherwise, keep going.
		    if ((robots[0].ypos() != 0) && (_numVertical != numRobots)) {
			_vertTendency = _CNORTH;
			_numVertical++;
			for (int i = 0; i < numRobots; i++)
			    currentDirection[i] = _CNORTH;
		    }
		    else if ((robots[0].ypos() != 0) && (_numVertical == numRobots)) {
			// OK, now move the army away
			if (robots[0].xpos() == 0) {  // on left wall
			    _numVertical = 0;
			    _vertTendency = _CNORTH;
			    for (int l = 0; l < numRobots; l++)
				currentDirection[l] = _CEAST;
			}
			else {  // on right wall
			    _vertTendency = _CNORTH;
			    _numVertical = 0;
			    for (int m = 0; m < numRobots; m++)
				currentDirection[m] = _CWEST;
			}
		    }
		    else if (robots[0].xpos() == 0) {
			_numVertical = 0;
			_vertTendency = _CSOUTH;
			for (int j = 0; j < numRobots; j++) 
			    currentDirection[j] = _CEAST;
		    }
		    else {
			_numVertical = 0;
			_vertTendency = _CSOUTH;
			for (int k = 0; k < numRobots; k++)
			    currentDirection[k] = _CWEST;
		    }
		    break;
	    
		case _CSOUTH:
		    // If in a corner, move away from it...
		    // otherwise, keep going.
		    if ((robots[numRobots - 1].ypos() != size - 1) && (_numVertical != numRobots)) {
			_vertTendency = _CSOUTH;
			_numVertical++;
			for (int i = 0; i < numRobots; i++)
			    currentDirection[i] = _CSOUTH;
		    }
		    else if ((robots[numRobots - 1].ypos() != size - 1) && (_numVertical == numRobots)) {
			// OK, now move the army away
			if (robots[0].xpos() == 0) {  // on left wall
			    _numVertical = 0;
			    _vertTendency = _CSOUTH;
			    for (int l = 0; l < numRobots; l++)
				currentDirection[l] = _CEAST;
			}
			else {  // on right wall
			    _vertTendency = _CSOUTH;
			    _numVertical = 0;
			    for (int m = 0; m < numRobots; m++)
				currentDirection[m] = _CWEST;
			}
		    }
		    else if (robots[0].xpos() == 0) {
			_vertTendency = _CNORTH;
			_numVertical = 0;
			for (int j = 0; j < numRobots; j++) 
			    currentDirection[j] = _CEAST;
		    }
		    else {
			_numVertical = 0;
			_vertTendency = _CNORTH;
			for (int k = 0; k < numRobots; k++)
			    currentDirection[k] = _CWEST;
		    }
		    break;
		default: 
		    /* Not reached! */ 
		    break;
		}
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public boolean tooMuchBlack() throws Exception {
	try
	    {
		int ourIndex = _rect.indexOf(this);
		int numRobots = _rect.numRobots();
		int cnt=0, black=0, firstRow=0, start, totalFilled=0;
		boolean[][] filled = _rect.filled();
		int size = _rect.size();
		/****
		 * check for end game scenario -- always return false (which
		 * will allow the player to do default sweeping)
		 * if the board is more than half filled
		 ***/
		for (int i=0;i<size;i++) {
		    for (int j=0;j<size;j++) {
			if (filled[i][j]) {
			    totalFilled++;
			}
		    }
		}
		float f = ((float)totalFilled / (float)(size*size));
		if (f >= 0.5) {
		    return false;
		}
		/** end of check for end game scenario **/
		
		switch (currentDirection[0]) {
		case _CEAST:
		    //iterate through the rows, starting at where the
		    //army is horizontally
		    start = robots[0].xpos() + 1;
		    if (start < 0 || start > size - 1) break;
		    for (int i=start; i<size;i++) {
			//iterate through the cols, starting from where the army's
			//first man is vertically
			for (int j=robots[0].ypos();j<robots[_rect.numRobots()-1].ypos();j++) {
			    if (filled[i][j]) {
				if (i==start) {
				    firstRow++;
				}
				black++;
			    }
			    cnt++;
			}
		    }
		    //if the row directly to the west at least half open, 
		    //go west
		    if (firstRow < (numRobots / 2) ) {
			return false;
		    }
		    //if more than half of the rows to the west
		    //are filled, there's too much black
		    if (black >= (cnt / 2) ) {
			return true;
		    }
		    break;
		case _CWEST:
		    //iterate through the rows, starting at where the
		    //army is horizontally
		    start = robots[0].xpos() - 1;
		    if (start < 0) break;
		    for (int i=start;i>=0;i--) {
			//iterate through the cols, starting from where the army's
			//first man is vertically
			for (int j=robots[0].ypos();j<robots[_rect.numRobots()-1].ypos();j++) {
			    if (filled[i][j]) {
				if (i==start) {
				    firstRow++;
				}
				black++;
			    }
			    cnt++;
			}
		    }
		    //if the row directly to the west at least half open, 
		    //go west
		    if (firstRow < (numRobots / 2) ) {
			return false;
		    }
		    //if more than half of the rows to the west
		    //are filled, there's too much black
		    if (black >= (cnt / 2) ) {
			return true;
		    }
		    break;
		default:
		    break;
		}
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }

	return false;
    }

    public void doLadderMovement()
    {
	try
	    {
		int numRobots = _rect.numRobots();
		int rounds = _rect.rounds();
		boolean [][] filled = _rect.filled();
		int changeRounds = 2 * _rect.size();
		
		//do initial testing
		if(rounds > changeRounds)
		    {
			for(int i=0;i<numRobots;i++)
			    chasing[i] = true;
		    }

		for (int i=0; i < numRobots; i++)
		    {
			if(!chasing[i])
			    {
				if((rounds % rectangleSize == 0) && (rounds != 0))
				    {
					if(currentDirection[i] == _CEAST)
					    currentDirection[i] = _CSOUTH;
					else if(currentDirection[i] == _CSOUTH)
					    currentDirection[i] = _CEAST;
					else if(currentDirection[i] == _CWEST)
					    currentDirection[i] = _CNORTH;
					else if(currentDirection[i] == _CNORTH)
					    currentDirection[i] = _CWEST;
					
					//avoid redundancy
					if(rounds % (2 * rectangleSize) == 0)
					    {
						//define rectangle
						int x1, y1, x2, y2;
						if((currentDirection[i] == _CEAST) || (currentDirection[i] == _CSOUTH))
						    {
							x1 = robots[i].xpos();
							y1 = robots[i].ypos();
							x2 = Math.min(robots[i].xpos() + rectangleSize, _rect.size() - 1);
							y2 = Math.min(robots[i].ypos() + rectangleSize, _rect.size() - 1);
						    }
						else
						    {
							x2 = robots[i].xpos();
							y2 = robots[i].ypos();
							x1 = Math.max(robots[i].xpos() - rectangleSize, 0);
							y1 = Math.max(robots[i].ypos() - rectangleSize, 0);
						    }
						
						//check rectangle border for black
						for(int x=x1;x<=x2;x++)
						    {
							if(filled[x][y1])
							    chasing[i] = true;
							if(filled[x][y2])
							    chasing[i] = true;
						    }
						
						for(int y=y1;y<=y2;y++)
						    {
							if(filled[x1][y])
							    chasing[i] = true;
							if(filled[x2][y])
							    chasing[i] = true;
						    }
					    }
				    }
				
				if((currentDirection[i] == _CEAST) && (robots[i].xpos() == _rect.size() - 1))
				    currentDirection[i] = _CWEST;
				else if((currentDirection[i] == _CWEST) && (robots[i].xpos() == 0))
				    currentDirection[i] = _CEAST;
				else if((currentDirection[i] == _CNORTH) && (robots[i].ypos() == 0))
				    currentDirection[i] = _CSOUTH;
				else if((currentDirection[i] == _CSOUTH) && (robots[i].ypos() == _rect.size() - 1))
				    currentDirection[i] = _CNORTH;
			    }
		    }
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public void doChaserMovement()
    {
	try
	    {
		int numRobots = _rect.numRobots();

		//for each robot that is chasing, do chasing
		Robot [][] allRobots = _rect.allRobots();
		int ourIndex = _rect.indexOf(this);
		
		Robot [] opponentRobots = new Robot[( numRobots * (_rect.numPlayers()-1)) ];
		int [][] opponentRobotsIndices = new int [opponentRobots.length][2];
		boolean [] eliminate = new boolean [opponentRobots.length];
		boolean [] eliminate2 = new boolean [opponentRobots.length];
		int tempRobotCount = 0;
			
		MoveResult [] moveResults = _rect.history();
		char [][] pastMoves;
		double [] scores;
		int [][] colors;
		boolean [][] filled;

		if(moveResults.length == 0)
		    {
			pastMoves = null;
			scores = null;
			colors = null;
			filled = null;
		    }
		else
		    {
			pastMoves = moveResults[moveResults.length - 1].moves();
			scores = moveResults[moveResults.length - 1].scores();
			colors = _rect.colors();
			filled = _rect.filled();
		    }

		boolean weAreInFirstPlace = false;
		double maxScore = 0;
		if(scores != null)
		    {
			for(int i=0;i<_rect.numPlayers();i++)
			    if(scores[i] > maxScore)
				maxScore = scores[i];
			
			if(maxScore == scores[ourIndex])
			    weAreInFirstPlace = true;
		    }
			
		/* 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];
					opponentRobotsIndices[tempRobotCount - 1][0] = i;
					opponentRobotsIndices[tempRobotCount - 1][1] = j;
					if(pastMoves != null)
					    {
						if((pastMoves[i][j] == _CSTAY) || (pastMoves[i][j] == _CUNDEFINED))
						    eliminate[tempRobotCount - 1] = true;
						    
						if((scores[i] < scores[ourIndex]) || (scores[i] < maxScore))
						    eliminate2[tempRobotCount - 1] = true;
					    }
				    }
					
			    }
		    }
			
		//eliminate some robots
		ArrayList tempRobots = new ArrayList();
		ArrayList tempRobotsIndices = new ArrayList();
		for(int i=0;i<opponentRobots.length;i++)
		    {
			if(!eliminate[i] && !eliminate2[i])
			    {
				tempRobots.add(opponentRobots[i]);
				tempRobotsIndices.add(opponentRobotsIndices[i]);
			    }
			else if(eliminate2[i] && !eliminate[i] && weAreInFirstPlace)
			    {
				tempRobots.add(opponentRobots[i]);
				tempRobotsIndices.add(opponentRobotsIndices[i]);
			    }
		    }
			
		//add robots as needed
		boolean done = false;
		int index = 0;
		if(!weAreInFirstPlace)
		    while(!done)
			{
			    if(tempRobots.size() >= robots.length)
				done = true;
			    else
				{
				    if(eliminate2[index] && !eliminate[index])
					{
					    tempRobots.add(opponentRobots[index]);
					    tempRobotsIndices.add(opponentRobotsIndices[index]);
					}

				    index++;
				    if(index == opponentRobots.length)
					done = true;
				}
			}

		done = false;
		index = 0;
		while(!done)
		    {
			if(tempRobots.size() >= robots.length)
			    done = true;
			else
			    {
				if(eliminate[index])
				    {
					tempRobots.add(opponentRobots[index]);
					tempRobotsIndices.add(opponentRobotsIndices[index]);
				    }
				index++;
			    }
		    }
			
		//copy array
		opponentRobots = new Robot [tempRobots.size()];
		opponentRobotsIndices = new int [tempRobots.size()][2];
		for(int i=0;i<opponentRobots.length;i++)
		    {
			opponentRobots[i] = (Robot) tempRobots.get(i);
			opponentRobotsIndices[i] = (int []) tempRobotsIndices.get(i);
		    }
			
		//find out if any player is within one unit and start chasing
		for(int i=0;i<numRobots;i++)
		    for(int j=0;j<opponentRobots.length;j++)
			{
			    Robot robot1 = robots[i];
			    Robot robot2 = opponentRobots[j];
			    int delx = Math.abs(robot1.xpos() - robot2.xpos());
			    int dely = Math.abs(robot1.ypos() - robot2.ypos());
			    if((delx <= 1) && (dely <= 1))
				{
				    chasing[i] = true;
				}
			}
			
		//precalculate the distances
		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;
			}
			
		//initialize the used arrays
		boolean [] ourUsed = new boolean [numRobots];
		int numChasing = 0;
		for(int i=0;i<numRobots;i++)
		    {
			ourUsed[i] = !chasing[i];
			if(chasing[i])
			    numChasing++;
		    }
			
		boolean [] opponentUsed = new boolean [opponentRobots.length];
		int [] closestOpponent = new int [numRobots];
			
		for(int n=0;n<numChasing;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;
			//follow the same robot if still following
			for(int i=0;i<numRobots;i++)
			    {
				if(!ourUsed[i])
				    {
					if(chasee[i] != null)
					    {
						for(int j=0;j<opponentRobots.length;j++)
						    {
							if(!opponentUsed[j])
							    {
								int [] opponentRobotsIndex = opponentRobotsIndices[j];
								if((opponentRobotsIndex[0] == chasee[i][0]) && (opponentRobotsIndex[1] == chasee[i][1]))
								    {
									index1 = i;
									index2 = j;
								    }
							    }
						    }
					    }
				    }
			    }

			if(index1 == -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;
			    }

			if((Math.abs(dely) <= 1) && (Math.abs(delx) <= 1))
			    chasee[index1] = opponentRobotsIndices[index2];
			else
			    chasee[index1] = null;

			//move randomly if chasing a stalled player
			int [] tempIndices = opponentRobotsIndices[index2];
			if(pastMoves != null)
			    {
				if((pastMoves[tempIndices[0]][tempIndices[1]] == _CSTAY) && (!weAreInFirstPlace))
				    {
					int x = robot1.xpos();
					int y = robot1.ypos();
					char [] coordinates = new char [4];
					int coordinatesSize = 0;
					int [][] displacements = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
					char [] directions = {_CEAST, _CSOUTH, _CWEST, _CNORTH};
					for(int i=0;i<4;i++)
					    {
						int x2 = x + displacements[i][0];
						int y2 = y + displacements[i][1];
						if(onBoard(x2, y2))
						    if((colors[x2][y2] != ourIndex) && (!filled[x2][y2]) && ((x2 != robot2.xpos()) || (y2 != robot2.ypos())))
							coordinates[coordinatesSize++] = directions[i];
					    }
						
					if(coordinatesSize == 0)
					    currentDirection[index1] = _CDIRECTIONS[(int) (Math.random() * 4 + 1)];
					else
					    currentDirection[index1] = coordinates[(int) (Math.random() * coordinatesSize)];
				    }
			    }
		    }
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

    public boolean onBoard(int x, int y)
    {
	try
	    {
		if(x < 0)
		    return false;
		
		if(y < 0)
		    return false;
		
		if(x >= _rect.size())
		    return false;
		
		if(y >= _rect.size())
		    return false;

		return true;
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
		return false;
	    }
    }

    public void doSinglePlayerChaserMovement()
    {
	try
	    {
		int numRobots = _rect.numRobots();

		//cover border if only player
		for(int i=0;i<numRobots;i++)
		    if(chasing[i])
			{
			    if((currentDirection[i] == _CEAST) && (robots[i].xpos() == _rect.size() - 1))
				currentDirection[i] = _CSOUTH;
			    if((currentDirection[i] == _CSOUTH) && (robots[i].ypos() == _rect.size() - 1))
				currentDirection[i] = _CWEST;
			    if((currentDirection[i] == _CWEST) && (robots[i].xpos() == 0))
				currentDirection[i] = _CNORTH;
			    if((currentDirection[i] == _CNORTH) && (robots[i].ypos() == 0))
				currentDirection[i] = _CEAST;
			    if((currentDirection[i] == _CEAST) && (robots[i].xpos() == _rect.size() - 1))
				currentDirection[i] = _CSOUTH;
			}
	    }
	catch(Exception e)
	    {
		System.out.println("Error: " + e.getMessage());
		e.printStackTrace();
	    }
    }

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

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

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