Skip to content

Commit

Permalink
add reproduction
Browse files Browse the repository at this point in the history
* add reproduction

* improve reproduction

* rebase onto main

---------

Co-authored-by: Johnny <Johnny.Busch@haw-hamburg.de>
  • Loading branch information
Johnny-MB and Johnny authored Jan 29, 2024
1 parent 5c3a517 commit 6a8e4b5
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 51 deletions.
92 changes: 64 additions & 28 deletions GeoRasterBlueprint/Model/AbstractAnimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,73 @@
using Mars.Interfaces.Environments;
using NetTopologySuite.Utilities;
using Position = Mars.Interfaces.Environments.Position;
using Mars.Interfaces.Annotations;

namespace GeoRasterBlueprint.Model;

public abstract class AbstractAnimal : IPositionable, IAgent<LandscapeLayer> {

[ActiveConstructor]
public AbstractAnimal() {
}

[ActiveConstructor]
public AbstractAnimal(
LandscapeLayer landscapeLayer,
Perimeter perimeter,
VegetationLayer vegetationLayer,
VectorWaterLayer waterLayer,
RasterWaterLayer rasterWaterLayer,
Guid id,
AnimalType animalType,
bool isLeading,
int herdId,
double latitude,
double longitude,
Position position) {
//Position = Position.CreateGeoPosition(longitude, latitude);
Position = position;
_landscapeLayer = landscapeLayer;
_perimeter = perimeter;
_vegetationLayer = vegetationLayer;
_vectorWaterLayer = waterLayer;
_rasterWaterLayer = rasterWaterLayer;
_animalType = animalType;
ID = id;
_isLeading = isLeading;
_herdId = herdId;
}

public Guid ID { get; set; }
public abstract Position Position { get; set; }
public abstract Position Target { get; set; }
public double Bearing = 222.0;
public const double Distance = 5000.0;
public LandscapeLayer LandscapeLayer { get; set; }
public LandscapeLayer _landscapeLayer { get; set; }
public abstract double Latitude { get; set; }
public abstract double Longitude { get; set; }
public Perimeter Perimeter { get; set; }
public Perimeter _perimeter { get; set; }
public abstract double Hydration { get; set; }
public abstract double Satiety { get; set; }
public VectorWaterLayer VectorWaterLayer { get; set; }
public RasterWaterLayer RasterWaterLayer { get; set; }
public VegetationLayer VegetationLayer { get; set; }
public VectorWaterLayer _vectorWaterLayer { get; set; }
public RasterWaterLayer _rasterWaterLayer { get; set; }
public VegetationLayer _vegetationLayer { get; set; }

public int _hoursLived;
public AnimalType _animalType;
public readonly int[] _reproductionYears = {2, 15};
public bool _pregnant;
public int _pregnancyDuration;
public int _chanceOfDeath;
public int Age { get; set; }
public AnimalLifePeriod _LifePeriod;
public MattersOfDeath MatterOfDeath { get; private set; }
public bool IsAlive { get; set; } = true;

protected bool isLeading { get; }
protected int herdId { get; }
[PropertyDescription (Name="isLeading")]
protected bool _isLeading { get; }
[PropertyDescription (Name="_herdId")]
protected int _herdId { get; }

public static Random _random = new ();
private const int RandomWalkMaxDistanceInM = 500;
Expand All @@ -47,11 +82,12 @@ public abstract class AbstractAnimal : IPositionable, IAgent<LandscapeLayer> {


public void Init(LandscapeLayer layer) {
LandscapeLayer = layer;
_landscapeLayer = layer;

var spawnPosition = new Position(Longitude, Latitude);
_landscapeLayer = layer;

if (Perimeter.IsPointInside(spawnPosition) && !RasterWaterLayer.IsPointInside(spawnPosition)) {
if (_perimeter.IsPointInside(spawnPosition) && !_rasterWaterLayer.IsPointInside(spawnPosition)) {
Position = Position.CreateGeoPosition(Longitude, Latitude);
} else {
throw new Exception($"Start point is not valid. Lon: {Longitude}, Lat: {Latitude}");
Expand All @@ -61,58 +97,58 @@ public void Init(LandscapeLayer layer) {
public abstract void Tick();

protected void DoRandomWalk(int numOfAttempts) {
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
Assert.IsTrue(_perimeter.IsPointInside(Position) && !_rasterWaterLayer.IsPointInside(Position));

while (numOfAttempts > 0) {
var randomDistance = _random.Next(RandomWalkMinDistanceInM, RandomWalkMaxDistanceInM);
var randomDirection = _random.Next(0, 360);

Target = Position.GetRelativePosition(randomDirection, randomDistance);

if (Perimeter.IsPointInside(Target) && !RasterWaterLayer.IsPointInside(Target)) {
if (_perimeter.IsPointInside(Target) && !_rasterWaterLayer.IsPointInside(Target)) {
Position = Target;
break;
}
numOfAttempts--;
}

Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
Assert.IsTrue(_perimeter.IsPointInside(Position) && !_rasterWaterLayer.IsPointInside(Position));
}

protected void LookForWaterAndDrink() {
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
Assert.IsTrue(_perimeter.IsPointInside(Position) && !_rasterWaterLayer.IsPointInside(Position));
const int radius = 2000;
var nearWaterSpots = VectorWaterLayer.Explore(Position.PositionArray, radius)
var nearWaterSpots = _vectorWaterLayer.Explore(Position.PositionArray, radius)
.ToList();

if (!nearWaterSpots.Any()) return;

var nearestWaterSpot = VectorWaterLayer
var nearestWaterSpot = _vectorWaterLayer
.Nearest(new []{Position.X, Position.Y})
.VectorStructured
.Geometry
.Coordinates
.Where(coordinate => Perimeter.IsPointInside(new Position(coordinate.X, coordinate.Y)))
.Where(coordinate => _perimeter.IsPointInside(new Position(coordinate.X, coordinate.Y)))
.OrderBy(coordinate => Position.DistanceInMTo(coordinate.X, coordinate.Y))
.ToList();

foreach (var point in nearestWaterSpot) {
Target = new Position(point.X, point.Y);

if (Perimeter.IsPointInside(Target) && !RasterWaterLayer.IsPointInside(Target)) {
if (_perimeter.IsPointInside(Target) && !_rasterWaterLayer.IsPointInside(Target)) {
Position = Target;
Hydration += 20;
break;
}
}

Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
Assert.IsTrue(_perimeter.IsPointInside(Position) && !_rasterWaterLayer.IsPointInside(Position));
}

protected void LookForFoodAndEat() {
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
if (VegetationLayer.IsPointInside(Position)) {
var nearVegetationSpots = VegetationLayer.Explore(Position, 20)
Assert.IsTrue(_perimeter.IsPointInside(Position) && !_rasterWaterLayer.IsPointInside(Position));
if (_vegetationLayer.IsPointInside(Position)) {
var nearVegetationSpots = _vegetationLayer.Explore(Position, 20)
.OrderByDescending(node => node.Node.Value)
.ToList();

Expand All @@ -121,21 +157,21 @@ protected void LookForFoodAndEat() {
var targetX = spot.Node.NodePosition.X;
var targetY = spot.Node.NodePosition.Y;

var targetLon = VegetationLayer.LowerLeft.X +
targetX * VegetationLayer.CellWidth;
var targetLat = VegetationLayer.LowerLeft.Y +
targetY * VegetationLayer.CellHeight;
var targetLon = _vegetationLayer.LowerLeft.X +
targetX * _vegetationLayer.CellWidth;
var targetLat = _vegetationLayer.LowerLeft.Y +
targetY * _vegetationLayer.CellHeight;

Target = new Position(targetLon, targetLat);

if (Perimeter.IsPointInside(Target) && !RasterWaterLayer.IsPointInside(Target)) {
if (_perimeter.IsPointInside(Target) && !_rasterWaterLayer.IsPointInside(Target)) {
Position = Target;
Satiety += 12;
break;
}
}
}
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
Assert.IsTrue(_perimeter.IsPointInside(Position) && !_rasterWaterLayer.IsPointInside(Position));
}

//every animals has different ways to consume food or hydration
Expand Down Expand Up @@ -170,7 +206,7 @@ public void Die(MattersOfDeath mannerOfDeath)
{
MatterOfDeath = mannerOfDeath;
IsAlive = false;
//add removal of animal
_landscapeLayer.removeAnimal(_landscapeLayer, this);
}

}
60 changes: 53 additions & 7 deletions GeoRasterBlueprint/Model/Bison.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,38 @@
namespace GeoRasterBlueprint.Model;

public class Bison : AbstractAnimal {

[ActiveConstructor]
public Bison() {
}

[ActiveConstructor]
public Bison(
LandscapeLayer landscapeLayer,
Perimeter perimeter,
VegetationLayer vegetationLayer,
VectorWaterLayer waterLayer,
RasterWaterLayer rasterWaterLayer,
Guid id,
AnimalType animalType,
bool isLeading,
int herdId,
double latitude,
double longitude,
Position position) :
base(landscapeLayer,
perimeter,
vegetationLayer,
waterLayer,
rasterWaterLayer,
id,
animalType,
isLeading,
herdId,
latitude,
longitude,
position) {
}

#region Properties and Fields

Expand All @@ -18,6 +50,9 @@ public class Bison : AbstractAnimal {
public override double Latitude { get; set; }
[PropertyDescription(Name = "Longitude")]
public override double Longitude { get; set; }
//Chance for a female animal to become pregnant per year
public int ChanceForPregnancy = 10;



protected string BisonType;
Expand Down Expand Up @@ -70,9 +105,18 @@ public class Bison : AbstractAnimal {

public override void Tick() {

if (!IsAlive) return;
_hoursLived++;
if (_hoursLived == 300)
if (_hoursLived % 1 == 0 && _pregnant) {
if (_pregnancyDuration < 8) {
_pregnancyDuration++;
}
else {
_pregnancyDuration = 0;
_landscapeLayer.SpawnBison(_landscapeLayer, _perimeter, _vegetationLayer, _vectorWaterLayer, _rasterWaterLayer,
AnimalType.BisonCalf, false, _herdId, Latitude, Longitude, Position);
}
}
if (_hoursLived == 2)
{
YearlyRoutine();
}
Expand All @@ -92,8 +136,8 @@ public override void Tick() {
protected override void UpdateState()
{
int currentHour;
if (LandscapeLayer.Context.CurrentTimePoint != null)
currentHour = LandscapeLayer.Context.CurrentTimePoint.Value.Hour;
if (_landscapeLayer.Context.CurrentTimePoint != null)
currentHour = _landscapeLayer.Context.CurrentTimePoint.Value.Hour;
else
throw new NullReferenceException();

Expand Down Expand Up @@ -137,11 +181,13 @@ public override void YearlyRoutine() {
}

//check for possible reproduction
if (!_reproductionYears.Contains(Age)) return;
if (!(Age >= _reproductionYears[0] && Age <= _reproductionYears[1])) return;

if (!_animalType.Equals(AnimalType.BisonBull)) return;
if (!_animalType.Equals(AnimalType.BisonCow)) return;

_pregnant = true;
if (_LifePeriod == AnimalLifePeriod.Adult && _random.Next(100) < ChanceForPregnancy-1) {
_pregnant = true;
}
}

public override AnimalLifePeriod GetAnimalLifePeriodFromAge(int age)
Expand Down
Loading

0 comments on commit 6a8e4b5

Please sign in to comment.