├── Classes ├── Animal.java ├── Genes.java ├── Grass.java └── Vector2d.java ├── DarwinWorld ├── PropertiesLoader.java ├── SteppeJungleMap.java ├── World.java └── config.json ├── EnumClasses ├── MapDirection.java └── MoveDirection.java ├── Interfaces ├── IMapElement.java ├── IPositionChangeObserver.java └── IWorldMap.java ├── Menu ├── SettingsMenu.java └── SettingsPanel.java ├── POProject1.iml ├── README.md └── Visualization ├── FunctionPlot.java ├── MapSimulation.java ├── PlotRenderPanel.java └── RenderPanel.java /Classes/Animal.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Classes; 2 | 3 | import agh.cs.po.EnumClasses.MapDirection; 4 | import agh.cs.po.EnumClasses.MoveDirection; 5 | import agh.cs.po.Interfaces.IWorldMap; 6 | import agh.cs.po.Interfaces.IMapElement; 7 | import agh.cs.po.Interfaces.IPositionChangeObserver; 8 | 9 | import java.awt.*; 10 | import java.util.ArrayList; 11 | 12 | public class Animal implements IMapElement { 13 | public MapDirection direction; 14 | public IWorldMap map; 15 | public int energy; 16 | public int startEnergy; 17 | public ArrayList observerlist = new ArrayList<>(); 18 | public Genes genes; 19 | protected Vector2d position; 20 | 21 | //CONSTRUCTORS 22 | 23 | public Animal() { 24 | this.direction = MapDirection.NORTH; 25 | genes = new Genes(8, 32); 26 | position = new Vector2d(2, 2); 27 | } 28 | 29 | public Animal(IWorldMap map) { 30 | this(); 31 | this.map = map; 32 | } 33 | 34 | public Animal(IWorldMap map, Vector2d initialPosition) { 35 | this(map); 36 | this.position = initialPosition; 37 | } 38 | 39 | public Animal(IWorldMap map, Vector2d initialPosition, int energy) { 40 | this(map, initialPosition); 41 | this.energy = energy; 42 | this.startEnergy = energy; 43 | } 44 | 45 | //ENERGY 46 | 47 | public boolean isDead() { 48 | return this.energy <= 0; 49 | } 50 | 51 | public void changeEnergy(int value) { 52 | this.energy = this.energy + value; 53 | if (this.energy < 0) { 54 | this.energy = 0; 55 | } 56 | } 57 | //MOVING 58 | 59 | public void move(MoveDirection d) { 60 | 61 | switch (d) { 62 | case LEFT: 63 | this.direction = this.direction.previous(); 64 | return; 65 | case RIGHT: 66 | this.direction = this.direction.next(); 67 | return; 68 | case FORWARD: 69 | if (map.canMoveTo(position.add(direction.toUnitVector()))) { 70 | Vector2d old = new Vector2d(this.getPosition().x, this.getPosition().y); 71 | this.position = position.add(direction.toUnitVector()); 72 | this.positionChanged(old, this.position, this); 73 | } 74 | return; 75 | case BACKWARD: 76 | if (map.canMoveTo(position.subtract(direction.toUnitVector()))) { 77 | Vector2d old = new Vector2d(this.getPosition().x, this.getPosition().y); 78 | position = position.subtract(direction.toUnitVector()); 79 | this.positionChanged(old, this.position, this); 80 | } 81 | return; 82 | //no need default 83 | } 84 | } 85 | 86 | public void rotate() { 87 | int numOfRotation = genes.returnRandomGen(); 88 | for (int i = 0; i < numOfRotation; i++) { 89 | this.move(MoveDirection.RIGHT); 90 | } 91 | } 92 | 93 | @Override 94 | public Vector2d getPosition() { 95 | return this.position; 96 | } 97 | 98 | @Override 99 | public boolean isMovable() { 100 | return true; 101 | } 102 | 103 | //OBSERVERS 104 | 105 | @Override 106 | public void addObserver(IPositionChangeObserver observer) { 107 | observerlist.add(observer); 108 | } 109 | 110 | public void removeObserver(IPositionChangeObserver observer) { 111 | observerlist.remove(observer); 112 | } 113 | 114 | private void positionChanged(Vector2d old, Vector2d n, Object a) { 115 | for (IPositionChangeObserver o : observerlist) { 116 | o.positionChanged(old, n, a); 117 | } 118 | } 119 | 120 | //OTHER 121 | 122 | @Override 123 | public String toString() { 124 | return energy == 0 ? "X" : this.direction.toString(); 125 | } 126 | 127 | 128 | //COPULATION 129 | 130 | public Animal copulation(Animal mother) { 131 | 132 | int childEnergy = (int) (0.25 * mother.energy) + (int) (this.energy * 0.25); 133 | mother.changeEnergy((int) -(0.25 * mother.energy)); 134 | this.changeEnergy((int) -(this.energy * 0.25)); 135 | 136 | Animal child = new Animal(map, mother.getPosition(), childEnergy); 137 | child.genes = new Genes(this.genes, mother.genes); 138 | 139 | return child; 140 | } 141 | 142 | @Override 143 | public Color toColor() { 144 | if (energy == 0) return new Color(222, 221, 224); 145 | if (energy < 0.2 * startEnergy) return new Color(224, 179, 173); 146 | if (energy < 0.4 * startEnergy) return new Color(224, 142, 127); 147 | if (energy < 0.6 * startEnergy) return new Color(201, 124, 110); 148 | if (energy < 0.8 * startEnergy) return new Color(182, 105, 91); 149 | if (energy < startEnergy) return new Color(164, 92, 82); 150 | if (energy < 2 * startEnergy) return new Color(146, 82, 73); 151 | if (energy < 4 * startEnergy) return new Color(128, 72, 64); 152 | if (energy < 6 * startEnergy) return new Color(119, 67, 59); 153 | if (energy < 8 * startEnergy) return new Color(88, 50, 44); 154 | if (energy < 10 * startEnergy) return new Color(74, 42, 37); 155 | return new Color(55, 31, 027); 156 | } 157 | 158 | 159 | } 160 | -------------------------------------------------------------------------------- /Classes/Genes.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Classes; 2 | 3 | import java.util.Arrays; 4 | 5 | //alias in comments: DNA 6 | public class Genes { 7 | 8 | private int[] genes; 9 | private int size; 10 | private int numOfGenes; 11 | 12 | public Genes(int numOfGenes, int size) { 13 | genes = new int[size]; 14 | this.size = size; 15 | this.numOfGenes = numOfGenes; 16 | fillRandom(); 17 | makeProprielyGen(); 18 | } 19 | 20 | public Genes(Genes g) { 21 | this(g.getNumOfGenes(), g.getSize()); 22 | genes = Arrays.copyOf(g.getGenes(), size); 23 | } 24 | 25 | public Genes(Genes g1, Genes g2) { 26 | this(g1.getNumOfGenes(), g1.getSize()); 27 | 28 | if (g1.getSize() != g2.getSize()) throw new IllegalArgumentException("Gens have different sizes"); 29 | if (g1.getNumOfGenes() != g2.getNumOfGenes()) 30 | throw new IllegalArgumentException("Gens have different range of values"); 31 | 32 | //random places to div DNA 33 | int firstPlaceToDiv = (int) (Math.random() * (size - 1)); 34 | int secondPlaceToDiv = firstPlaceToDiv; 35 | while (secondPlaceToDiv == firstPlaceToDiv) { 36 | secondPlaceToDiv = (int) (Math.random() * (size - 1)); 37 | } 38 | if (firstPlaceToDiv > secondPlaceToDiv) { 39 | int tmp = firstPlaceToDiv; 40 | firstPlaceToDiv = secondPlaceToDiv; 41 | secondPlaceToDiv = tmp; 42 | } 43 | 44 | //FILLING GENES BY 2 PARTS OF FIRST PARENT'S DNA AND 1 PART OF SECOND PARENT'S DNA 45 | for (int i = 0; i <= firstPlaceToDiv; i++) { 46 | genes[i] = g1.getGenes()[i]; 47 | } 48 | for (int i = firstPlaceToDiv + 1; i <= secondPlaceToDiv; i++) { 49 | genes[i] = g2.getGenes()[i]; 50 | } 51 | for (int i = secondPlaceToDiv; i < size; i++) { 52 | genes[i] = g1.getGenes()[i]; 53 | } 54 | 55 | //REPAIR GENES, THERE IS A CHANCE THAT SOME GENS FROM RANGE AREN'T EXIST IN CHILD GENES 56 | makeProprielyGen(); 57 | 58 | } 59 | 60 | 61 | public int getNumOfGenes() { 62 | return this.numOfGenes; 63 | } 64 | 65 | public int getSize() { 66 | return this.size; 67 | } 68 | 69 | public int[] getGenes() { 70 | return genes; 71 | } 72 | 73 | private void fillRandom() { 74 | for (int i = 0; i < size; i++) { 75 | genes[i] = (int) (Math.random() * (numOfGenes)); 76 | } 77 | Arrays.sort(genes); 78 | } 79 | 80 | private void makeProprielyGen() { 81 | boolean flag = true; 82 | while (flag) { 83 | flag = false; 84 | 85 | boolean[] isInGens = new boolean[numOfGenes + 1]; 86 | 87 | for (int i = 0; i < numOfGenes; i++) { 88 | isInGens[i] = false; 89 | } 90 | for (int i = 0; i < size; i++) { 91 | isInGens[this.genes[i]] = true; 92 | } 93 | for (int i = 0; i < numOfGenes; i++) { 94 | if (!isInGens[i]) { 95 | flag = true; 96 | } 97 | } 98 | 99 | if (flag) { 100 | for (int i = 0; i < numOfGenes; i++) { 101 | if (!isInGens[i]) { 102 | genes[(int) (Math.random() * (size))] = i; 103 | } 104 | } 105 | } 106 | } 107 | 108 | Arrays.sort(genes); 109 | } 110 | 111 | public int returnRandomGen() { 112 | int rand = (int) (Math.random() * (size)); 113 | return genes[rand]; 114 | } 115 | 116 | @Override 117 | public String toString() { 118 | String result = ""; 119 | for (int i = 0; i < size; i++) { 120 | result = result + " " + Integer.toString(genes[i]); 121 | } 122 | return result; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Classes/Grass.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Classes; 2 | 3 | import agh.cs.po.Interfaces.IMapElement; 4 | import agh.cs.po.EnumClasses.MoveDirection; 5 | import agh.cs.po.Interfaces.IPositionChangeObserver; 6 | 7 | import java.awt.*; 8 | 9 | public class Grass implements IMapElement { 10 | 11 | protected Vector2d position; 12 | 13 | public Vector2d getPosition() { 14 | return this.position; 15 | } 16 | 17 | public Grass(Vector2d position) { 18 | this.position = position; 19 | } 20 | 21 | public boolean isMovable() { 22 | return false; 23 | } 24 | 25 | 26 | public void move(MoveDirection d) { 27 | } 28 | 29 | public void addObserver(IPositionChangeObserver observer) { 30 | return; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "*"; 36 | } 37 | 38 | @Override 39 | public Color toColor() { 40 | return new Color(67, 222, 31); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Classes/Vector2d.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Classes; 2 | 3 | public class Vector2d { 4 | public final int x; 5 | public final int y; 6 | 7 | public Vector2d(int x, int y) { 8 | this.x = x; 9 | this.y = y; 10 | } 11 | 12 | 13 | @Override 14 | public String toString() { 15 | return "(" + Integer.toString(this.x) + "," + Integer.toString(this.y) + ")"; 16 | } 17 | 18 | public boolean precedes(Vector2d other) { 19 | if (this.x <= other.x && this.y <= other.y) { 20 | return true; 21 | } 22 | return false; 23 | } 24 | 25 | public boolean follows(Vector2d other) { 26 | if (this.x >= other.x && this.y >= other.y) { 27 | return true; 28 | } 29 | return false; 30 | } 31 | 32 | public Vector2d upperRight(Vector2d other) { 33 | if (other == null) return this; 34 | int xn = this.x >= other.x ? this.x : other.x; 35 | 36 | int yn = this.y >= other.y ? this.y : other.y; 37 | return new Vector2d(xn, yn); 38 | } 39 | 40 | public Vector2d lowerLeft(Vector2d other) { 41 | if (other == null) return this; 42 | int xn = Math.min(other.x, this.x); 43 | int yn = Math.min(other.y, this.y); 44 | 45 | return new Vector2d(xn, yn); 46 | } 47 | 48 | public Vector2d add(Vector2d other) { 49 | return new Vector2d(this.x + other.x, this.y + other.y); 50 | } 51 | 52 | public Vector2d subtract(Vector2d other) { 53 | return new Vector2d(this.x - other.x, this.y - other.y); 54 | } 55 | 56 | public boolean equals(Object other) { 57 | if (this == other) 58 | return true; 59 | if (!(other instanceof Vector2d)) 60 | return false; 61 | Vector2d that = (Vector2d) other; 62 | return that.x == this.x && that.y == this.y; 63 | } 64 | 65 | public Vector2d opposite() { 66 | return new Vector2d(-1 * this.x, -1 * this.y); 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | int hash = 13; 72 | hash += this.x * 31; 73 | hash += this.y * 17; 74 | return hash; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /DarwinWorld/PropertiesLoader.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.DarwinWorld; 2 | import com.google.gson.Gson; 3 | 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | 8 | public class PropertiesLoader { 9 | 10 | private int mapWidth; 11 | private int mapHeight; 12 | private int jungleWidth; 13 | private int jungleHeight; 14 | private int grassEatingEnergyProfit; 15 | private int dayEnergyCost; 16 | private int copulationMinimumEnergy; 17 | private int animalsStartEnergy; 18 | private int numOfSpawnedAnimals; 19 | private int delay; 20 | private int grassSpawnedInEachDay; 21 | 22 | 23 | static public PropertiesLoader loadPropFromFile() throws FileNotFoundException,IllegalArgumentException { 24 | Gson gson = new Gson(); 25 | File f = new File(""); 26 | System.out.println(f.getAbsolutePath()); 27 | PropertiesLoader properties = (PropertiesLoader)gson.fromJson(new FileReader("src\\main\\agh\\cs\\po\\DarwinWorld\\config.json"), PropertiesLoader.class); 28 | properties.validate(); 29 | return properties; 30 | } 31 | 32 | public void validate() throws IllegalArgumentException{ 33 | if(this.mapWidth <= 0){ throw new IllegalArgumentException("Invalid map width");} 34 | if(this.mapHeight <= 0){ throw new IllegalArgumentException("Invalid map height");} 35 | if(this.jungleHeight <= 0){ throw new IllegalArgumentException("Invalid jungle width");} 36 | if(this.jungleWidth<= 0){ throw new IllegalArgumentException("Invalid jungle height");} 37 | if(this.copulationMinimumEnergy <= 0){ throw new IllegalArgumentException("Invalid copulationMinimumEnergy");} 38 | if(this.animalsStartEnergy < 0){ throw new IllegalArgumentException("Invalid animalsStartEnergy");} 39 | if(this.numOfSpawnedAnimals < 0){ throw new IllegalArgumentException("Invalid numOfSpawnedAnimals");} 40 | if(this.grassSpawnedInEachDay < 0){ throw new IllegalArgumentException("Invalid grassSpawnedInEachDay");} 41 | 42 | } 43 | 44 | public int getMapWidth() { 45 | return mapWidth; 46 | } 47 | 48 | public void setMapWidth(int mapWidth) { 49 | this.mapWidth = mapWidth; 50 | } 51 | 52 | public int getMapHeight() { 53 | return mapHeight; 54 | } 55 | 56 | public void setMapHeight(int mapHeight) { 57 | this.mapHeight = mapHeight; 58 | } 59 | 60 | public int getJungleWidth() { 61 | return jungleWidth; 62 | } 63 | 64 | public void setJungleWidth(int jungleWidth) { 65 | this.jungleWidth = jungleWidth; 66 | } 67 | 68 | public int getJungleHeight() { 69 | return jungleHeight; 70 | } 71 | 72 | public void setJungleHeight(int jungleHeight) { 73 | this.jungleHeight = jungleHeight; 74 | } 75 | 76 | public int getGrassEatingEnergyProfit() { 77 | return grassEatingEnergyProfit; 78 | } 79 | 80 | public void setGrassEatingEnergyProfit(int grassEatingEnergyProfit) { 81 | this.grassEatingEnergyProfit = grassEatingEnergyProfit; 82 | } 83 | 84 | public int getDayEnergyCost() { 85 | return dayEnergyCost; 86 | } 87 | 88 | public void setDayEnergyCost(int dayEnergyCost) { 89 | this.dayEnergyCost = dayEnergyCost; 90 | } 91 | 92 | public int getCopulationMinimumEnergy() { 93 | return copulationMinimumEnergy; 94 | } 95 | 96 | public void setCopulationMinimumEnergy(int copulationMinimumEnergy) { 97 | this.copulationMinimumEnergy = copulationMinimumEnergy; 98 | } 99 | 100 | public int getAnimalsStartEnergy() { 101 | return animalsStartEnergy; 102 | } 103 | 104 | public void setAnimalsStartEnergy(int animalsStartEnergy) { 105 | this.animalsStartEnergy = animalsStartEnergy; 106 | } 107 | 108 | public int getNumOfSpawnedAnimals() { 109 | return numOfSpawnedAnimals; 110 | } 111 | 112 | public void setNumOfSpawnedAnimals(int numOfSpawnedAnimals) { 113 | this.numOfSpawnedAnimals = numOfSpawnedAnimals; 114 | } 115 | 116 | public int getDelay() { 117 | return delay; 118 | } 119 | 120 | public void setDelay(int delay) { 121 | this.delay = delay; 122 | } 123 | 124 | public int getGrassSpawnedInEachDay() { 125 | return grassSpawnedInEachDay; 126 | } 127 | 128 | public void setGrassSpawnedInEachDay(int grassSpawnedInEachDay) { 129 | this.grassSpawnedInEachDay = grassSpawnedInEachDay; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /DarwinWorld/SteppeJungleMap.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.DarwinWorld; 2 | 3 | import agh.cs.po.Classes.Vector2d; 4 | import agh.cs.po.Classes.Animal; 5 | import agh.cs.po.EnumClasses.MoveDirection; 6 | import agh.cs.po.Interfaces.IWorldMap; 7 | import agh.cs.po.Classes.Grass; 8 | import agh.cs.po.Interfaces.IMapElement; 9 | import agh.cs.po.Interfaces.IPositionChangeObserver; 10 | 11 | import java.util.*; 12 | 13 | public class SteppeJungleMap implements IWorldMap, IPositionChangeObserver { 14 | 15 | //map properties 16 | 17 | //size 18 | private final Vector2d upperRight; 19 | private final Vector2d lowerLeft; 20 | private final Vector2d lowerLeftJungle; 21 | private final Vector2d upperRightJungle; 22 | public final int jungleWidth; 23 | public final int jungleHeight; 24 | public int width; 25 | public int height; 26 | 27 | //eating 28 | private int grassProfit; 29 | private int dayCost; 30 | private int startAnimalsEnergy; 31 | //copulation 32 | private final int energyLimitToCopulation; 33 | 34 | //map elements 35 | public Map grass = new HashMap<>(); 36 | public Map> animals = new HashMap<>(); 37 | public LinkedList animalsList; 38 | public LinkedList grassList; 39 | 40 | public SteppeJungleMap(int width, int height, int jungleWidth, int jungleHeight, int grassProfit, int dayCost, int energyLimitToCopulation, int startAnimalsEnergy) { 41 | this.startAnimalsEnergy = startAnimalsEnergy; 42 | this.grassList = new LinkedList<>(); 43 | this.animalsList = new LinkedList<>(); 44 | this.energyLimitToCopulation = energyLimitToCopulation; 45 | this.grassProfit = grassProfit; 46 | this.dayCost = (-1) * dayCost; 47 | this.lowerLeft = new Vector2d(0, 0); 48 | this.upperRight = new Vector2d(width - 1, height - 1); 49 | this.width = width; 50 | this.height = height; 51 | this.jungleWidth = jungleWidth; 52 | this.jungleHeight = jungleHeight; 53 | 54 | //default cords of jungle's corners 55 | int lljx = 0; //LOWER LEFT JUNGLE X 56 | int lljy = 0; //LOWER LEFT JUNGLE y 57 | int urjx = width - 1; //UPPER RIGHT JUNGLE x 58 | int urjy = height - 1; //UPPER RIGHT JUNGLE y 59 | 60 | 61 | //calculating jungle's position 62 | for (int i = 0; i < (width - jungleWidth); i++) { 63 | if (i % 2 == 0) { 64 | lljx++; 65 | } else { 66 | urjx--; 67 | } 68 | } 69 | 70 | for (int i = 0; i < (height - jungleHeight); i++) { 71 | if (i % 2 == 0) { 72 | lljy++; 73 | } else { 74 | urjy--; 75 | } 76 | } 77 | 78 | this.lowerLeftJungle = new Vector2d(lljx, lljy); 79 | this.upperRightJungle = new Vector2d(urjx, urjy); 80 | 81 | } 82 | 83 | 84 | public Vector2d toNoBoundedPosition(Vector2d position) { 85 | int newX; 86 | int newY; 87 | 88 | if (position.x < lowerLeft.x) { 89 | newX = (width - Math.abs(position.x % width)) % width; 90 | } else { 91 | newX = Math.abs(position.x % width); 92 | } 93 | if (position.y < lowerLeft.y) { 94 | newY = (height - Math.abs(position.y % height)) % height; 95 | } else { 96 | newY = Math.abs(position.y % height); 97 | } 98 | 99 | return new Vector2d(newX, newY); 100 | } 101 | 102 | @Override 103 | public boolean place(IMapElement e) { 104 | //we can place maximum 3 animals on one field, to change it, change this code 105 | Vector2d position = toNoBoundedPosition(e.getPosition()); 106 | 107 | if (!canPlace(position)) { 108 | throw new IllegalArgumentException("Field " + e.getPosition() + " is full"); 109 | 110 | } else { 111 | if (e instanceof Grass) { 112 | if (grass.get(position) == null) 113 | grass.put(position, (Grass) e); 114 | grassList.add((Grass) e); 115 | } 116 | if (e instanceof Animal) { 117 | addAnimal((Animal) e, position); 118 | animalsList.add((Animal) e); 119 | e.addObserver(this); 120 | } 121 | 122 | } 123 | return true; 124 | } 125 | 126 | // removing from hashMap if you want definitely remove animal you should in addition remove its Observer, It is just use to moving animals 127 | private boolean removeAnimal(Animal a, Vector2d position2) { 128 | Vector2d position = toNoBoundedPosition(position2); 129 | LinkedList l = animals.get(position); 130 | if (l == null) 131 | throw new IllegalArgumentException("Animal" + a.getPosition() + " -> " + position + " already not exist in the map"); 132 | else if (l.size() == 0) 133 | throw new IllegalArgumentException("Animal" + a.getPosition() + " already not exist in the map empty list"); 134 | else { 135 | l.remove(a); 136 | if (l.size() == 0) { 137 | animals.remove(position); 138 | } 139 | } 140 | return true; 141 | } 142 | 143 | // adding to hashMap if you want totally add animal you should add its Observer, It is just use to moving animals 144 | private boolean addAnimal(Animal a, Vector2d p) { 145 | if (a == null) return false; 146 | Vector2d pos = toNoBoundedPosition(p); 147 | LinkedList l = animals.get(pos); 148 | if (l == null) { 149 | LinkedList tmp = new LinkedList<>(); 150 | tmp.add(a); 151 | animals.put(pos, tmp); 152 | 153 | } else if (l != null) { 154 | l.add(a); 155 | } 156 | return true; 157 | 158 | } 159 | 160 | 161 | @Override 162 | public boolean isOccupied(Vector2d position2) { 163 | return objectAt(position2) != null; 164 | } 165 | 166 | @Override 167 | public Object objectAt(Vector2d position2) { 168 | Vector2d position = toNoBoundedPosition(position2); 169 | LinkedList l = animals.get(position); 170 | if (l == null) return grass.get(position); 171 | else if (l.size() == 0) return grass.get(position); 172 | else return l.getFirst(); 173 | } 174 | 175 | @Override 176 | public boolean canMoveTo(Vector2d position2) { 177 | //checking place have there 2 animals already 178 | Vector2d position = toNoBoundedPosition(position2); 179 | if (animals.get(position) == null) return true; 180 | if (animals.get(position).size() < 2) return true; 181 | return false; 182 | } 183 | 184 | public boolean canPlace(Vector2d position2) { 185 | //checking place have there 3 animals already 186 | Vector2d position = toNoBoundedPosition(position2); 187 | if (animals.get(position) == null) return true; 188 | if (animals.get(position).size() < 3) return true; 189 | return false; 190 | } 191 | 192 | public void eating() { 193 | LinkedList toRemoveAfterEating = new LinkedList<>(); 194 | 195 | for (Grass food : grass.values()) { 196 | LinkedList l = animals.get(food.getPosition()); 197 | if (l != null) { 198 | if (l.size() > 0) { 199 | for (Animal a : l) { 200 | a.changeEnergy(grassProfit / l.size()); 201 | toRemoveAfterEating.add(food); 202 | } 203 | } 204 | } 205 | } 206 | 207 | for (Grass g : toRemoveAfterEating) { 208 | grass.remove(g.getPosition()); 209 | grassList.remove(g); 210 | 211 | } 212 | 213 | } 214 | 215 | public void moveRandomAllAnimals() { 216 | LinkedList l = getAnimals(); 217 | for (int i = 0; i < l.size(); i++) { 218 | animalsList.get(i).rotate(); 219 | animalsList.get(i).move(MoveDirection.FORWARD); 220 | } 221 | } 222 | 223 | public void copulation() { 224 | for (LinkedList animalList : animals.values()) { 225 | if (animalList != null) { 226 | if (animalList.size() == 2) { 227 | Animal mother = animalList.get(0); 228 | Animal father = animalList.get(1); 229 | if (mother.energy >= energyLimitToCopulation) 230 | if (father.energy >= energyLimitToCopulation) { 231 | Animal child = father.copulation(mother); 232 | place(child); 233 | } 234 | } 235 | } 236 | } 237 | } 238 | 239 | public void nextDay() { 240 | for (LinkedList animalList : animals.values()) { 241 | if (animalList != null) { 242 | if (animalList.size() > 0) { 243 | for (Animal a : animalList) { 244 | a.changeEnergy(dayCost); 245 | } 246 | } 247 | } 248 | } 249 | } 250 | 251 | public void removeDeadAnimals() { 252 | LinkedList l = getAnimals(); 253 | for (int i = 0; i < l.size(); i++) { 254 | Animal a = animalsList.get(i); 255 | if (a.isDead()) { 256 | removeAnimal(a, a.getPosition()); 257 | a.removeObserver(this); 258 | animalsList.remove(a); 259 | } 260 | } 261 | } 262 | 263 | public boolean addAnimalOnRandomField() { 264 | 265 | int toMuchTimes = 0; 266 | while (toMuchTimes < width * height * 2) { 267 | Vector2d position = new Vector2d((int) (Math.random() * (width) + lowerLeft.x), (int) (Math.random() * (height) + lowerLeft.y)); 268 | if (canPlace(position)) { 269 | place(new Animal(this, position, startAnimalsEnergy)); 270 | return true; 271 | } 272 | toMuchTimes++; 273 | } 274 | return false; 275 | } 276 | 277 | public boolean placeAnimalToRandomFieldInJungle() { 278 | int jungleSize = jungleWidth * jungleHeight; 279 | int mapSize = height * width; 280 | int steppeSize = mapSize - jungleSize; 281 | 282 | int toMuchTimes = 0; 283 | while ((double) toMuchTimes < (double) 2 * ((double) jungleSize / (double) steppeSize) * mapSize) { 284 | 285 | Vector2d position = new Vector2d((int) (Math.random() * (jungleWidth) + lowerLeftJungle.x), (int) (Math.random() * (jungleHeight) + lowerLeftJungle.y)); 286 | if (canPlace(position)) { 287 | place(new Animal(this, position, startAnimalsEnergy)); 288 | return true; 289 | } 290 | toMuchTimes++; 291 | } 292 | return false; 293 | } 294 | 295 | 296 | public boolean positionChanged(Vector2d oldPosition2, Vector2d newPosition2, Object a) { 297 | 298 | Vector2d oldPosition = toNoBoundedPosition(oldPosition2); 299 | Vector2d newPosition = toNoBoundedPosition(newPosition2); 300 | 301 | if (canMoveTo(newPosition)) { 302 | 303 | removeAnimal((Animal) a, oldPosition); 304 | addAnimal((Animal) a, newPosition); 305 | return true; 306 | } 307 | return false; 308 | } 309 | 310 | public void spawnGrass() { 311 | 312 | //For Jungle 313 | 314 | int jungleSize = jungleWidth * jungleHeight; 315 | int mapSize = height * width; 316 | int steppeSize = mapSize - jungleSize; 317 | int toMuchTimes = 0; 318 | // stop looking for free place for grass in jungle, following to uniform probability distribution: after (size of jungle) times we should find free position 319 | //but if we didn't we can stop and meaning that jungle fields are close to be full of grass. 320 | while (toMuchTimes < 2 * jungleSize) { 321 | 322 | //random position in jungle 323 | Vector2d newGrass = new Vector2d((int) (Math.random() * (jungleWidth) + lowerLeftJungle.x), (int) (Math.random() * (jungleHeight) + lowerLeftJungle.y)); 324 | if (grass.get(newGrass) == null && canPlace(newGrass)) { 325 | place(new Grass(newGrass)); 326 | break; 327 | } 328 | toMuchTimes++; 329 | } 330 | 331 | //For Steppe 332 | 333 | toMuchTimes = 0; 334 | // stop looking for free place for grass in steppe, following to uniform probability distribution: after (size of steppe) times we should find free position 335 | //but if we didn't we can stop and be sure that steppe fields are close to be full of grass. 336 | while ((double) toMuchTimes < (double) 2 * ((double) jungleSize / (double) steppeSize) * mapSize) { 337 | 338 | Vector2d newGrass = new Vector2d((int) (Math.random() * (width) + lowerLeft.x), (int) (Math.random() * (height) + lowerLeft.y)); 339 | if (grass.get(newGrass) == null && canPlace(newGrass) && !(newGrass.follows(lowerLeftJungle) && newGrass.precedes(upperRightJungle))) { 340 | place(new Grass(newGrass)); 341 | break; 342 | } 343 | toMuchTimes++; 344 | } 345 | } 346 | 347 | public String toString() { 348 | return "SteppeJungleMap"; 349 | } 350 | 351 | 352 | public LinkedList getAnimals() { 353 | return animalsList; 354 | } 355 | 356 | public LinkedList getGrass() { 357 | return grassList; 358 | } 359 | 360 | public Vector2d getJungleLowerLeft() { 361 | return lowerLeftJungle; 362 | } 363 | 364 | } 365 | -------------------------------------------------------------------------------- /DarwinWorld/World.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.DarwinWorld; 2 | 3 | import agh.cs.po.Menu.SettingsMenu; 4 | 5 | import java.io.FileNotFoundException; 6 | 7 | public class World { 8 | 9 | public static void main(String[] args) { 10 | 11 | try { 12 | 13 | PropertiesLoader properties = PropertiesLoader.loadPropFromFile(); 14 | 15 | Integer[] defaultMapProperties = { 16 | properties.getMapWidth(), 17 | properties.getMapHeight(), 18 | properties.getJungleWidth(), 19 | properties.getJungleHeight(), 20 | properties.getGrassEatingEnergyProfit(), 21 | properties.getDayEnergyCost(), 22 | properties.getCopulationMinimumEnergy(), 23 | properties.getAnimalsStartEnergy(), 24 | properties.getNumOfSpawnedAnimals(), 25 | properties.getDelay(), 26 | properties.getGrassSpawnedInEachDay() 27 | }; 28 | //SettingsMenu constructor start animation 29 | SettingsMenu menu = new SettingsMenu(); 30 | menu.startSimulation(defaultMapProperties); 31 | 32 | } catch (IllegalArgumentException ex) { 33 | System.out.println(ex); 34 | return; 35 | } 36 | catch (FileNotFoundException ex) { 37 | System.out.println(ex); 38 | return; 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /DarwinWorld/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "mapWidth": 30, 3 | "mapHeight": 30, 4 | "jungleWidth": 10, 5 | "jungleHeight": 10, 6 | "grassEatingEnergyProfit": 15, 7 | "dayEnergyCost": 1, 8 | "copulationMinimumEnergy": 15, 9 | "animalsStartEnergy": 40, 10 | "numOfSpawnedAnimals": 10, 11 | "delay": 10, 12 | "grassSpawnedInEachDay": 4 13 | 14 | } -------------------------------------------------------------------------------- /EnumClasses/MapDirection.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.EnumClasses; 2 | 3 | import agh.cs.po.Classes.Vector2d; 4 | 5 | public enum MapDirection { 6 | NORTH, SOUTH, WEST, EAST, NORTHWEST, SOUTHWEST, NORTHEAST, SOUTHEAST; 7 | 8 | public String toString() { 9 | 10 | switch (this) { 11 | case NORTH: 12 | return "↑"; 13 | case SOUTH: 14 | return "↓"; 15 | case WEST: 16 | return "←"; 17 | case EAST: 18 | return "→"; 19 | case NORTHWEST: 20 | return "↖"; 21 | case SOUTHWEST: 22 | return "↙"; 23 | case NORTHEAST: 24 | return "↗"; 25 | case SOUTHEAST: 26 | return "↘"; 27 | //no need for default 28 | } 29 | return null; 30 | } 31 | 32 | public MapDirection next() { 33 | switch (this) { 34 | case NORTH: 35 | return NORTHEAST; 36 | case SOUTH: 37 | return SOUTHWEST; 38 | case WEST: 39 | return NORTHWEST; 40 | case EAST: 41 | return SOUTHEAST; 42 | case NORTHWEST: 43 | return NORTH; 44 | case SOUTHWEST: 45 | return WEST; 46 | case NORTHEAST: 47 | return EAST; 48 | case SOUTHEAST: 49 | return SOUTH; 50 | //no need for default 51 | } 52 | return null; 53 | } 54 | 55 | public MapDirection previous() { 56 | switch (this) { 57 | case NORTH: 58 | return NORTHWEST; 59 | case SOUTH: 60 | return SOUTHEAST; 61 | case WEST: 62 | return SOUTHWEST; 63 | case EAST: 64 | return NORTHEAST; 65 | case NORTHWEST: 66 | return WEST; 67 | case SOUTHWEST: 68 | return SOUTH; 69 | case NORTHEAST: 70 | return NORTH; 71 | case SOUTHEAST: 72 | return EAST; 73 | //no need for default 74 | } 75 | return null; 76 | } 77 | 78 | public Vector2d toUnitVector() { 79 | switch (this) { 80 | case NORTH: 81 | return new Vector2d(0, 1); 82 | case SOUTH: 83 | return new Vector2d(0, -1); 84 | case WEST: 85 | return new Vector2d(-1, 0); 86 | case EAST: 87 | return new Vector2d(1, 0); 88 | case NORTHWEST: 89 | return new Vector2d(-1, 1); 90 | case SOUTHWEST: 91 | return new Vector2d(-1, -1); 92 | case NORTHEAST: 93 | return new Vector2d(1, 1); 94 | case SOUTHEAST: 95 | return new Vector2d(1, -1); 96 | //no need for default 97 | } 98 | return null; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /EnumClasses/MoveDirection.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.EnumClasses; 2 | 3 | public enum MoveDirection { 4 | FORWARD, BACKWARD, RIGHT, LEFT; 5 | } 6 | -------------------------------------------------------------------------------- /Interfaces/IMapElement.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Interfaces; 2 | 3 | import agh.cs.po.Classes.Vector2d; 4 | import agh.cs.po.EnumClasses.MoveDirection; 5 | 6 | import java.awt.*; 7 | 8 | public interface IMapElement { 9 | /** 10 | * standard 2D position of element 11 | * position param should const every class implements IMapElement 12 | */ 13 | Vector2d getPosition(); 14 | 15 | 16 | /** 17 | * Its 18 | * 19 | * @return true if elements will use move function to move, else should return false. 20 | */ 21 | boolean isMovable(); 22 | 23 | 24 | /** 25 | * If element is not movable you should implement empty move function. 26 | * 27 | * @param d to specialize direction to move 28 | */ 29 | void move(MoveDirection d); 30 | 31 | void addObserver(IPositionChangeObserver observer); 32 | 33 | Color toColor(); 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Interfaces/IPositionChangeObserver.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Interfaces; 2 | 3 | import agh.cs.po.Classes.Vector2d; 4 | 5 | public interface IPositionChangeObserver { 6 | boolean positionChanged(Vector2d oldPosition, Vector2d newPosition, Object o); 7 | } 8 | -------------------------------------------------------------------------------- /Interfaces/IWorldMap.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Interfaces; 2 | 3 | import agh.cs.po.Classes.Vector2d; 4 | 5 | /** 6 | * The interface responsible for interacting with the map of the world. 7 | * Assumes that Vector2d and MoveDirection classes are defined. 8 | * 9 | * @author apohllo 10 | */ 11 | public interface IWorldMap { 12 | /** 13 | * Indicate if any object can move to the given position. 14 | * 15 | * @param position The position checked for the movement possibility. 16 | * @return True if the object can move to that position. 17 | */ 18 | boolean canMoveTo(Vector2d position); 19 | 20 | /** 21 | * Place a animal on the map. 22 | * 23 | * @param animal The animal to place on the map. 24 | * @return True if the animal was placed. The animal cannot be placed if the map is already occupied. 25 | */ 26 | boolean place(IMapElement animal); 27 | 28 | 29 | /** 30 | * Return true if given position on the map is occupied. Should not be 31 | * confused with canMove since there might be empty positions where the animal 32 | * cannot move. 33 | * 34 | * @param position Position to check. 35 | * @return True if the position is occupied. 36 | */ 37 | boolean isOccupied(Vector2d position); 38 | 39 | /** 40 | * Return an object at a given position. 41 | * 42 | * @param position The position of the object. 43 | * @return Object or null if the position is not occupied. 44 | */ 45 | Object objectAt(Vector2d position); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Menu/SettingsMenu.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Menu; 2 | 3 | import javax.swing.*; 4 | 5 | public class SettingsMenu { 6 | public JFrame menuFrame; 7 | 8 | public SettingsMenu() { 9 | 10 | menuFrame = new JFrame("Evolution Simulator (Settings)"); 11 | menuFrame.setSize(500, 500); 12 | menuFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 13 | menuFrame.setLocationRelativeTo(null); 14 | 15 | } 16 | public void startSimulation(Integer[] defaultMapProperties){ 17 | menuFrame.add(new SettingsPanel(defaultMapProperties)); 18 | menuFrame.setVisible(true); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Menu/SettingsPanel.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Menu; 2 | 3 | import agh.cs.po.DarwinWorld.SteppeJungleMap; 4 | import agh.cs.po.Visualization.MapSimulation; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | 11 | public class SettingsPanel extends JPanel implements ActionListener { 12 | // 13 | public static final int HEIGHT = 600; 14 | public static final int WIDTH = 600; 15 | //Fields for data entry 16 | private JTextField delay; 17 | private JTextField animalsStartEnergy; 18 | private JTextField copulationMinimumEnergy; 19 | private JTextField numOfSpawnedAnimals; 20 | private JTextField grassEatingEnergyProfit; 21 | private JTextField mapWidth; 22 | private JTextField mapHeight; 23 | private JTextField jungleWidth; 24 | private JTextField jungleHeight; 25 | private JTextField dayEnergyCost; 26 | private JTextField grassSpawnedInEachDay; 27 | //Labels to identify the fields 28 | private JLabel delayLabel; 29 | private JLabel animalsStartEnergyLabel; 30 | private JLabel copulationMinimumEnergyLabel; 31 | private JLabel numOfSpawnedAnimalsLabel; 32 | private JLabel grassEatingEnergyProfitLabel; 33 | private JLabel mapWidthLabel; 34 | private JLabel mapHeightLabel; 35 | private JLabel jungleWidthLabel; 36 | private JLabel jungleHeightLabel; 37 | private JLabel dayEnergyCostLabel; 38 | private JLabel grassSpawnedInEachDayLabel; 39 | //button 40 | private JButton startButton; 41 | 42 | public SettingsPanel(Integer[] defaultMapProperties) { 43 | setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 44 | setPreferredSize(new Dimension(WIDTH, HEIGHT)); 45 | 46 | startButton = new JButton("Start Simulation"); 47 | startButton.addActionListener(this); 48 | 49 | //LABELS 50 | delayLabel = new JLabel("Real refresh time (ms): "); 51 | animalsStartEnergyLabel = new JLabel("Animal start energy: "); 52 | copulationMinimumEnergyLabel = new JLabel("Minimum energy to copulation: "); 53 | numOfSpawnedAnimalsLabel = new JLabel("Animals spawning at the start: "); 54 | grassEatingEnergyProfitLabel = new JLabel("Grass energy profit: "); 55 | mapHeightLabel = new JLabel("Map height: "); 56 | mapWidthLabel = new JLabel("Map width: "); 57 | jungleWidthLabel = new JLabel("Jungle width: "); 58 | jungleHeightLabel = new JLabel("Jungle height: "); 59 | dayEnergyCostLabel = new JLabel("Daily energy cost: "); 60 | grassSpawnedInEachDayLabel = new JLabel("Grass spawned in each day "); 61 | //TEXT FIELDS 62 | int a = 10; 63 | delay = new JTextField(); 64 | delay.setColumns(a); 65 | delay.setText(defaultMapProperties[9].toString()); 66 | 67 | animalsStartEnergy = new JTextField(); 68 | animalsStartEnergy.setColumns(a); 69 | animalsStartEnergy.setText(defaultMapProperties[7].toString()); 70 | 71 | copulationMinimumEnergy = new JTextField(); 72 | copulationMinimumEnergy.setColumns(a); 73 | copulationMinimumEnergy.setText(defaultMapProperties[6].toString()); 74 | 75 | numOfSpawnedAnimals = new JTextField(); 76 | numOfSpawnedAnimals.setColumns(a); 77 | numOfSpawnedAnimals.setText(defaultMapProperties[8].toString()); 78 | 79 | grassEatingEnergyProfit = new JTextField(); 80 | grassEatingEnergyProfit.setColumns(a); 81 | grassEatingEnergyProfit.setText(defaultMapProperties[4].toString()); 82 | 83 | mapHeight = new JTextField(); 84 | mapHeight.setColumns(a); 85 | mapHeight.setText(defaultMapProperties[1].toString()); 86 | 87 | mapWidth = new JTextField(); 88 | mapWidth.setColumns(a); 89 | mapWidth.setText(defaultMapProperties[0].toString()); 90 | 91 | jungleWidth = new JTextField(); 92 | jungleWidth.setColumns(a); 93 | jungleWidth.setText(defaultMapProperties[2].toString()); 94 | 95 | jungleHeight = new JTextField(); 96 | jungleHeight.setColumns(a); 97 | jungleHeight.setText(defaultMapProperties[3].toString()); 98 | 99 | dayEnergyCost = new JTextField(); 100 | dayEnergyCost.setColumns(a); 101 | dayEnergyCost.setText(defaultMapProperties[5].toString()); 102 | 103 | grassSpawnedInEachDay = new JTextField(); 104 | grassSpawnedInEachDay.setColumns(a); 105 | grassSpawnedInEachDay.setText(defaultMapProperties[10].toString()); 106 | 107 | //Labels to text fields 108 | delayLabel.setLabelFor(delay); 109 | animalsStartEnergyLabel.setLabelFor(animalsStartEnergy); 110 | copulationMinimumEnergyLabel.setLabelFor(copulationMinimumEnergy); 111 | numOfSpawnedAnimalsLabel.setLabelFor(numOfSpawnedAnimals); 112 | grassEatingEnergyProfitLabel.setLabelFor(grassEatingEnergyProfit); 113 | mapHeightLabel.setLabelFor(mapHeight); 114 | mapWidthLabel.setLabelFor(mapWidth); 115 | jungleWidthLabel.setLabelFor(jungleWidth); 116 | jungleHeightLabel.setLabelFor(jungleHeight); 117 | dayEnergyCostLabel.setLabelFor(dayEnergyCost); 118 | grassSpawnedInEachDayLabel.setLabelFor(grassSpawnedInEachDay); 119 | 120 | JPanel l1 = new JPanel(); 121 | JPanel l2 = new JPanel(); 122 | JPanel l3 = new JPanel(); 123 | JPanel l4 = new JPanel(); 124 | JPanel l5 = new JPanel(); 125 | JPanel l6 = new JPanel(); 126 | JPanel l7 = new JPanel(); 127 | JPanel l8 = new JPanel(); 128 | JPanel l9 = new JPanel(); 129 | JPanel l10 = new JPanel(); 130 | JPanel l11 = new JPanel(); 131 | 132 | 133 | l1.add(delayLabel); 134 | l2.add(animalsStartEnergyLabel); 135 | l3.add(copulationMinimumEnergyLabel); 136 | l4.add(numOfSpawnedAnimalsLabel); 137 | l5.add(grassEatingEnergyProfitLabel); 138 | l6.add(mapHeightLabel); 139 | l7.add(mapWidthLabel); 140 | l8.add(jungleWidthLabel); 141 | l9.add(jungleHeightLabel); 142 | l10.add(dayEnergyCostLabel); 143 | l11.add(grassSpawnedInEachDayLabel); 144 | 145 | l1.add(delay); 146 | l2.add(animalsStartEnergy); 147 | l3.add(copulationMinimumEnergy); 148 | l4.add(numOfSpawnedAnimals); 149 | l5.add(grassEatingEnergyProfit); 150 | l6.add(mapHeight); 151 | l7.add(mapWidth); 152 | l8.add(jungleWidth); 153 | l9.add(jungleHeight); 154 | l10.add(dayEnergyCost); 155 | l11.add(grassSpawnedInEachDay); 156 | 157 | JPanel buttonPanel = new JPanel(); 158 | buttonPanel.add(startButton); 159 | 160 | add(new JLabel("Map properties")); 161 | add(l6); 162 | add(l7); 163 | add(l8); 164 | add(l9); 165 | add(new JLabel("Energy properties")); 166 | add(l5); 167 | add(l3); 168 | add(l2); 169 | add(l10); 170 | 171 | add(new JLabel("Spawning properties")); 172 | add(l4); 173 | add(l11); 174 | add(new JLabel("Others")); 175 | add(l1); 176 | 177 | add(buttonPanel); 178 | 179 | } 180 | 181 | @Override 182 | public void actionPerformed(ActionEvent e) { 183 | 184 | 185 | SteppeJungleMap map = new SteppeJungleMap( 186 | Integer.parseInt(mapWidth.getText()), 187 | Integer.parseInt(mapHeight.getText()), 188 | Integer.parseInt(jungleWidth.getText()), 189 | Integer.parseInt(jungleHeight.getText()), 190 | Integer.parseInt(grassEatingEnergyProfit.getText()), 191 | Integer.parseInt(dayEnergyCost.getText()), 192 | Integer.parseInt(copulationMinimumEnergy.getText()), 193 | Integer.parseInt(animalsStartEnergy.getText()) 194 | ); 195 | MapSimulation simulation = new MapSimulation( 196 | map, Integer.parseInt(delay.getText()), 197 | Integer.parseInt(numOfSpawnedAnimals.getText()), 198 | Integer.parseInt(grassSpawnedInEachDay.getText())); 199 | simulation.startSimulation(); 200 | 201 | } 202 | } 203 | 204 | -------------------------------------------------------------------------------- /POProject1.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Symulator Ewolucyjny 2 | #### Opis 3 | Jest to symulator mający przedstawić proste zachowanie środowiska. Zwierzęta poruszające sie po mapie 4 | starają się przetrwać zjadając "wyrastającą" cyklicznie trawę, gromadzone są również statystyki 5 | dotyczące całej symulacji takie jak np. liczbeność populacji zwierząt. 6 | #### Background 7 | Projekt został wykonany na zajęcia z programowania obiektowego prowadzone na 8 | Akademii Górniczo-Hutniczej im. Stanisława Staszica w Krakowie na Wydziale 9 | Informatyki,Elektroniki i Telekomiunikacji na keirunku Informatyka. 10 | #### Uruchomienie 11 | Klasa uruchamiająca program nazywa się "World" i znajduje się w folderze 'DarwinWorld' 12 | #### Technologie 13 | Java 13 + Swing 14 | #### Twórcy 15 | Radosław Kopeć 16 | #### Film 17 | https://www.youtube.com/watch?v=4FangGEpwe4&t=16s -------------------------------------------------------------------------------- /Visualization/FunctionPlot.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Visualization; 2 | 3 | public class FunctionPlot { 4 | public int width; 5 | public int height; 6 | public int cpx; 7 | public int cpy; 8 | 9 | FunctionPlot(int width, int height, int cpx, int cpy) { 10 | this.width = width; 11 | this.height = height; 12 | this.cpx = cpx; 13 | this.cpy = cpy; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Visualization/MapSimulation.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Visualization; 2 | 3 | import agh.cs.po.DarwinWorld.SteppeJungleMap; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | 10 | 11 | public class MapSimulation implements ActionListener { 12 | 13 | //simulation options: 14 | public final int delay; 15 | public SteppeJungleMap map; 16 | public int startNumOfAnimals; 17 | public int grassSpawnedInEachDay; 18 | 19 | //simulation necessary: 20 | public JFrame frame; 21 | public RenderPanel renderPanel; 22 | public PlotRenderPanel plotRenderPanel; 23 | public Timer timer; 24 | 25 | 26 | public MapSimulation(SteppeJungleMap map, int delay, int startNumOfAnimals, int grassSpawnedInEachDay) { 27 | 28 | this.map = map; 29 | this.delay = delay; 30 | this.startNumOfAnimals = startNumOfAnimals; 31 | this.grassSpawnedInEachDay = grassSpawnedInEachDay; 32 | 33 | timer = new Timer(delay, this); 34 | 35 | frame = new JFrame("Evolution Simulator"); 36 | frame.setSize(1000, 1000); 37 | frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 38 | frame.setLocationRelativeTo(null); 39 | frame.setVisible(true); 40 | 41 | renderPanel = new RenderPanel(map, this); 42 | renderPanel.setSize(new Dimension(1, 1)); 43 | 44 | plotRenderPanel = new PlotRenderPanel(map, this); 45 | plotRenderPanel.setSize(1, 1); 46 | 47 | frame.add(renderPanel); 48 | frame.add(plotRenderPanel); 49 | 50 | } 51 | 52 | public void startSimulation() { 53 | 54 | for (int i = 0; i < startNumOfAnimals; i++) { 55 | map.addAnimalOnRandomField(); 56 | map.placeAnimalToRandomFieldInJungle(); 57 | } 58 | timer.start(); 59 | 60 | } 61 | 62 | @Override 63 | //It will executed when timer finished counting 64 | public void actionPerformed(ActionEvent e) { 65 | plotRenderPanel.repaint(); 66 | renderPanel.repaint(); 67 | 68 | map.removeDeadAnimals(); 69 | map.moveRandomAllAnimals(); 70 | map.eating(); 71 | map.nextDay(); 72 | map.copulation(); 73 | for (int i = 0; i < grassSpawnedInEachDay / 2; i++) { 74 | map.spawnGrass(); 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Visualization/PlotRenderPanel.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Visualization; 2 | 3 | import agh.cs.po.DarwinWorld.SteppeJungleMap; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.Collections; 10 | 11 | public class PlotRenderPanel extends JPanel { 12 | 13 | private SteppeJungleMap map; 14 | private MapSimulation simulation; 15 | private int totalDays; 16 | ArrayList animalsPopulation; 17 | ArrayList grassPopulation; 18 | 19 | public PlotRenderPanel(SteppeJungleMap map, MapSimulation simulation) { 20 | animalsPopulation = new ArrayList<>(); 21 | grassPopulation = new ArrayList<>(); 22 | this.map = map; 23 | this.simulation = simulation; 24 | totalDays = 0; 25 | } 26 | 27 | @Override 28 | protected void paintComponent(Graphics g) { 29 | super.paintComponent(g); 30 | this.setSize((int) (simulation.frame.getWidth() * 0.4), simulation.frame.getHeight() - 38); //38 is toolbar size 31 | this.setLocation(0, 0); 32 | int width = this.getWidth(); 33 | int height = this.getHeight(); 34 | totalDays++; 35 | g.drawString("Total days: " + totalDays, 10, height - 20); 36 | 37 | animalsPopulation.add(map.animalsList.size()); 38 | grassPopulation.add(map.grassList.size()); 39 | 40 | FunctionPlot p1 = new FunctionPlot(width - 10, height * 2 / 3 - 50, 5, height * 2 / 3 - 30); 41 | 42 | g.setColor(new Color(0, 0, 0)); 43 | 44 | drawVerticalArrow(g, p1.cpx, p1.cpy, p1.cpx, p1.cpy - p1.height, "Population of grass and animals"); 45 | drawHorizontalArrow(g, p1.cpx, p1.cpy, p1.cpx + p1.width, p1.cpy, totalDays, "Day"); 46 | 47 | 48 | g.setColor(new Color(160, 67, 41)); 49 | Integer[] animalPopulationAvg = new Integer[p1.width]; 50 | Integer[] grassPopulationAvg = new Integer[p1.width]; 51 | 52 | //calculate and scale animal population per day 53 | for (int i = 0; i < animalPopulationAvg.length; i++) { 54 | animalPopulationAvg[i] = 0; 55 | } 56 | 57 | int i = 0; 58 | for (int j : animalsPopulation) { 59 | animalPopulationAvg[i] = j; 60 | i++; 61 | if (i == animalPopulationAvg.length) break; 62 | } 63 | i = 0; 64 | for (int j : animalsPopulation) { 65 | animalPopulationAvg[i % animalPopulationAvg.length] += j; 66 | animalPopulationAvg[i % animalPopulationAvg.length] /= 2; 67 | i++; 68 | } 69 | double maxY = (double) Collections.max(Arrays.asList(animalPopulationAvg)); 70 | double scale = p1.height / maxY; 71 | for (i = 0; i < animalPopulationAvg.length; i++) { 72 | animalPopulationAvg[i] = (int) (scale * animalPopulationAvg[i]); 73 | } 74 | //drawing 75 | for (i = 0; i < p1.width - 1; i++) { 76 | g.drawLine(i + p1.cpx + 1, p1.cpy - animalPopulationAvg[i], i + p1.cpx + 2, p1.cpy - animalPopulationAvg[i + 1]); //drawing point 77 | } 78 | 79 | //calculate and scale grass populate 80 | for (i = 0; i < grassPopulationAvg.length; i++) { 81 | grassPopulationAvg[i] = 0; 82 | } 83 | 84 | i = 0; 85 | for (int j : grassPopulation) { 86 | grassPopulationAvg[i] = j; 87 | i++; 88 | if (i == grassPopulationAvg.length) break; 89 | } 90 | i = 0; 91 | for (int j : grassPopulation) { 92 | grassPopulationAvg[i % grassPopulationAvg.length] += j; 93 | grassPopulationAvg[i % grassPopulationAvg.length] /= 2; 94 | i++; 95 | } 96 | maxY = (double) Collections.max(Arrays.asList(grassPopulationAvg)); 97 | scale = p1.height / maxY; 98 | for (i = 0; i < grassPopulationAvg.length; i++) { 99 | grassPopulationAvg[i] = (int) (scale * grassPopulationAvg[i]); 100 | } 101 | g.setColor(new Color(0, 160, 7)); 102 | for (i = 0; i < p1.width - 1; i++) { 103 | g.drawLine(i + p1.cpx + 1, p1.cpy - grassPopulationAvg[i], i + p1.cpx + 2, p1.cpy - grassPopulationAvg[i + 1]); //drawing point 104 | } 105 | 106 | //Legend 107 | g.setColor(new Color(160, 67, 41)); 108 | g.fillRect(p1.cpx, p1.cpy + height / 30, width / 25, height / 50); 109 | g.drawString(" - Animal population plot", p1.cpx + width / 25, p1.cpy + height / 22); 110 | 111 | g.setColor(new Color(0, 160, 7)); 112 | g.fillRect(p1.cpx, p1.cpy + height / 20, width / 25, height / 50); 113 | g.drawString(" - Grass population plot", p1.cpx + width / 25, p1.cpy + height / 15); 114 | 115 | g.setColor(new Color(0, 0, 0)); 116 | g.drawString("Legend: ", p1.cpx, p1.cpy + height / 10); 117 | int yp = p1.cpy + height / 10; 118 | int a = height / 22; 119 | g.drawString("Steppe Field ", p1.cpx + width / 10, yp + a); 120 | g.drawString("Jungle Field ", p1.cpx + width / 10, yp + 2 * a); 121 | g.drawString("Animal (Changes color to darker when has more energy)", p1.cpx + width / 10, yp + 3 * a); 122 | g.drawString("Grass ", p1.cpx + width / 10, yp + 4 * a); 123 | 124 | g.setColor(new Color(170, 224, 103)); 125 | g.fillRect(p1.cpx, yp + a - 10, width / 20, height / 40); 126 | 127 | g.setColor(new Color(0, 160, 7)); 128 | g.fillRect(p1.cpx, yp + 2 * a - 10, width / 20, height / 40); 129 | 130 | g.setColor(new Color(146, 82, 73)); 131 | g.fillOval(p1.cpx, yp + 3 * a - 10, width / 20, height / 40); 132 | 133 | g.setColor(new Color(67, 222, 31)); 134 | g.fillRect(p1.cpx, yp + 4 * a - 10, width / 20, height / 40); 135 | 136 | 137 | } 138 | 139 | private void drawVerticalArrow(Graphics g, int x, int y, int x2, int y2, String title) { 140 | g.drawLine(x, y, x2, y2); 141 | g.drawLine(x2, y2, x2 - 5, y2 + 5); 142 | g.drawLine(x2, y2, x2 + 5, y2 + 5); 143 | g.drawString(title, x, y2 - 10); 144 | } 145 | 146 | private void drawHorizontalArrow(Graphics g, int x, int y, int x2, int y2, Integer max, String title) { 147 | g.drawLine(x, y, x2, y2); 148 | g.drawLine(x2, y2, x2 - 5, y2 + 5); 149 | g.drawLine(x2, y2, x2 - 5, y2 - 5); 150 | 151 | g.drawString(title, x2 - 50, y + 30); 152 | 153 | // g.drawLine(x2,y2+3,x2,y2-3); 154 | // g.drawString(max.toString(),x2-20,y+20); 155 | 156 | g.drawLine(x2 / 2, y2 + 3, x2 / 2, y2 - 3); 157 | g.drawString(Integer.toString(max / 2), x2 / 2 - 20, y + 20); 158 | 159 | g.drawLine(x2 / 4, y2 + 3, x2 / 4, y2 - 3); 160 | g.drawString(Integer.toString(max / 4), x2 / 4 - 20, y + 20); 161 | 162 | g.drawLine(x2 * 3 / 4, y2 + 3, x2 * 3 / 4, y2 - 3); 163 | g.drawString(Integer.toString(max * 3 / 4), x2 * 3 / 4 - 20, y + 20); 164 | 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /Visualization/RenderPanel.java: -------------------------------------------------------------------------------- 1 | package agh.cs.po.Visualization; 2 | 3 | import agh.cs.po.Classes.Animal; 4 | import agh.cs.po.Classes.Grass; 5 | import agh.cs.po.DarwinWorld.SteppeJungleMap; 6 | 7 | import javax.swing.*; 8 | import java.awt.*; 9 | 10 | public class RenderPanel extends JPanel { 11 | 12 | public SteppeJungleMap map; 13 | public MapSimulation simulation; 14 | 15 | public RenderPanel(SteppeJungleMap map, MapSimulation simulation) { 16 | this.map = map; 17 | this.simulation = simulation; 18 | } 19 | 20 | @Override 21 | protected void paintComponent(Graphics g) { 22 | super.paintComponent(g); 23 | this.setSize((int) (simulation.frame.getWidth() * 0.6), simulation.frame.getHeight() - 38); 24 | this.setLocation((int) (0.4 * simulation.frame.getWidth()), 0); 25 | int width = this.getWidth(); 26 | int height = this.getHeight(); //38 is toolbar size 27 | int widthScale = Math.round(width / map.width); 28 | int heightScale = height / map.height; 29 | 30 | //draw Steppe 31 | g.setColor(new Color(170, 224, 103)); 32 | g.fillRect(0, 0, width, height); 33 | 34 | //draw Jungle 35 | g.setColor(new Color(0, 160, 7)); 36 | g.fillRect(map.getJungleLowerLeft().x * widthScale, 37 | map.getJungleLowerLeft().y * heightScale, 38 | map.jungleWidth * widthScale, 39 | map.jungleHeight * heightScale); 40 | 41 | //draw Grass 42 | for (Grass grass : map.getGrass()) { 43 | g.setColor(grass.toColor()); 44 | int y = map.toNoBoundedPosition(grass.getPosition()).y * heightScale; 45 | int x = map.toNoBoundedPosition(grass.getPosition()).x * widthScale; 46 | g.fillRect(x, y, widthScale, heightScale); 47 | } 48 | //draw Animals 49 | for (Animal a : map.getAnimals()) { 50 | g.setColor(a.toColor()); 51 | int y = map.toNoBoundedPosition(a.getPosition()).y * heightScale; 52 | int x = map.toNoBoundedPosition(a.getPosition()).x * widthScale; 53 | g.fillOval(x, y, widthScale, heightScale); 54 | } 55 | } 56 | 57 | } 58 | --------------------------------------------------------------------------------