package agent;
import constants.MovementConstants;
import constants.ResourceConstants;
import environment.Cell;
import environment.World;
import functions.EnvironmentFunction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import resource.Resource;
import resource.TraceResource;
/**
*
* @author marcocelesti
*/
public class Tracer extends Agent {
private List<Integer[]> directionList;
public Tracer(short progenitor, short id, short idWorld) {
super(progenitor, id, idWorld);
directionList = new ArrayList<Integer[]>();
}
public Tracer(World world, DNAparameters dnaParam, Cell cell, short id, short progenitor) {
super(world, dnaParam, cell, id, progenitor);
directionList = new ArrayList<Integer[]>();
}
protected void executeActions(String time) {
if (time.equals("minute")) {
if (getSpeedCounter() >= getDnaParams().getSpeed()) {
move();
// if (getBorder() % getDivisor() == 0 && isAlive()) {
// duplicate();
// }
setSpeedCounter(0);
} else {
setSpeedCounter(getSpeedCounter() + 1);
}
} else if (time.equals("hour")) {
} else if (time.equals("day")) {
}
}
private void move() {
setBorder((short) (getBorder() + 1));
switch (getParams().getMovement()) {
case (MovementConstants.RANDOM):
setLastDirection(getDirection());
float delta = 0.001f;
if (Math.random() < getThrshld()) {
setDirection((short) (getDirection() + getLeftOrRight()));
if (getDirection() > 7) {
setDirection((short) 0);
}
if (getDirection() < 0) {
setDirection((short) 7);
}
setThrshld(0.07f);
} else {
setThrshld(getThrshld() + delta);
}
switch (getDirection()) {
case 0:
move(-1, 0);
break;
case 1:
move(-1, 1);
break;
case 2:
move(0, 1);
break;
case 3:
move(1, 1);
break;
case 4:
move(1, 0);
break;
case 5:
move(1, -1);
break;
case 6:
move(0, -1);
break;
case 7:
move(-1, -1);
break;
default:
move(0, 0);
}
die();
break;
case (MovementConstants.CIRCLES):
if (directionList.isEmpty()) {
if (!die()) {
fillDirectionList();
}
}
if (directionList.size() > 0) {
Integer dir[] = directionList.remove(0);
move(dir[0], dir[1]);
}
break;
default:
break;
}
}
private boolean die() {
boolean died = false;
if (getBorder() >= getDnaParams().getLifeLenght()) {
setDeathCell(getUnit().getCell());
System.err.println("\nDEATH CELL: (" + getDeathCell().getX() + "," + getDeathCell().getY() + ") for tracer " + this.toString());
getDeathCell().setOccupied(getDnaParams().getSpecies(), false, getProgenitor());
stopThread();
died = true;
}
return died;
}
private void duplicate() {
if (getParams().isDuplication()) {
setDuplicating(true);
agentChanged();
}
}
private void move(int downMove, int rightMove) {
getUnit().setLastOccupiedCell(getUnit().getCell());
if (isAlive()) {
int oldX = getUnit().getCell().getX();
int oldY = getUnit().getCell().getY();
Cell cell = getUnit().move(getDnaParams().getSpecies(), downMove, rightMove, getProgenitor());
if (oldX != cell.getX() || oldY != cell.getY()) {
Resource resource = getUnit().getCell().getResource();
int artisticType = resource.getType();
if (artisticType == ResourceConstants.ARTISTIC_TRACE_RESOURCE) {
TraceResource traceResource = (TraceResource) resource;
traceResource.setColor(getInternalColor());
traceResource.setTracer(this.toString());
duplicate();
} else if (artisticType == ResourceConstants.ARTISTIC_COLOR_RESOURCE) {
TraceResource traceResource = new TraceResource(this.toString());
traceResource.setColor(getInternalColor());
getUnit().getCell().setResource(traceResource);
}
if (getBirthCell() == null) {
setBirthCell(new Cell(cell.getX(), cell.getY(), cell.getResource(), null));
System.err.println("BIRTH CELL: (" + getBirthCell().getX() + "," + getBirthCell().getY() + ") for tracer " + this.toString());
}
}
getUnit().getCell().cellChanged();
}
}
private void fillDirectionList() {
short x = getUnit().getCell().getX();
short y = getUnit().getCell().getY();
switch (getParams().getMovement()) {
case (MovementConstants.CIRCLES):
// (x − a)^2 + (y − b)^2 = r^2
float numerator = (short) ((getWorld().getParams().getCols() + getWorld().getParams().getRows()) / 2f);
float denominator = (float) Math.sqrt((Math.random() * numerator) + Math.sqrt(numerator));
short radius = (short) (numerator / denominator);
short deltaX = (short) ((Math.random() * (radius * 2 + 1)) - radius);
short deltaY = (short) ((Math.random() * (radius * 2 + 1)) - radius);
short xCenter = EnvironmentFunction.getNormalizedX((short) (x + deltaX), getWorld().getParams().getCols());
short yCenter = EnvironmentFunction.getNormalizedY((short) (y + deltaY), getWorld().getParams().getRows());
Set<Cell> cells = circleMidpoint(xCenter, yCenter, radius);
List<Cell> orderedCells = EnvironmentFunction.getSortedOutline(cells, getUnit().getCell(), getParams().getCols(), getParams().getRows());
Cell lastCell = getUnit().getCell();
for (Cell c : orderedCells) {
Integer[] dir = new Integer[2];
dir[0] = (int) EnvironmentFunction.getNormalizedMovement((short) (c.getX() - lastCell.getX()), getWorld().getParams().getCols());
dir[1] = (int) EnvironmentFunction.getNormalizedMovement((short) (c.getY() - lastCell.getY()), getWorld().getParams().getRows());
directionList.add(dir);
lastCell = c;
}
break;
default:
break;
}
}
private Set<Cell> circlePoints(short cx, short cy, short x, short y) {
Set<Cell> cells = new HashSet<Cell>();
if (x == 0) {
cells.add(getWorld().getCell(cx, cy + y));
cells.add(getWorld().getCell(cx, cy - y));
cells.add(getWorld().getCell(cx + y, cy));
cells.add(getWorld().getCell(cx - y, cy));
} else if (x == y) {
cells.add(getWorld().getCell(cx + x, cy + y));
cells.add(getWorld().getCell(cx - x, cy + y));
cells.add(getWorld().getCell(cx + x, cy - y));
cells.add(getWorld().getCell(cx - x, cy - y));
} else if (x < y) {
cells.add(getWorld().getCell(cx + x, cy + y));
cells.add(getWorld().getCell(cx - x, cy + y));
cells.add(getWorld().getCell(cx + x, cy - y));
cells.add(getWorld().getCell(cx - x, cy - y));
cells.add(getWorld().getCell(cx + y, cy + x));
cells.add(getWorld().getCell(cx - y, cy + x));
cells.add(getWorld().getCell(cx + y, cy - x));
cells.add(getWorld().getCell(cx - y, cy - x));
}
return cells;
}
public Set<Cell> circleMidpoint(short xCenter, short yCenter, short radius) {
short x = 0;
short y = radius;
short p = (short) ((5 - radius * 4) / 4);
Set<Cell> cells = new HashSet<Cell>();
cells.addAll(circlePoints(xCenter, yCenter, x, y));
while (x < y) {
x++;
if (p < 0) {
p += 2 * x + 1;
} else {
y--;
p += 2 * (x - y) + 1;
}
cells.addAll(circlePoints(xCenter, yCenter, x, y));
}
return cells;
}
}