Skip to content

Commit

Permalink
Fix/water random walk (#44)
Browse files Browse the repository at this point in the history
* Fix random walk and eat and drink logic

* Clean up
  • Loading branch information
srgjc authored Jan 29, 2024
1 parent 150781a commit 5c3a517
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 134 deletions.
110 changes: 54 additions & 56 deletions GeoRasterBlueprint/Model/AbstractAnimal.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GeoRasterBlueprint.Util;
using Mars.Common;
using Mars.Components.Layers;
using Mars.Interfaces.Agents;
using Mars.Interfaces.Environments;
using NetTopologySuite.Utilities;
using Position = Mars.Interfaces.Environments.Position;

namespace GeoRasterBlueprint.Model;

Expand All @@ -22,7 +21,8 @@ public abstract class AbstractAnimal : IPositionable, IAgent<LandscapeLayer> {
public Perimeter Perimeter { get; set; }
public abstract double Hydration { get; set; }
public abstract double Satiety { get; set; }
public WaterLayer WaterLayer { get; set; }
public VectorWaterLayer VectorWaterLayer { get; set; }
public RasterWaterLayer RasterWaterLayer { get; set; }
public VegetationLayer VegetationLayer { get; set; }

public int _hoursLived;
Expand All @@ -48,77 +48,78 @@ public abstract class AbstractAnimal : IPositionable, IAgent<LandscapeLayer> {

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

var spawnPosition = new Position(Longitude, Latitude);

if (LandscapeLayer.Fence.IsPointInside(new Position(Longitude, Latitude))) {
if (Perimeter.IsPointInside(spawnPosition) && !RasterWaterLayer.IsPointInside(spawnPosition)) {
Position = Position.CreateGeoPosition(Longitude, Latitude);
} else {
throw new Exception($"Start point is not inside perimeter. Lon: {Longitude}, Lat: {Latitude}");
throw new Exception($"Start point is not valid. Lon: {Longitude}, Lat: {Latitude}");
}
}

public abstract void Tick();

protected Position Move(AbstractAnimal animal, double bearing, double distance) {
return LandscapeLayer.Environment.MoveTowards(animal, bearing, distance);
}

protected void DoRandomWalk(int numOfAttempts) {
bool walkedSuccessfully = false;
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));

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

var targetPosition = Position.GetRelativePosition(randomDirection, randomDistance);

// removed for being bugged && !WaterLayer.IsIntersectsAny(Position, targetPosition)
if (Perimeter.IsPointInside(targetPosition)) {
var newCurrentPosition = Move(this, randomDirection, randomDistance);
if (newCurrentPosition != null) {
walkedSuccessfully = true;
}
Target = Position.GetRelativePosition(randomDirection, randomDistance);

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

numOfAttempts--;
}

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

protected void MoveToWaterSource() {
int radius = 2000;
List<VectorFeature> nearWaterSpots = WaterLayer.Explore(Position.PositionArray, radius).ToList();
if (nearWaterSpots.Any()) {
var nearest = WaterLayer.Nearest(new []{Position.X, Position.Y});
protected void LookForWaterAndDrink() {
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
const int radius = 2000;
var nearWaterSpots = VectorWaterLayer.Explore(Position.PositionArray, radius)
.ToList();

var nearestPoints = nearest.VectorStructured.Geometry.Coordinates.ToList();

nearestPoints.Sort(new DistanceComparer(Position.X, Position.Y));

Target = new Position(nearestPoints.First().X, nearestPoints.First().Y);
if (!nearWaterSpots.Any()) return;

var nearestWaterSpot = VectorWaterLayer
.Nearest(new []{Position.X, Position.Y})
.VectorStructured
.Geometry
.Coordinates
.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);

Bearing = Position.GetBearing(Target);

if (Target.DistanceInMTo(Position) < 50) {
if (Perimeter.IsPointInside(Target) && !RasterWaterLayer.IsPointInside(Target)) {
Position = Target;
Hydration += 20;
Bearing = (Bearing + 45) % 360;
break;
}

var distanceToTarget = Target.DistanceInMTo(Position);

Position = distanceToTarget > Distance
? Move(this, Bearing, Distance)
: Move(this, Bearing, distanceToTarget - 10);
} else {
Console.WriteLine("No water found in {0}m radius.", radius);
}

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

protected void SearchForFood() {
protected void LookForFoodAndEat() {
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
if (VegetationLayer.IsPointInside(Position)) {
var all = VegetationLayer.Explore(Position, 20, 4);
var res = all.OrderBy(a => a.Node.Value).Last();
if (res.Node?.NodePosition != null) {
var targetX = res.Node.NodePosition.X;
var targetY = res.Node.NodePosition.Y;
var nearVegetationSpots = VegetationLayer.Explore(Position, 20)
.OrderByDescending(node => node.Node.Value)
.ToList();

foreach (var spot in nearVegetationSpots) {

var targetX = spot.Node.NodePosition.X;
var targetY = spot.Node.NodePosition.Y;

var targetLon = VegetationLayer.LowerLeft.X +
targetX * VegetationLayer.CellWidth;
Expand All @@ -127,17 +128,14 @@ protected void SearchForFood() {

Target = new Position(targetLon, targetLat);

if (Perimeter.IsPointInside(Target)) {
if (Perimeter.IsPointInside(Target) && !RasterWaterLayer.IsPointInside(Target)) {
Position = Target;
Satiety += 12;
var oldPos = Position;
var distanceToTarget = Target.DistanceInMTo(Position);
Bearing = Position.GetBearing(Target);
Position = distanceToTarget > Distance
? Move(this, Bearing, Distance)
: Move(this, Bearing, distanceToTarget);
break;
}
}
}
Assert.IsTrue(Perimeter.IsPointInside(Position) && !RasterWaterLayer.IsPointInside(Position));
}

//every animals has different ways to consume food or hydration
Expand Down
6 changes: 2 additions & 4 deletions GeoRasterBlueprint/Model/Bison.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ public override void Tick() {
if (!IsAlive) return;

if (Satiety < 40) {
SearchForFood();
LookForFoodAndEat();
}
else if (Hydration < 40) {
MoveToWaterSource();
// currently buggy because we walk into water
Hydration += 20;
LookForWaterAndDrink();
}
else {
DoRandomWalk(10);
Expand Down
6 changes: 2 additions & 4 deletions GeoRasterBlueprint/Model/Elk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,10 @@ public override void Tick() {
if (!IsAlive) return;

if (Satiety < 40) {
SearchForFood();
LookForFoodAndEat();
}
else if (Hydration < 40) {
MoveToWaterSource();
// currently buggy because we walk into water
Hydration += 20;
LookForWaterAndDrink();
}
else {
DoRandomWalk(10);
Expand Down
6 changes: 2 additions & 4 deletions GeoRasterBlueprint/Model/Moose.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,10 @@ public override void Tick() {
if (!IsAlive) return;

if (Satiety < 40) {
SearchForFood();
LookForFoodAndEat();
}
else if (Hydration < 40) {
MoveToWaterSource();
// currently buggy because we walk into water
Hydration += 20;
LookForWaterAndDrink();
}
else {
DoRandomWalk(10);
Expand Down
15 changes: 15 additions & 0 deletions GeoRasterBlueprint/Model/RasterWaterLayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Mars.Components.Layers;
using Mars.Interfaces.Environments;

namespace GeoRasterBlueprint.Model;

/// <summary>
/// Represents water spots in the Elk Island National Park.
/// </summary>
public class RasterWaterLayer : RasterLayer {

public bool IsPointInside(Position position) {
return Extent.Contains(position.X, position.Y) && GetValue(position) == 0;
}

}
11 changes: 11 additions & 0 deletions GeoRasterBlueprint/Model/VectorWaterLayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Mars.Components.Layers;
using NetTopologySuite.Geometries;
using Position = Mars.Interfaces.Environments.Position;

namespace GeoRasterBlueprint.Model;

/// <summary>
/// Represents water spots in the Elk Island National Park.
/// </summary>
public class VectorWaterLayer : VectorLayer {
}
31 changes: 0 additions & 31 deletions GeoRasterBlueprint/Model/WaterLayer.cs

This file was deleted.

3 changes: 2 additions & 1 deletion GeoRasterBlueprint/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public static void Main(string[] args) {
var description = new ModelDescription();
description.AddLayer<LandscapeLayer>();
description.AddLayer<Perimeter>();
description.AddLayer<WaterLayer>();
description.AddLayer<VectorWaterLayer>();
description.AddLayer<RasterWaterLayer>();
description.AddLayer<VegetationLayer>();
description.AddLayer<TemperatureLayer>();
description.AddLayer<AltitudeLayer>();
Expand Down
Loading

0 comments on commit 5c3a517

Please sign in to comment.