diff options
| -rw-r--r-- | .gitignore | 10 | ||||
| -rw-r--r-- | MorgSimulator.csproj | 10 | ||||
| -rw-r--r-- | MorgSimulator/Dish.cs | 42 | ||||
| -rw-r--r-- | MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs | 12 | ||||
| -rw-r--r-- | MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs | 12 | ||||
| -rw-r--r-- | MorgSimulator/IFeedingStrategy.cs | 7 | ||||
| -rw-r--r-- | MorgSimulator/IMovementStrategy.cs | 7 | ||||
| -rw-r--r-- | MorgSimulator/Morg.cs | 87 | ||||
| -rw-r--r-- | MorgSimulator/MovementStrategy/MovementStrategyOozes.cs | 12 | ||||
| -rw-r--r-- | MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs | 12 | ||||
| -rw-r--r-- | MorgSimulator/Program.cs | 36 | ||||
| -rw-r--r-- | MorgSimulator/Type/TypeAMorg.cs | 16 | ||||
| -rw-r--r-- | MorgSimulator/Type/TypeBMorg.cs | 15 | ||||
| -rw-r--r-- | MorgSimulator/Type/TypeCMorg.cs | 16 | ||||
| -rw-r--r-- | justfile | 15 |
15 files changed, 309 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..263f35f --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# .NET +obj +bin +docs + +# Visual Studio Code +.vscode + +# macOS +.DS_Store diff --git a/MorgSimulator.csproj b/MorgSimulator.csproj new file mode 100644 index 0000000..017f6f8 --- /dev/null +++ b/MorgSimulator.csproj @@ -0,0 +1,10 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net9.0</TargetFramework> + <ImplicitUsings>false</ImplicitUsings> + <Nullable>warnings</Nullable> + </PropertyGroup> + +</Project> diff --git a/MorgSimulator/Dish.cs b/MorgSimulator/Dish.cs new file mode 100644 index 0000000..d81fc8a --- /dev/null +++ b/MorgSimulator/Dish.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Linq; + +namespace MorgSimulator +{ + public class Dish + { + private readonly List<Morg> _morgs = []; + + public void AddMorg(Morg morg) + { + _morgs.Add(morg); + } + + public List<Morg> GetAllMorgs() + { + return [.. _morgs]; + } + +#nullable enable + public Morg? FindNearestPrey(Morg predator) + { + Morg? nearestPrey = null; + double nearestDistance = double.MaxValue; + + foreach (var potentialPrey in _morgs.Where(m => m.IsAlive && m != predator)) + if (predator.CanEat(potentialPrey.Type)) + { + double distance = predator.DistanceTo(potentialPrey.Location); + + if (distance < nearestDistance) + { + nearestDistance = distance; + nearestPrey = potentialPrey; + } + } + + return nearestPrey; + } +#nullable disable + } +}
\ No newline at end of file diff --git a/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs b/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs new file mode 100644 index 0000000..9e0f9a0 --- /dev/null +++ b/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs @@ -0,0 +1,12 @@ +namespace MorgSimulator +{ + public class FeedingStrategyAbsorbs : IFeedingStrategy + { + public void Feed(Morg predator, Morg prey) + { + System.Console.WriteLine($"Morg {predator.Id} Absorbs Morg {prey.Id} at ({prey.Location.x},{prey.Location.y})"); + + prey.IsAlive = false; + } + } +} diff --git a/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs b/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs new file mode 100644 index 0000000..d35227c --- /dev/null +++ b/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs @@ -0,0 +1,12 @@ +namespace MorgSimulator +{ + public class FeedingStrategyEnvelops : IFeedingStrategy + { + public void Feed(Morg predator, Morg prey) + { + System.Console.WriteLine($"Morg {predator.Id} Envelops Morg {prey.Id} at ({prey.Location.x},{prey.Location.y})"); + + prey.IsAlive = false; + } + } +} diff --git a/MorgSimulator/IFeedingStrategy.cs b/MorgSimulator/IFeedingStrategy.cs new file mode 100644 index 0000000..b0344ea --- /dev/null +++ b/MorgSimulator/IFeedingStrategy.cs @@ -0,0 +1,7 @@ +namespace MorgSimulator +{ + public interface IFeedingStrategy + { + void Feed(Morg predator, Morg prey); + } +} diff --git a/MorgSimulator/IMovementStrategy.cs b/MorgSimulator/IMovementStrategy.cs new file mode 100644 index 0000000..2b073e1 --- /dev/null +++ b/MorgSimulator/IMovementStrategy.cs @@ -0,0 +1,7 @@ +namespace MorgSimulator +{ + public interface IMovementStrategy + { + void Move(Morg morg, (int x, int y) newLocation); + } +} diff --git a/MorgSimulator/Morg.cs b/MorgSimulator/Morg.cs new file mode 100644 index 0000000..62048bf --- /dev/null +++ b/MorgSimulator/Morg.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Linq; + +namespace MorgSimulator +{ + public abstract class Morg(int id, (int x, int y) location, (int x, int y) direction) + { + public int Id { get; set; } = id; + public string Type { get; protected set; } = string.Empty; + public (int x, int y) Location { get; set; } = location; + public (int x, int y) Direction { get; set; } = direction; + public bool IsAlive { get; set; } = true; + public IMovementStrategy MovementStrategy { get; protected set; } = null!; + public IFeedingStrategy FeedingStrategy { get; protected set; } = null!; + public List<string> PreyTypes { get; protected set; } = new List<string>(); +#nullable enable + public Morg? Prey { get; set; } +#nullable disable + + private readonly List<Morg> _observers = []; + + public void Attach(Morg observer) + { + if (!_observers.Contains(observer)) + _observers.Add(observer); + } + + public void Detach(Morg observer) + { + _observers.Remove(observer); + } + + public void Notify() + { + foreach (var observer in _observers.ToList()) + observer.Update(this); + } + + public virtual void Update(Morg subject) + { + Direction = CalculateDirectionToTarget(subject.Location); + } + + public virtual void Move() + { + if (!IsAlive) return; + + var newLocation = (Location.x + Direction.x, Location.y + Direction.y); + + MovementStrategy.Move(this, newLocation); + Notify(); + } + + public virtual void Feed() + { + if (!IsAlive || Prey == null || !Prey.IsAlive) return; + + FeedingStrategy.Feed(this, Prey); + + Prey = null; + } + + public bool CanEat(string targetType) + { + return PreyTypes.Contains(targetType); + } + + public (int x, int y) CalculateDirectionToTarget((int x, int y) target) + { + int deltaX = target.x - Location.x; + int deltaY = target.y - Location.y; + int directionX = deltaX > 0 ? 1 : (deltaX < 0 ? -1 : 0); + int directionY = deltaY > 0 ? 1 : (deltaY < 0 ? -1 : 0); + + return (directionX, directionY); + } + + public double DistanceTo((int x, int y) target) + { + int deltaX = target.x - Location.x; + int deltaY = target.y - Location.y; + + return System.Math.Sqrt(deltaX * deltaX + deltaY * deltaY); + } + + } +}
\ No newline at end of file diff --git a/MorgSimulator/MovementStrategy/MovementStrategyOozes.cs b/MorgSimulator/MovementStrategy/MovementStrategyOozes.cs new file mode 100644 index 0000000..217d175 --- /dev/null +++ b/MorgSimulator/MovementStrategy/MovementStrategyOozes.cs @@ -0,0 +1,12 @@ +namespace MorgSimulator +{ + public class MovementStrategyOozes : IMovementStrategy + { + public void Move(Morg morg, (int x, int y) newLocation) + { + System.Console.WriteLine($"Morg {morg.Id} Oozes from ({morg.Location.x},{morg.Location.y}) to ({newLocation.x},{newLocation.y})"); + + morg.Location = newLocation; + } + } +} diff --git a/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs b/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs new file mode 100644 index 0000000..efdd3ef --- /dev/null +++ b/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs @@ -0,0 +1,12 @@ +namespace MorgSimulator +{ + public class MovementStrategyPaddles : IMovementStrategy + { + public void Move(Morg morg, (int x, int y) newLocation) + { + System.Console.WriteLine($"Morg {morg.Id} Paddles from ({morg.Location.x},{morg.Location.y}) to ({newLocation.x},{newLocation.y})"); + + morg.Location = newLocation; + } + } +} diff --git a/MorgSimulator/Program.cs b/MorgSimulator/Program.cs new file mode 100644 index 0000000..bf15776 --- /dev/null +++ b/MorgSimulator/Program.cs @@ -0,0 +1,36 @@ +using MorgSimulator; + +var dish = new Dish(); + +dish.AddMorg(new TypeAMorg(1, (0, 0), (1, 0))); +dish.AddMorg(new TypeAMorg(2, (10, 10), (-1, -1))); +dish.AddMorg(new TypeBMorg(3, (5, 5), (0, 1))); +dish.AddMorg(new TypeBMorg(4, (15, 0), (-1, 0))); +dish.AddMorg(new TypeCMorg(5, (8, 8), (0, -1))); +dish.AddMorg(new TypeCMorg(6, (20, 5), (-1, 1))); + +const int RUN_TIME = 15; + +for (int timeStep = 0; timeStep < RUN_TIME; timeStep++) + foreach (var morg in dish.GetAllMorgs()) + if (morg.IsAlive) + { + if (morg.Prey == null || !morg.Prey.IsAlive) + { + var nearestPrey = dish.FindNearestPrey(morg); + + if (nearestPrey != null) + { + nearestPrey.Attach(morg); + + morg.Prey = nearestPrey; + morg.Direction = morg.CalculateDirectionToTarget(nearestPrey.Location); + } + } + + morg.Move(); + morg.Notify(); + + if (morg.Prey != null && morg.Prey.IsAlive && morg.DistanceTo(morg.Prey.Location) <= 1.0) + morg.Feed(); + } diff --git a/MorgSimulator/Type/TypeAMorg.cs b/MorgSimulator/Type/TypeAMorg.cs new file mode 100644 index 0000000..376f054 --- /dev/null +++ b/MorgSimulator/Type/TypeAMorg.cs @@ -0,0 +1,16 @@ +namespace MorgSimulator +{ + public class TypeAMorg : Morg + { + public TypeAMorg(int id, (int x, int y) location, (int x, int y) direction) + : base(id, location, direction) + { + Type = "A"; + MovementStrategy = new MovementStrategyPaddles(); + FeedingStrategy = new FeedingStrategyAbsorbs(); + + PreyTypes.Add("B"); + PreyTypes.Add("C"); + } + } +} diff --git a/MorgSimulator/Type/TypeBMorg.cs b/MorgSimulator/Type/TypeBMorg.cs new file mode 100644 index 0000000..5b235ed --- /dev/null +++ b/MorgSimulator/Type/TypeBMorg.cs @@ -0,0 +1,15 @@ +namespace MorgSimulator +{ + public class TypeBMorg : Morg + { + public TypeBMorg(int id, (int x, int y) location, (int x, int y) direction) + : base(id, location, direction) + { + Type = "B"; + MovementStrategy = new MovementStrategyOozes(); + FeedingStrategy = new FeedingStrategyEnvelops(); + + PreyTypes.Add("A"); + } + } +} diff --git a/MorgSimulator/Type/TypeCMorg.cs b/MorgSimulator/Type/TypeCMorg.cs new file mode 100644 index 0000000..35577a1 --- /dev/null +++ b/MorgSimulator/Type/TypeCMorg.cs @@ -0,0 +1,16 @@ +namespace MorgSimulator +{ + public class TypeCMorg : Morg + { + public TypeCMorg(int id, (int x, int y) location, (int x, int y) direction) + : base(id, location, direction) + { + Type = "C"; + MovementStrategy = new MovementStrategyPaddles(); + FeedingStrategy = new FeedingStrategyEnvelops(); + + PreyTypes.Add("A"); + PreyTypes.Add("B"); + } + } +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..976d1b8 --- /dev/null +++ b/justfile @@ -0,0 +1,15 @@ +name := "MorgSimulator" + +alias fmt := format + +dotnet_execute command: + dotnet {{ command }} ./{{ name }}.csproj --verbosity diagnostic + +format: + just dotnet_execute format + +build: + just dotnet_execute build + +run: + just dotnet_execute run |