package simulation.entity;
import java.util.ArrayList;
import sim.field.grid.SparseGrid2D;
import sim.util.Int2D;
import simulation.SimulationModel;
public class Herbivorious extends Animal {
private static final long serialVersionUID = 1L;
private PerceptionTableCell[][] perception;
int perceptionCases;
public Herbivorious(String type, SimulationModel simModel) {
super(type, simModel);
// System.out.println(this.getType()+" #"+this.hashCode()+" sees "+visionPoint+" meters away.");
//System.out.println(this.getType()+" #"+this.hashCode()+" smells "+smellPoint+" meters away.");
}
public void initializePerception(){
//System.out.println(this.getType()+" #"+this.hashCode()+" perception initialized !");
perceptionCases=MeterToCase(Math.max(smellPoint, visionPoint));
//Initialize perception table
perception = new PerceptionTableCell[2*perceptionCases][2*perceptionCases];
for(int i = 0; i<2*perceptionCases;i++){
for(int j = 0; j<2*perceptionCases;j++){
perception[i][j]=new PerceptionTableCell();
}
}
}
@Override
public void action() {
SparseGrid2D yard = simModel.getYard();
detectFood(yard, simModel.getVegetation(), simModel);
Integer[] coor = getNearbyFood();
if (weight < (minimumWeightToDeath + weightConsumeByDay * maxNbDaySafe)) {
//System.out.println(this.getType()+" #"+this.hashCode()+" is on ("+getX()+","+getY()+") and is hungry !");
if((coor[0]!=-1)&&(coor[1]!=-1)){
if(isOnFood()){
//System.out.println(this.getType()+" #"+this.hashCode()+" and is on food !");
eat((int)getX(),(int)getY(),simModel.getVegetation(),simModel);
}else{
//System.out.println(this.getType()+" #"+this.hashCode()+" and sees food on ("+coor[0]+","+coor[1]+")/("+simModel.getVegetationAt(coor[0], coor[1])+") !");
moveTo(yard,coor);
}
}else{
if(!isOnFood()){
//System.out.println(this.getType()+" #"+this.hashCode()+" and doesn't see food !");
moveRandom(yard);
}else{
//System.out.println(this.getType()+" #"+this.hashCode()+" and is on food !");
eat((int)getX(),(int)getY(),simModel.getVegetation(),simModel);
}
}
}else{
//System.out.println(this.getType()+" #"+this.hashCode()+" is not hungry and is on ("+getX()+","+getY()+") !");
moveRandom(yard);
}
}
private void detectFood(SparseGrid2D yard,Float[][] Vegetation, SimulationModel simModel) {
//Parse surrounding to get vegetation
for(int dx=perceptionCases*-1;dx<perceptionCases;dx++){
for(int dy=perceptionCases*-1;dy<perceptionCases;dy++){
int x = yard.stx((int)getX()+dx);
int y = yard.sty((int)getY()+dy);
//System.out.println("yard : ("+yard.getWidth()+","+yard.getHeight()+")");
while((Math.abs(x)>Math.abs(yard.getWidth()-1))||(x<0)){
x=yard.stx(x);
}
while((Math.abs(y)>Math.abs(yard.getHeight()-1))||(y<0)){
y=yard.stx(y);
}
//System.out.println(this.getType()+" #"+this.hashCode()+" myPosition is ("+getX()+","+getY()+") my perception is "+perceptionPoint+" i'm looking at ("+dx+","+dy+") of me, so at ("+x+","+y+")");
//update perception matrix
perception[dx+perceptionCases][dy+perceptionCases].setX(x);
perception[dx+perceptionCases][dy+perceptionCases].setY(y);
perception[dx+perceptionCases][dy+perceptionCases].setAmount(simModel.getVegetationAt(x, y));
}
}
//printPerception();
}
private Integer[] getNearbyFood() {
ArrayList<Int2D> cases = new ArrayList<Int2D>();
double minDistance=MeterToCase(movePoint);
double currentDistance;
for(PerceptionTableCell[] i:perception){
for(PerceptionTableCell j:i){
if(j.getAmount()>ValueByDayToValueByStep(weightConsumeByDay)){
currentDistance = getShortestDistanceToPoint(j.getX(), j.getY());
if(currentDistance<minDistance){ //if nearer food found
cases.clear();
cases.add(new Int2D(j.getX(),j.getY()));
minDistance = currentDistance; //update min distance
}else if(currentDistance==minDistance){
cases.add(new Int2D(j.getX(),j.getY()));
}
}
}
}
if(cases.size()==0){
Integer[] i = new Integer[2];
i[0]=-1;
i[1]=-1;
return i;
}else{
int ind = (int) (Math.random()*cases.size());
Integer[] i = new Integer[2];
Int2D d = cases.get(ind);
i[0]=d.x;
i[1]=d.y;
return i;
}
}
private Double moveRandom(SparseGrid2D yard) {
float randomSign = (float) (Math.random()*2);
float randomAngle = (float) ((float) Math.random()*2*Math.PI);
if(randomSign<=1){
randomAngle*=-1;
}
//maximum distance toward random direction
float dX = (float) (Math.cos(randomAngle)*MeterToCase(movePoint));
float dY = (float) (Math.sin(randomAngle)*MeterToCase(movePoint));
//System.out.println(this.getType()+" #"+this.hashCode()+" ("+movePoint+") move randomly toward "+Math.toDegrees(randomAngle)+"+ degrees ("+Math.cos(randomAngle)+","+Math.sin(randomAngle)+") to ("+dX+","+dY+") from itself!");
//Avoid null move
if((dX<1)&&(dY<1)){
if(dX>dY){
dX=1;
dY=0;
}else{
dY=1;
dX=0;
}
}
//destination is
int X = yard.stx((int) (getX()+dX));
int Y = yard.sty((int) (getY()+dY));
//System.out.println("yard : ("+yard.getWidth()+","+yard.getHeight()+")");
while((Math.abs(X)>Math.abs(yard.getWidth()-1))||(X<0)){
X=yard.stx(X);
}
while((Math.abs(Y)>Math.abs(yard.getHeight()-1))||(Y<0)){
Y=yard.stx(Y);
}
//System.out.println(this.getType()+" #"+this.hashCode()+" move randomly to ("+X+","+Y+")!");
yard.setObjectLocation(this, X, Y);
return (double) 0;
}
private void eat(int VegetationX, int VegetationY, Float[][] floats, SimulationModel SimModel) {
//consume vegetationand update weight
double consumes=SimModel.consumeVegetationAt(VegetationX, VegetationY, ValueByDayToValueByStep(weightConsumeByDay)*2);
//System.out.println(this.getType()+" #"+this.hashCode()+" tries to eat "+(toStep(weightConsumeByDay)*1000)+"g of grass !");
//System.out.println(this.getType()+" #"+this.hashCode()+" eats "+(consumes*1000)+"g of grass !");
this.getSupport().firePropertyChange("ate",this.getType(), consumes);
weight+=consumes;
}
public boolean isOnFood(){
if(simModel.getVegetationAt((int)getX(), (int)getY())>ValueByDayToValueByStep(weightConsumeByDay)){
return true;
}else{
return false;
}
}
public void printPerception(){
for(int i=0;i<perceptionCases*2;i++){
for(int j=0;j<perceptionCases*2;j++){
if((i==perceptionCases)&&(j==perceptionCases)){
System.out.print("X ");
}else{
System.out.print(perception[i][j].getAmount()+" ");
}
}
System.out.print("\n");
}
System.out.print("\n\n");
}
class PerceptionTableCell {
private float amount;
private int X;
private int Y;
public PerceptionTableCell(){
amount=-1;
X=-1;
Y=-1;
}
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
public int getX() {
return X;
}
public void setX(int x) {
X = x;
}
public int getY() {
return Y;
}
public void setY(int y) {
Y = y;
}
}
}