+F@S(1U#UfxTzFBr()oF`1
zJUaRng_k=s^LAxOc0L_+^sPDQ3kPt+%yqb){f{Sa-p+jbSbaL#>#3y?=zyR;Z!}C6D#nJz3(Bb*
zG#ra6ekH>IcNs#1qs+vNwm!E*EnNOh>M{|!<*6r+1)+T?p|@kD91fQ1`-`;Utea{c
zk6;9;jHzCIMOWZJjke%hP3v`Ps|dRtqcdv;v*@pcM;uEAX)OaP>pZW;o?FsTW~P}I+#l)r*BltZ$);}zDUF^HO$ujQS7k8UO|zz8lxEPYt5d=2r(_8>0
z;r5=^$~as562E15N!Lb>5v5#H4OS3Vxxr&mcR`ke=ExHvc};5>%W?)zEZ0(^jCB~j
zdtW5uXXQRp}tKPyCp#TEF6I
z7iUpdUT44-E37*x&yAGIOO=%~Q)RQZ(p>Q^XdKVm9>NnVkCyTd{mgc7&!tDhFNYCl
zDhSt$4)8n5knEQbHIn4xOYf5twLV@&dt^Yhe9Rc#b-!a0P06FdI~U{R^B3wzZ)3ps
zCGV5SZHS-KPbk73G7H2I^qCqinq1;q{`NND^7X&olhR8O2_29(Fpw{Y@#j}_Gci*6
z+f^Ag)d$J)A`f498G=!q^|P;;r6rYV3YliEU+73!AlDgF*lgTfaagCWdt&6?U4UQf
zTi6IFv9kit>uvId5&6X0f%YDP{NQ}0OZNL@1o%7g;DNiwLz#Eyp5hHZ%H`A~d2tO`
z#2lU?svRxN#)>qK#0`baRDLA|xoS@64l(R#*Ypm1yx((L6A6t^DV7lnI5
zSIjlzb?rN9`a)Zs%p5qPiaR=b9}9-hXXd`{;9FMe*wh%#WQ>h%xep8KrZzkE6MQ>I
zjUN!~FRVP(T}kbs%1K<_%2ivd&W^L-<4R?ZoJTaK)tE0a5Mkrz{}j(=R<
z|IrPIVn9Yzf|9}j2}bay+~aE?n4vf_GND;!;Y3VMHf#1ye9M-cJ_%4=*`v2&+Y~8q
z=gt!f&haAECs4&a?R%qn3>8lyhH9>dRL%wKsmriyg~2o3XrT5nUx4e_owm$Q~J!W@f`M0p)S`+93Ji@@K1XnfwUw{?qB?K_ORnDlTd$*<4-L
z18@30@y7H0NJr@W#0gothXKiy{CryvClwE2biDxs7ukahHEW0&eYS0o|M-<{(K~v~
zQ6xfZE>_OMi;D~Aq)(DKer8t5#y+;E{zj+5rG^PdLZ-Ox9pPDB(Ta7?L~BSc_K;#1
ze)@!7$)bf%y8gCcu8TD*cw5!jUzux*Th^h_DBFi8lI`mNIxVYH3T@r(_DXlttyElk
zL{luC>eDD%gTBFKY1sagyUrR<3lU!jcKBU&YpSTk;yX2k{qCq(TkM-JXeU!2;)xih
zs_IbX8}3?I*Y}q9wh?uuL;*(bYL5qHBDE>$tKvv!Cf#?f
zx_^9o57ruPNk`5-^L>t@P0>ca;^f?Vat_f%G1)F15u)N8>U9QL2lXt!i08;uTo>&<2(lYK
zRxHP0*f6uru-3IQV@m!qad^i2ieqLEFA|f}FmWuG7;_4_gD~+J=NR)MQOE)gvViGy
z5+(1>Cdb?6<0eC)(YXd?Y+1%}-bAy;H}1YhoRLx}AD4-CV^DTTjW9l4?$>gAh|^$f
zmJxBn{Cf4(sExTi2K?q7Ohv4$_CRVJQ3!$TgNW~@<@`?|zwIm^
z-B;ES!Bpe9!dWT?-dO4J%dyYA;!zKn0&r#eu*QBrlHbCWQ3|f~cznu`483BCLB`Tf
z8K(=ekWk;p)lQc|sewUONoS^f(yj@ctPd503nbrwnPJ|M1N>Sj`d*xcAX9I^U}@t^%YBUCdJ$A(@AH{S
zSnYz!Z)s&~f$=$0N$Gax)3&}XJc=DuFkxPaJ37tDx5jWT|KJ*X*8E|*;+S4M@lJ$1
z!@*3zKNn9s>p)!jP6SXhXHte1rX5rm!)wYix(yhV?*7@3uAS(Pr9*Y?y8+v$x;-km1)R
zzAK}c{UZA}+CPUn@L97Ue{O9tJ*};ifWw*B+Z;Bn09OAJ-WZP>X)%2mseY;
zg1(>(Ii9PZWtH;L%c@@-=pQ`!Z`x2OXJqneA*go!QIH9$tjFC=Bm~_KD)J++xJ3Qe
zM#n`EDj*ym`~v4Sg*6qK5L=qlNb%x2OW2{pADN&9CLD2s`c9%8Yrf06Pu)qYw(~R;lo1IhISu^JI(FQ;tm>C9_-e{z*WwE-KKCt$Uhk9XN@iYxK
z+@Bpyi3q(cmuS|;r>6uz7`EN!WN!s&*Tyj9;CsnG`Yp~R!^-(slo79dnI0(IXWW;A
z&v!x6J^EhD=M-$0X|k6wyA?XV1P874eEz(svos*FJ<)&Zge#^G+gy#C-PnUSmh7NF
zn&Udmp(0}wwb2->a6!Z4Sw9T`Ief--v!I^szPWI1NTR(8Ak=t{{r(OnH1n3Bn-}{S
zO7BeYoY*O|{Y+s4Q_uwb3^AYoZCGDGF+d`^e{azJ<;eVf{7bv8qRc-D{IiAd@8DdB
zL;1Ic!ry`a?5p}aZ~#(s`u}xV{Z8rkE}Oq-JwtkL{#Vb<@9^KtTz|p4AU!*Oz<)1#
z{Z8Wdtm0oJ;&J|TSN;|_{|^5>Me-LMn&5xn|45kpj{iMa{|nzn_&@mHLigV({4)an
z3l9L4Kw6i6kB5Ip|1(JVJGzhbZ|FZmhTq}8yLW#P5U2Q)d;ibbQ
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/simulation/src/control/Controller.java b/simulation/src/control/Controller.java
new file mode 100644
index 0000000..56dae3c
--- /dev/null
+++ b/simulation/src/control/Controller.java
@@ -0,0 +1,81 @@
+package control;
+
+import javafx.scene.canvas.Canvas;
+import javafx.scene.chart.StackedAreaChart;
+import javafx.scene.control.Label;
+import javafx.scene.control.Slider;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.input.ScrollEvent;
+import simulation.Simulation;
+
+//Controller class for user input handling
+public class Controller {
+ double mouseX;
+ double mouseY;
+ Simulation simulation;
+
+ //interface handlers, public for fxml link
+ public javafx.scene.control.Button pauseButton;
+ public javafx.scene.control.Button playButton;
+ public StackedAreaChart animalNumChart;
+ public StackedAreaChart GrassNumChart;
+ public Label dominatingGenotype;
+ public Label lifeTimeExpectancy;
+ public Label avarageEnergy;
+ public Label avarageChildrenNumber;
+ public Canvas simulationCanvas;
+ public Slider speedSlider;
+
+
+
+ //user interaction functions
+ public void drag(MouseEvent mouseEvent) {
+ for(int i=0;i0.2) {
+ for(int i=0;igetController();
+
+ primaryStage.setTitle("Simulation");
+ primaryStage.setResizable(false);
+ Simulation simulation=new Simulation("param.json",controller);
+ controller.setSimulation(simulation);
+ primaryStage.show();
+
+
+ primaryStage.setScene(new Scene(root, 960, 720));
+ Scene scene = primaryStage.getScene();
+ Canvas canvas=(Canvas)scene.lookup("#simulationCanvas");
+ simulation.canvas=canvas;
+ GraphicsContext context = canvas.getGraphicsContext2D();
+ simulation.initialize(simulation.startAnimalNum,System.currentTimeMillis());
+
+ //main loop
+ new AnimationTimer(){
+ public void handle(long currentNanoTime)
+ {
+ context.clearRect(0,0,960,720);
+ simulation.visualize(context);
+ simulation.simulate(System.currentTimeMillis(),controller);
+ }
+
+ }.start();
+ primaryStage.show();
+ }
+
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+}
diff --git a/simulation/src/control/sample.fxml b/simulation/src/control/sample.fxml
new file mode 100644
index 0000000..d09871d
--- /dev/null
+++ b/simulation/src/control/sample.fxml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/simulation/src/simulation/Animal.java b/simulation/src/simulation/Animal.java
new file mode 100644
index 0000000..433e37f
--- /dev/null
+++ b/simulation/src/simulation/Animal.java
@@ -0,0 +1,87 @@
+package simulation;
+
+import utils.Direction;
+import utils.Vector2;
+
+import java.util.Random;
+
+class Animal extends MapObject{
+ int childNum;
+ int lifeTime;
+ boolean touched;
+ Direction orientation;
+ double energy;
+ Genotype genes;
+
+ public Animal(Vector2 pos,double energy){
+ super(pos);
+ Random gen=new Random();
+ orientation=new Direction(gen.nextInt(9));
+ this.energy=energy;
+ genes=new Genotype();
+
+ }
+ //child generating
+ public Animal(Animal parent1,Animal parent2){
+ super(parent1.pos);
+ Random gen=new Random();
+ orientation=new Direction(gen.nextInt(9));
+ Direction offset=new Direction(gen.nextInt(8));
+ this.pos=this.pos.sum(offset.getDirVec());
+ this.energy=parent1.energy/4+parent2.energy/4;
+ parent1.energy-=parent1.energy/4;
+ parent2.energy-=parent2.energy/4;
+
+ genes=new Genotype(parent1,parent2);
+
+
+ }
+
+
+ //check if dead, update stats
+ public boolean checkStatus(){
+ if(this.energy<=0){
+ this.energy=0;
+ observer.notPresent(this);
+ return true;
+ }
+ lifeTime++;
+ return false;
+ }
+ //move, inform observer and update stats
+ public void move(int width,int height){
+ touched=false;
+ energy--;
+ if(energy<0)
+ energy=0;
+ Vector2 oldPos=this.pos;
+
+ Random gen=new Random();
+ int rand=gen.nextInt(31);
+ int sum=0;
+ int i=0;
+ for(;i<8;i++){
+ sum+=genes.genes[i];
+ if(sum>=rand)
+ break;
+
+ }
+
+ orientation.rotate(i);
+ this.pos=this.pos.sum(orientation.getDirVec());
+ this.pos.x=this.pos.x%width;
+ if(this.pos.x<0)
+ this.pos.x=width+this.pos.x;
+ this.pos.y=this.pos.y%height;
+ if(this.pos.y<0)
+ this.pos.y=height+this.pos.y;
+ observer.positionChanged(oldPos,this);
+
+
+
+ }
+
+
+
+
+}
diff --git a/simulation/src/simulation/Genotype.java b/simulation/src/simulation/Genotype.java
new file mode 100644
index 0000000..0275637
--- /dev/null
+++ b/simulation/src/simulation/Genotype.java
@@ -0,0 +1,120 @@
+package simulation;
+import java.util.Random;
+
+public class Genotype {
+ int[] genes;
+ int dominating;
+
+ //search for dominating gene
+ private void createDominatingGene(int[] genes){
+ int max=0;
+ int maxIdx=0;
+ for(int i=0;i<8;i++)
+ if(genes[i]>max){
+ max=genes[i];
+ maxIdx=i;
+ }
+ this.dominating=maxIdx;
+ }
+ //write genotype to repeating array
+ public int[] toArray(){
+
+ int[] array=new int[32];
+ int idx=0;
+ for(int i=0;i<8;i++)
+ for(int y=0;y=2){
+ genes[y]--;
+ genes[i]++;
+ break;
+ }
+ }
+ }
+
+
+ createDominatingGene(this.genes);
+ }
+
+
+}
diff --git a/simulation/src/simulation/GlobalStats.java b/simulation/src/simulation/GlobalStats.java
new file mode 100644
index 0000000..ed21662
--- /dev/null
+++ b/simulation/src/simulation/GlobalStats.java
@@ -0,0 +1,77 @@
+package simulation;
+
+import control.Controller;
+import javafx.scene.chart.NumberAxis;
+import javafx.scene.chart.StackedAreaChart;
+import javafx.scene.chart.XYChart;
+import utils.Average;
+
+public class GlobalStats {
+ int animalNum;
+ int grassNum;
+ int parentNum;
+ int[] genotypes=new int[8];
+
+ Average avgLifeExpectancy =new Average();
+ private Average avgChildren=new Average();
+ Average avgEnergy=new Average();
+
+
+ GlobalStats(Controller controller){
+ this.animalNumChart=controller.animalNumChart;
+ this.grassNumChart=controller.GrassNumChart;
+ animalNumChart.getData().addAll(animalsSeries);
+ grassNumChart.getData().add(grassSeries);
+ }
+
+ //charts
+ private StackedAreaChart animalNumChart;
+ private XYChart.Series animalsSeries = new XYChart.Series();
+
+ private StackedAreaChart grassNumChart;
+ private XYChart.Series grassSeries = new XYChart.Series();
+
+
+
+ //update stats including visualization
+ public void update(Controller controller,long turn,double delay,double energyLoss){
+ // avgEnergy.sumAdd(animalNum*energyLoss*-1);
+ avgEnergy.divSet(animalNum);
+ if(turn%(int)(1000/delay)!=0)
+ return;
+ if(turn%1000==0){
+ animalsSeries.getData().remove(1,animalsSeries.getData().size()-1);
+ grassSeries.getData().remove(1,grassSeries.getData().size()-1);
+ NumberAxis axisX=((NumberAxis)animalNumChart.getXAxis());
+ axisX.setAutoRanging(false);
+ axisX.setLowerBound(turn-500);
+ axisX.setUpperBound(turn+1000);
+ axisX=((NumberAxis)grassNumChart.getXAxis());
+ axisX.setAutoRanging(false);
+ axisX.setLowerBound(turn-500);
+ axisX.setUpperBound(turn+1000);
+ }
+
+ animalsSeries.getData().add(new XYChart.Data<>(turn,animalNum));
+ grassSeries.getData().add(new XYChart.Data<>(turn,grassNum));
+
+ controller.lifeTimeExpectancy.setText(String.format("%.3f",avgLifeExpectancy.avg));
+ avgChildren.sumSet(parentNum);
+ avgChildren.divSet(animalNum-parentNum);
+
+ controller.avarageChildrenNumber.setText(String.format("%.3f",avgChildren.avg));
+
+ controller.avarageEnergy.setText(String.format("%.3f",avgEnergy.avg));
+
+ int max=0;
+ int maxIdx=0;
+ for(int i=0;i<8;i++)
+ if(genotypes[i]>max){
+ max=genotypes[i];
+ maxIdx=i;
+ }
+
+ controller.dominatingGenotype.setText(Integer.toString(maxIdx));
+ System.out.println(animalNum);
+ }
+}
diff --git a/simulation/src/simulation/Grass.java b/simulation/src/simulation/Grass.java
new file mode 100644
index 0000000..c4dc0cd
--- /dev/null
+++ b/simulation/src/simulation/Grass.java
@@ -0,0 +1,9 @@
+package simulation;
+
+import utils.Vector2;
+
+public class Grass extends MapObject{
+ public Grass(Vector2 pos) {
+ super(pos);
+ }
+}
diff --git a/simulation/src/simulation/Grid.java b/simulation/src/simulation/Grid.java
new file mode 100644
index 0000000..992a9f6
--- /dev/null
+++ b/simulation/src/simulation/Grid.java
@@ -0,0 +1,230 @@
+package simulation;
+
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.paint.Color;
+import utils.Vector2;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class Grid implements IStateObserver {
+
+ int height = 0;
+ int width = 0;
+ double cellSize=7.2;
+
+
+ public double zoom=1;
+ public double translateX;
+ public double translateY;
+
+
+ private Vector2 junglePos;
+ private Vector2 jungleSize;
+ HashMap> grid = new HashMap<>();
+
+ public Grid(int w, int h, Vector2 jPos, Vector2 jSize,double translateX,double translateY) {
+ this.width = w;
+ this.height = h;
+ this.junglePos = jPos;
+ this.jungleSize = jSize;
+ this.translateX=translateX;
+ this.translateY=translateY;
+ this.cellSize=720/(double)Math.max(w,h);
+
+ }
+
+ public void addObject(MapObject obj) {
+ ArrayList values = grid.get(obj.pos);
+ if (values == null) {
+ values = new ArrayList();
+ values.add(obj);
+ grid.put(obj.pos, values);
+ } else {
+ values.add(obj);
+ }
+
+ obj.addObserver(this);
+ }
+
+ public void removeObject(MapObject obj) {
+ ArrayList values = grid.get(obj.pos);
+ values.remove(obj);
+ }
+
+
+ @Override
+ public void positionChanged(Vector2 oldPosition, MapObject obj) {
+ ArrayList values = grid.get(oldPosition);
+ values.remove(obj);
+
+ this.addObject(obj);
+ }
+
+ @Override
+ public void notPresent(MapObject obj) {
+ this.removeObject(obj);
+ }
+
+ public boolean isOccupied(Vector2 pos){
+ if(grid.get(pos)!=null&&grid.get(pos).size()>0)
+ return true;
+ return false;
+ }
+
+ public boolean isOccupiedByAnimal(Vector2 pos){
+ if(grid.get(pos)!=null&&grid.get(pos).size()>0&&grid.get(pos).get(0) instanceof Animal)
+ return true;
+ return false;
+ }
+
+ //check and remove if there is grass on given position
+ public boolean eatGrassOnPos(Vector2 pos){
+
+ if(grid.get(pos)!=null&&grid.get(pos).get(0) instanceof Grass){
+ grid.get(pos).remove(0);
+ return true;}
+ return false;
+ }
+
+ public int numberOfObjectsOnPos(Vector2 pos){
+ if(grid.get(pos)!=null){
+ return grid.get(pos).size();
+ }
+ return 0;
+ }
+ //feed strongest animals on position by given energy divided by their number
+ public void feedThemAll(Vector2 pos,double energy){
+ ArrayList objectList=(ArrayList)grid.get(pos);
+ double max=0;
+ int strongestNum=0;
+ for(int i=0;imax)
+ max=((Animal)objectList.get(i)).energy;
+
+ for(int i=0;i objectList=(ArrayList)grid.get(pos);
+ if(objectList.get(0) instanceof Grass)
+ return null;
+ double max=0;
+ int idx=0;
+ for(int i=0;i max)
+ max = ((Animal) objectList.get(i)).energy;
+ }
+ for(int i=0;imax2&&((Animal)objectList.get(i)).energy!=max)
+ max2=((Animal)objectList.get(i)).energy;
+
+ for(int i=0;i objectList=(ArrayList)grid.get(pos);
+ double max=0;
+ int idx=-1;
+ for(int i=0;i max)
+ max = ((Animal) objectList.get(i)).energy;
+ idx=i;
+ }
+ if(idx==-1)
+ return null;
+ return (Animal)objectList.get(idx);
+ }
+ //draw grid and associated objects using given context
+ public void visualize(GraphicsContext context,double startEnergy) {
+
+ context.setFill(Color.RED);
+ context.setStroke(Color.BLACK);
+ context.setLineWidth(0.1);
+
+
+ for (Map.Entry element : grid.entrySet()) {
+ Vector2 pos=(Vector2)element.getKey();
+ ArrayList objectList=(ArrayList)element.getValue();
+
+ if(objectList.size()!=0&&objectList.get(0) instanceof Animal){
+ context.setFill(Color.color((((Animal) objectList.get(0)).energy>startEnergy?1: Math.abs(((Animal) objectList.get(0)).energy/startEnergy)),0,0));
+
+ context.fillRect(translateX+pos.x*cellSize,translateY+pos.y*cellSize,cellSize,cellSize);
+ }else if(objectList.size()!=0&&objectList.get(0) instanceof Grass){
+ context.setFill(Color.GREEN);
+ context.fillRect(translateX+pos.x*cellSize,translateY+pos.y*cellSize,cellSize,cellSize);
+ context.setFill(Color.RED);
+ }
+
+ }
+ context.setLineWidth(1);
+ context.strokeRect(translateX, translateY, width*cellSize, height*cellSize);
+ context.setLineWidth(0.1);
+ }
+ //change zoom transformation for given grid, overall it is not used but it supports multiple viewports
+ public void zoomChange(double zoom){
+ if(this.zoom<0)
+ this.zoom=-1/this.zoom;
+ this.translateX=(this.translateX+((Math.max(width,height) * cellSize) / this.zoom * (this.zoom/2-0.5)))/this.zoom;
+ this.translateY=(this.translateY+((Math.max(width,height) * cellSize) / this.zoom * (this.zoom/2-0.5)))/this.zoom;
+ this.cellSize=this.cellSize/this.zoom;
+
+
+ this.zoom+=zoom;
+ if(this.zoom<0)
+ this.zoom=-1/this.zoom;
+ this.cellSize=this.cellSize*this.zoom;
+
+ this.translateX = this.translateX*this.zoom-(Math.max(width,height) * cellSize) / this.zoom * (this.zoom/2-0.5);
+ this.translateY =this.translateY*this.zoom-(Math.max(width,height) * cellSize) / this.zoom * (this.zoom/2-0.5);
+
+
+
+ }
+ //print the background, maps bounds and grid lines according to current viewport transformation
+ public void printBackground(GraphicsContext context){
+ context.setStroke(Color.BLACK);
+ context.setLineWidth(0.1);
+ if(this.zoom>=1&&Math.max(width,height)*Math.max(width,height)/(this.zoom*this.zoom)<50000){
+ context.setFill(Color.BISQUE);
+
+
+ context.fillRect(translateX%cellSize - cellSize, (translateY%cellSize) - cellSize, cellSize*Math.max(width+2,height+2), cellSize*Math.max(width+2,height+2));
+ context.setFill(Color.RED);
+ for (int x = -1; x < Math.max(width+2,height+2)/this.zoom; x++)
+ for (int y = -1; y < Math.max(width+2,height+2)/this.zoom; y++)
+ context.strokeRect(translateX%cellSize+x * cellSize, (translateY%cellSize)+y * cellSize, cellSize, cellSize);
+ }else{
+ context.setFill(Color.BISQUE);
+ context.fillRect((translateX%cellSize)-cellSize, (translateY%cellSize)- cellSize, cellSize*Math.max(width+2,height+2)*1/this.zoom, cellSize*Math.max(width+2,height+2)*1/this.zoom);
+ context.setFill(Color.RED);
+ }
+ }
+}
\ No newline at end of file
diff --git a/simulation/src/simulation/IStateObserver.java b/simulation/src/simulation/IStateObserver.java
new file mode 100644
index 0000000..43eaba1
--- /dev/null
+++ b/simulation/src/simulation/IStateObserver.java
@@ -0,0 +1,8 @@
+package simulation;
+
+import utils.Vector2;
+
+public interface IStateObserver {
+ void positionChanged(Vector2 oldPosition, MapObject obj);
+ void notPresent(MapObject obj);
+}
diff --git a/simulation/src/simulation/MapObject.java b/simulation/src/simulation/MapObject.java
new file mode 100644
index 0000000..25c11ac
--- /dev/null
+++ b/simulation/src/simulation/MapObject.java
@@ -0,0 +1,17 @@
+package simulation;
+
+
+import utils.Vector2;
+
+public class MapObject {
+ public Vector2 pos;
+ IStateObserver observer;
+
+public MapObject(Vector2 pos){
+ this.pos=pos;
+}
+ public void addObserver(IStateObserver observer){
+ this.observer=observer;
+ }
+
+}
diff --git a/simulation/src/simulation/Simulation.java b/simulation/src/simulation/Simulation.java
new file mode 100644
index 0000000..6c8b5ac
--- /dev/null
+++ b/simulation/src/simulation/Simulation.java
@@ -0,0 +1,262 @@
+package simulation;
+import control.Controller;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Font;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.*;
+import utils.Vector2;
+
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.Random;
+
+public class Simulation {
+
+
+ private long time;
+ private int width;
+ private int height;
+ public int mapNum;
+ private Vector2 jungleSize;
+ private double startEnergy;
+ private double moveEnergy;
+ private double plantEnergy;
+ private double jungleRatio;
+ public int startAnimalNum;
+ public Canvas canvas;
+ public Grid[] grid;
+ private long turn;
+ public boolean pause;
+ public double delay=20;
+ public boolean pick=false;
+ public double pickX;
+ public double pickY;
+ private ArrayList> animalList=new ArrayList>();
+ private GlobalStats stats;
+
+ public Simulation(String json,Controller controller){
+ try {
+ JSONObject parser = (JSONObject)new JSONParser().parse(new FileReader(json));
+ this.width=((Long)parser.get("width")).intValue();
+ this.height=((Long)parser.get("height")).intValue();
+ this.mapNum=((Long)parser.get("mapNum")).intValue();
+ this.startEnergy=((Double)parser.get("startEnergy"));
+ this.moveEnergy=((Double)parser.get("moveEnergy"));
+ this.plantEnergy=((Double)parser.get("plantEnergy"));
+ this.jungleRatio=((Double)parser.get("jungleRatio"));
+ this.startAnimalNum=((Long)parser.get("startAnimalNum")).intValue();
+
+ }
+ catch(Exception error){
+ System.out.println("File read error "+error.getMessage());
+ }
+ this.jungleSize=new Vector2(((Double)(width*jungleRatio)).intValue(),((Double)(height*jungleRatio)).intValue());
+ this.grid=new Grid[mapNum];
+ for(int i=0;i());
+ }
+ this.stats=new GlobalStats(controller);
+
+ }
+ //initialize basic state by adding starting animals to maps
+ public void initialize(int startAnimals,long time){
+
+ Random gen=new Random();
+ gen.nextInt(jungleSize.x);
+
+
+ for(int y=0;y20)
+ break;
+ Vector2 pos=new Vector2(width/2+gen.nextInt(Math.max(jungleSize.x/2,1))*(gen.nextBoolean()?-1:1),height/2+gen.nextInt(Math.max(jungleSize.y/2,1))*(gen.nextBoolean()?-1:1));
+ if(grid[y].isOccupied(pos)==true){
+ counter++;
+ i--;
+ continue;
+ }
+ Animal basic=new Animal(pos,startEnergy);
+ grid[y].addObject(basic);
+ animalList.get(y).add(basic);
+ this.stats.genotypes[basic.genes.dominating]++;
+ stats.animalNum++;
+ }}
+ this.time=time;
+ stats.avgEnergy.sumSet(mapNum*startAnimals*startEnergy);
+ stats.avgEnergy.divSet(mapNum*startAnimals);
+ }
+
+ public void simulate(long time, Controller controller){
+ //timer handling
+ if(pause==true||time-this.time0)
+ stats.parentNum--;
+ this.stats.genotypes[animalList.get(y).get(i).genes.dominating]--;
+ animalList.get(y).remove(i);
+ stats.animalNum--;
+
+
+ }
+ }
+
+
+ //move phaze
+
+ for(int i=0;i1){
+ Animal[] strongest=grid[y].getStrongestPair(animalList.get(y).get(i).pos,startEnergy/2);
+ if(strongest==null)
+ continue;
+ Animal child=new Animal(strongest[0],strongest[1]);
+ grid[y].addObject(child);
+ animalList.get(y).add(child);
+ stats.animalNum++;
+ if(strongest[0].childNum==0)
+ stats.parentNum++;
+ if(strongest[1].childNum==0)
+ stats.parentNum++;
+ strongest[0].childNum++;
+ strongest[1].childNum++;
+
+ this.stats.genotypes[child.genes.dominating]++;
+ }
+ }
+
+
+ //add grass (2 in jungle, 2 outside) and update stats
+ Random gen=new Random();
+ int counter=0;
+
+ counter=0;
+ for (int i = 0; i < 2; i++) {
+ if(counter>20)
+ break;
+ Vector2 pos = new Vector2(width / 2 + gen.nextInt(Math.max(jungleSize.x/2,1)) * (gen.nextBoolean() ? -1 : 1), height / 2 + gen.nextInt(Math.max(jungleSize.y/2,1)) * (gen.nextBoolean() ? -1 : 1));
+ if (grid[y].isOccupied(pos) == true) {
+ counter++;
+ i--;
+ continue;
+ }
+
+ grid[y].addObject(new Grass(pos));
+ stats.grassNum++;
+ }
+ counter=0;
+ for (int i = 0; i < 2; i++) {
+ if(counter>20)
+ break;
+ Vector2 pos = new Vector2( gen.nextInt(width) , gen.nextInt(height));
+ if(grid[y].isOccupied(pos)==true||(pos.xwidth/2-jungleSize.x/2&&pos.yheight/2-jungleSize.y/2)){
+ counter++;
+ i--;
+ continue;
+ }
+
+ grid[y].addObject(new Grass(pos));
+ stats.grassNum++;
+ }
+
+ }
+ //calculate advanced stats and update visualization
+ stats.update(controller,turn,delay,moveEnergy);
+ }
+ //visualize animation
+ public void visualize(GraphicsContext context){
+ this.grid[0].printBackground(context);
+ for(int i=0;if_AO&zRcrz3+R54UC6fslI7~V0#?170bKoUd9fn*^70GL?}Q~&?~
literal 0
HcmV?d00001