/******************************************************************************
 * Group4PlayerA4.java                                                        *
 * Adam M. Rosenzweig                                                         *
 * 11.24.03                                                                   *
 * This is a revised and upgraded version of the Group4PlayerA2 player.  It   *
 * uses the same basic concept - a checkerboard-style pattern that prevents   *
 * overpopulation.  The refinement is that its thresholds for starvation      *
 * behavior and willingness to reproduce are based on the available statistics*
 * M, u and v.                                                                *
 *****************************************************************************/

package Organisms2.g4;

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

public class Group4PlayerA4 implements IFCPlayer {

    private Organisms2 theWorld;
    private Random randomGenerator;
    private double REPRO_THRESHOLD;
    private double STARVE_THRESHOLD;
    private double MOVE_NONE;
    private double MOVE_ONE;
    private int state;
    
    /* The function called when the organism is born. */
    public void register (Organisms2 __amoeba, int key) {

	theWorld = __amoeba;
	randomGenerator = new Random ();
	
	/* Determine our thresholds */
	STARVE_THRESHOLD = ((double) theWorld.u () / (double) (theWorld.M ()))*
	    (1.0 + 2.0 * (double) theWorld.v () / (double) theWorld.u ());
	REPRO_THRESHOLD = 2 * STARVE_THRESHOLD + (double) theWorld.u () /
	    (double) theWorld.M ();
	MOVE_NONE = 0.005 * (double) theWorld.v () / (double) theWorld.u ();
	MOVE_ONE = 0.1 - MOVE_NONE;

	state = randomGenerator.nextInt (256);

	/*if (key == -1) {
	    System.out.println ("Starvation at " + STARVE_THRESHOLD);
	    System.out.println ("Reproduction at " + REPRO_THRESHOLD);
	    System.out.println ("Will move with one:  " + MOVE_ONE);
	    System.out.println ("Will move with none:  " + MOVE_NONE);
	    }*/
	
    }

    public String name () throws Exception {
	return "Tequila Kasparov";
    }

    public Color color () throws Exception {
	return new Color (0.9f, 0.85f, 0.2f);
    }

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

    public int externalState () throws Exception {
	return state;
    }

    public Move move (boolean [] foodPresent, int [] enemyPresent, 
		      int foodLeft, int energyLeft) throws Exception {

	int dir;
	boolean repro;
	boolean hungry;
	int enemyCount;
	int foodCount;

	/* Determine repro, enemyCount, foodCount */
	foodCount = 0;
	enemyCount = 0;
	repro = false;
	hungry = false;
	if (foodPresent [_CSTAYPUT]) { foodCount += 1; }
	if (foodPresent [_CNORTH]) { foodCount += 1; }
	if (foodPresent [_CSOUTH]) { foodCount += 1; }
	if (foodPresent [_CWEST]) { foodCount += 1; }
	if (foodPresent [_CEAST]) { foodCount += 1; }
	if (enemyPresent [_CNORTH] > -1) { enemyCount += 1; }
	if (enemyPresent [_CSOUTH] > -1) { enemyCount += 1; }
	if (enemyPresent [_CWEST] > -1) { enemyCount += 1; }
	if (enemyPresent [_CEAST] > -1) { enemyCount += 1; }
	if ((energyLeft > REPRO_THRESHOLD * theWorld.M ()) &&
	    (randomGenerator.nextInt () <= foodCount)) {
	    repro = true; 
	}
	if (energyLeft <= theWorld.M () - theWorld.u ()) { hungry = true; }
	/* Now modify foodCount to remove the tiles that have organisms on
	   them. */
	if (foodPresent [_CSTAYPUT]) { foodCount -= 1; }
	if (foodPresent [_CNORTH] && (enemyPresent [_CNORTH] > -1)) {
	    foodCount -= 1;
	}
	if (foodPresent [_CSOUTH] && (enemyPresent [_CSOUTH] > -1)) {
	    foodCount -= 1;
	}
	if (foodPresent [_CEAST] && (enemyPresent [_CEAST] > -1)) {
	    foodCount -= 1;
	}
	if (foodPresent [_CWEST] && (enemyPresent [_CWEST] > -1)) {
	    foodCount -= 1;
	}

	/* Are we starving? */
	if (energyLeft <= STARVE_THRESHOLD * theWorld.M ()) {
	    if (foodPresent [_CSTAYPUT]) { return new Move (_CSTAYPUT); }
	    dir = randomGenerator.nextInt (4) + 1;
	    if (foodPresent [dir]) { return new Move (dir); }
	    dir += 1;  if (dir > 4) { dir -= 4; }
	    if (foodPresent [dir]) { return new Move (dir); }
	    dir += 1;  if (dir > 4) { dir -= 4; }
	    if (foodPresent [dir]) { return new Move (dir); }
	    dir += 1;  if (dir > 4) { dir -= 4; }
	    if (foodPresent [dir]) { return new Move (dir); }
	}

	/* Am I not hungry but sitting on food?  We don't want that - it
	   keeps food from multiplying. */
	if (!hungry && foodPresent [_CSTAYPUT]) {
	    dir = randomGenerator.nextInt (4) + 1;
	    if (!foodPresent [dir] && (enemyPresent [dir] < 0)) {
		return new Move (dir);
	    }
	    dir += 1;  if (dir > 4) { dir -= 4; }
	    if (!foodPresent [dir] && (enemyPresent [dir] < 0)) {
		return new Move (dir);
	    }
	    dir += 1;  if (dir > 4) { dir -= 4; }
	    if (!foodPresent [dir] && (enemyPresent [dir] < 0)) {
		return new Move (dir);
	    }
	    dir += 1;  if (dir > 4) { dir -= 4; }
	    if (!foodPresent [dir] && (enemyPresent [dir] < 0)) {
		return new Move (dir);
	    }
	}

	/* Am I surrounded?  If so, not much I can do  */
	if (enemyCount == 4) { 
	    /* Spoof someone's state */
	    dir = randomGenerator.nextInt (4) + 1;
	    state = enemyPresent [dir];
	    return new Move (_CSTAYPUT); 
	}

	/* Are there 3 organisms next to me? */
	if (enemyCount == 3) {
	    /* Spoof someone's state */
	    dir = randomGenerator.nextInt (4) + 1;
	    if (enemyPresent [dir] > -1) {
		state = enemyPresent [dir];
	    }
	    else {
		dir += 1; if (dir > 4) { dir -= 4; }
		state = enemyPresent [dir];
	    }
	    dir = randomGenerator.nextInt (4) + 1;
	    while (enemyPresent [dir] > -1) {
		dir += 1; if (dir > 4) {dir -= 4; }
	    }
	    return new Move (dir);
	}

	/* Are there 2 organisms next to me? */
	if (enemyCount == 2) {
	    /* Spoof someone else's state */
	    dir = randomGenerator.nextInt (4) + 1;
	    while (enemyPresent [dir] == -1) {
		dir += 1; if (dir > 4) { dir -= 4; }
	    }
	    state = enemyPresent [dir];
	    dir = randomGenerator.nextInt (4) + 1;
	    while (enemyPresent [dir] > -1) {
		dir += 1; if (dir > 4) {dir -= 4; }
	    }
	    return new Move (dir);
	}

	/* Is there only 1 organism next to me? */
	if (enemyCount == 1) {
	    /* Spoof his state */
	    dir = randomGenerator.nextInt (4) + 1;
	    while (enemyPresent [dir] == -1) {
		dir += 1; if (dir > 4) { dir -= 4; }
	    }
	    state = enemyPresent [dir];
	    /* Pick a direction */
	    dir = randomGenerator.nextInt (4) + 1;
	    while (enemyPresent [dir] > -1) {
		dir += 1; if (dir > 4) { dir -= 4; }
	    }
	    if ((hungry || repro) && (foodCount > 0)) {
		while (!foodPresent [dir] || (enemyPresent [dir] > -1)) {
		    dir += 1; if (dir > 4) { dir -= 4; }
		}
	    }
	    if (repro) {
		return new Move (_CREPRODUCE, dir, 37);
	    }
	    if ((hungry && foodPresent [dir]) || 
		(randomGenerator.nextDouble () <= MOVE_ONE)) {
		return new Move (dir);
	    }
	    return new Move (_CSTAYPUT);
	}

	/* I guess I'm alone */
	/* Pick a random state to export */
	state = randomGenerator.nextInt (256);
	dir = randomGenerator.nextInt (4) + 1;
	if ((hungry || repro) && (foodCount > 0)) {
	    while (!foodPresent [dir]) {
		dir += 1; if (dir > 4) { dir -= 4; }
	    }
	}
	if (repro) {
	    return new Move (_CREPRODUCE, dir, 37);
	}
	if ((hungry && foodPresent [dir]) ||
	    (randomGenerator.nextDouble () <= MOVE_NONE)) {
	    return new Move (dir);
	}
	return new Move (_CSTAYPUT);

    }

}
