diff options
| author | Fuwn <[email protected]> | 2025-11-20 19:17:14 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-11-20 19:17:14 -0800 |
| commit | 9858b069ea4264840d98094e2e36ad2517f2215f (patch) | |
| tree | 367ac8bcab6107ef8dfa4be524f834a5336d9bc3 | |
| parent | feat: Add Assignment 2 diagrams (diff) | |
| download | cst276-9858b069ea4264840d98094e2e36ad2517f2215f.tar.xz cst276-9858b069ea4264840d98094e2e36ad2517f2215f.zip | |
feat: Implement Assignment 3 functionality
20 files changed, 268 insertions, 153 deletions
diff --git a/MorgSimulator/Dish.cs b/MorgSimulator/Dish.cs index 1813d5a..38f1bc0 100644 --- a/MorgSimulator/Dish.cs +++ b/MorgSimulator/Dish.cs @@ -1,29 +1,26 @@ -using System.Collections.Generic; -using System.Linq; +using MorgSimulator.Framework; namespace MorgSimulator { - public class Dish + public class Dish : Simulator<Morg> { - private readonly List<Morg> _morgs = []; - public void AddMorg(Morg morg) { - _morgs.Add(morg); + AddEntity(morg); } - public List<Morg> GetAllMorgs() + public System.Collections.Generic.List<Morg> GetAllMorgs() { - return [.. _morgs]; + return [.. _entities]; } #nullable enable - public Morg? FindNearestPrey(Morg predator) + protected override Entity? FindNearestPrey(Morg predator) { Morg? nearestPrey = null; double nearestDistance = double.MaxValue; - foreach (var potentialPrey in _morgs) + foreach (var potentialPrey in _entities) if (potentialPrey.IsAlive && potentialPrey != predator && predator.CanEat(potentialPrey.Type)) diff --git a/MorgSimulator/Factory/IMorgFactory.cs b/MorgSimulator/Factory/IMorgFactory.cs deleted file mode 100644 index 60537de..0000000 --- a/MorgSimulator/Factory/IMorgFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MorgSimulator.Factory -{ - public interface IMorgFactory - { - Morg CreateMorg(int id, string type, int x, int y, string movement, string feeding); - IMovementStrategy CreateMovementStrategy(string movementType); - IFeedingStrategy CreateFeedingStrategy(string behavior); - } -} diff --git a/MorgSimulator/Factory/MorgFactory.cs b/MorgSimulator/Factory/MorgFactory.cs index 95ecbee..3a6ef79 100644 --- a/MorgSimulator/Factory/MorgFactory.cs +++ b/MorgSimulator/Factory/MorgFactory.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; +using MorgSimulator.Framework; namespace MorgSimulator.Factory { - public class MorgFactory : IMorgFactory + public class MorgFactory : IEntityFactory<Morg> { - public Morg CreateMorg(int id, string type, int x, int y, string movement, string feeding) + public Morg CreateEntity(int id, string type, int x, int y, string movement, string feeding) { var trimmedFeeding = feeding.Trim(); var feedingParts = trimmedFeeding.Split(' '); diff --git a/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs b/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs index 9e0f9a0..e5fb8c9 100644 --- a/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs +++ b/MorgSimulator/FeedingStrategy/FeedingStrategyAbsorbs.cs @@ -1,8 +1,10 @@ +using MorgSimulator.Framework; + namespace MorgSimulator { public class FeedingStrategyAbsorbs : IFeedingStrategy { - public void Feed(Morg predator, Morg prey) + public void Feed(Entity predator, Entity prey) { System.Console.WriteLine($"Morg {predator.Id} Absorbs Morg {prey.Id} at ({prey.Location.x},{prey.Location.y})"); diff --git a/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs b/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs index d35227c..c5b96a3 100644 --- a/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs +++ b/MorgSimulator/FeedingStrategy/FeedingStrategyEnvelops.cs @@ -1,8 +1,10 @@ +using MorgSimulator.Framework; + namespace MorgSimulator { public class FeedingStrategyEnvelops : IFeedingStrategy { - public void Feed(Morg predator, Morg prey) + public void Feed(Entity predator, Entity prey) { System.Console.WriteLine($"Morg {predator.Id} Envelops Morg {prey.Id} at ({prey.Location.x},{prey.Location.y})"); diff --git a/MorgSimulator/Framework/Entity.cs b/MorgSimulator/Framework/Entity.cs new file mode 100644 index 0000000..d415fdd --- /dev/null +++ b/MorgSimulator/Framework/Entity.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; + +namespace MorgSimulator.Framework +{ + public abstract class Entity(int id, (int x, int y) location, (int x, int y) direction) + { + public int Id { get; set; } = id; + public string Type { get; 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; set; } = null!; + public IFeedingStrategy FeedingStrategy { get; set; } = null!; + public List<string> PreyTypes { get; set; } = []; +#nullable enable + public Entity? Prey { get; set; } +#nullable disable + + private readonly List<Entity> _observers = []; + + public void Attach(Entity observer) + { + if (!_observers.Contains(observer)) + _observers.Add(observer); + } + + public void Detach(Entity observer) + { + _observers.Remove(observer); + } + + public void Notify() + { + foreach (var observer in _observers) + observer.Update(this); + } + + public virtual void Update(Entity 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); + } + } +} diff --git a/MorgSimulator/Framework/EntityIterator.cs b/MorgSimulator/Framework/EntityIterator.cs new file mode 100644 index 0000000..84976c7 --- /dev/null +++ b/MorgSimulator/Framework/EntityIterator.cs @@ -0,0 +1,35 @@ +#nullable enable +using System.Collections.Generic; + +namespace MorgSimulator.Framework +{ + public class EntityIterator<T> : IEntityIterator<T> where T : Entity + { + private readonly List<T> _entities; + private int _currentIndex = 0; + + public EntityIterator(List<T> entities) + { + _entities = entities; + } + + public bool HasNext() + { + return _currentIndex < _entities.Count; + } + + public T? Next() + { + if (!HasNext()) + return null; + + return _entities[_currentIndex++]; + } + + public void Reset() + { + _currentIndex = 0; + } + } +} +#nullable disable diff --git a/MorgSimulator/Framework/EntityReader.cs b/MorgSimulator/Framework/EntityReader.cs new file mode 100644 index 0000000..b3c2fbd --- /dev/null +++ b/MorgSimulator/Framework/EntityReader.cs @@ -0,0 +1,11 @@ +#nullable enable +namespace MorgSimulator.Framework +{ + public abstract class EntityReader<T>(Reader.Reader reader, IEntityFactory<T> factory) : Reader.ReaderDecorator(reader) where T : Entity + { + protected readonly IEntityFactory<T> _factory = factory; + + public abstract T? ReadEntity(int id); + } +} +#nullable disable diff --git a/MorgSimulator/Framework/IEntityFactory.cs b/MorgSimulator/Framework/IEntityFactory.cs new file mode 100644 index 0000000..37da19d --- /dev/null +++ b/MorgSimulator/Framework/IEntityFactory.cs @@ -0,0 +1,9 @@ +namespace MorgSimulator.Framework +{ + public interface IEntityFactory<T> where T : Entity + { + T CreateEntity(int id, string type, int x, int y, string movement, string feeding); + IMovementStrategy CreateMovementStrategy(string movementType); + IFeedingStrategy CreateFeedingStrategy(string behavior); + } +} diff --git a/MorgSimulator/Framework/IEntityIterator.cs b/MorgSimulator/Framework/IEntityIterator.cs new file mode 100644 index 0000000..9333468 --- /dev/null +++ b/MorgSimulator/Framework/IEntityIterator.cs @@ -0,0 +1,11 @@ +#nullable enable +namespace MorgSimulator.Framework +{ + public interface IEntityIterator<T> where T : Entity + { + bool HasNext(); + T? Next(); + void Reset(); + } +} +#nullable disable diff --git a/MorgSimulator/Framework/IFeedingStrategy.cs b/MorgSimulator/Framework/IFeedingStrategy.cs new file mode 100644 index 0000000..cbbe315 --- /dev/null +++ b/MorgSimulator/Framework/IFeedingStrategy.cs @@ -0,0 +1,7 @@ +namespace MorgSimulator.Framework +{ + public interface IFeedingStrategy + { + void Feed(Entity predator, Entity prey); + } +} diff --git a/MorgSimulator/Framework/IMovementStrategy.cs b/MorgSimulator/Framework/IMovementStrategy.cs new file mode 100644 index 0000000..bb8d13d --- /dev/null +++ b/MorgSimulator/Framework/IMovementStrategy.cs @@ -0,0 +1,7 @@ +namespace MorgSimulator.Framework +{ + public interface IMovementStrategy + { + void Move(Entity entity, (int x, int y) newLocation); + } +} diff --git a/MorgSimulator/Framework/Simulator.cs b/MorgSimulator/Framework/Simulator.cs new file mode 100644 index 0000000..6e8c694 --- /dev/null +++ b/MorgSimulator/Framework/Simulator.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; + +namespace MorgSimulator.Framework +{ + public abstract class Simulator<T> where T : Entity + { + protected readonly List<T> _entities = []; + protected const double FEEDING_DISTANCE = 1.0; + + public void AddEntity(T entity) + { + _entities.Add(entity); + } + + public IEnumerable<T> GetAllEntities() + { + return _entities; + } + + public IEntityIterator<T> CreateIterator() + { + return new EntityIterator<T>(_entities); + } + + public void Run(int runTime) + { + for (int timeStep = 0; timeStep < runTime; timeStep++) + ProcessTimeStep(); + } + + protected virtual void ProcessTimeStep() + { + foreach (var entity in _entities) + if (entity.IsAlive) + { + FindPreyIfNeeded(entity); + entity.Move(); + CheckAndFeed(entity); + } + } + + protected virtual void FindPreyIfNeeded(T entity) + { + if (entity.Prey == null || !entity.Prey.IsAlive) + { + var nearestPrey = FindNearestPrey(entity); + + if (nearestPrey != null) + { + nearestPrey.Attach(entity); + + entity.Prey = nearestPrey as T; + entity.Direction = entity.CalculateDirectionToTarget(nearestPrey.Location); + } + } + } + + protected virtual void CheckAndFeed(T entity) + { + if (entity.Prey != null && entity.Prey.IsAlive && + entity.DistanceTo(entity.Prey.Location) <= FEEDING_DISTANCE) + entity.Feed(); + } + +#nullable enable + protected abstract Entity? FindNearestPrey(T predator); +#nullable disable + } +} diff --git a/MorgSimulator/IFeedingStrategy.cs b/MorgSimulator/IFeedingStrategy.cs deleted file mode 100644 index b0344ea..0000000 --- a/MorgSimulator/IFeedingStrategy.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace MorgSimulator -{ - public interface IFeedingStrategy - { - void Feed(Morg predator, Morg prey); - } -} diff --git a/MorgSimulator/IMovementStrategy.cs b/MorgSimulator/IMovementStrategy.cs deleted file mode 100644 index 2b073e1..0000000 --- a/MorgSimulator/IMovementStrategy.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace MorgSimulator -{ - public interface IMovementStrategy - { - void Move(Morg morg, (int x, int y) newLocation); - } -} diff --git a/MorgSimulator/Morg.cs b/MorgSimulator/Morg.cs index cfac9dd..ba91564 100644 --- a/MorgSimulator/Morg.cs +++ b/MorgSimulator/Morg.cs @@ -1,87 +1,9 @@ -using System.Collections.Generic; -using System.Linq; +using MorgSimulator.Framework; namespace MorgSimulator { public class Morg(int id, (int x, int y) location, (int x, int y) direction) + : Entity(id, location, direction) { - public int Id { get; set; } = id; - public string Type { get; 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; set; } = null!; - public IFeedingStrategy FeedingStrategy { get; set; } = null!; - public List<string> PreyTypes { get; set; } = []; -#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) - observer.Update(this); - } - - public void Update(Morg subject) - { - Direction = CalculateDirectionToTarget(subject.Location); - } - - public void Move() - { - if (!IsAlive) return; - - var newLocation = (Location.x + Direction.x, Location.y + Direction.y); - - MovementStrategy.Move(this, newLocation); - Notify(); - } - - public 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 index 217d175..dfc8423 100644 --- a/MorgSimulator/MovementStrategy/MovementStrategyOozes.cs +++ b/MorgSimulator/MovementStrategy/MovementStrategyOozes.cs @@ -1,12 +1,14 @@ +using MorgSimulator.Framework; + namespace MorgSimulator { public class MovementStrategyOozes : IMovementStrategy { - public void Move(Morg morg, (int x, int y) newLocation) + public void Move(Entity entity, (int x, int y) newLocation) { - System.Console.WriteLine($"Morg {morg.Id} Oozes from ({morg.Location.x},{morg.Location.y}) to ({newLocation.x},{newLocation.y})"); + System.Console.WriteLine($"Morg {entity.Id} Oozes from ({entity.Location.x},{entity.Location.y}) to ({newLocation.x},{newLocation.y})"); - morg.Location = newLocation; + entity.Location = newLocation; } } } diff --git a/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs b/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs index efdd3ef..ddbfe8c 100644 --- a/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs +++ b/MorgSimulator/MovementStrategy/MovementStrategyPaddles.cs @@ -1,12 +1,14 @@ +using MorgSimulator.Framework; + namespace MorgSimulator { public class MovementStrategyPaddles : IMovementStrategy { - public void Move(Morg morg, (int x, int y) newLocation) + public void Move(Entity entity, (int x, int y) newLocation) { - System.Console.WriteLine($"Morg {morg.Id} Paddles from ({morg.Location.x},{morg.Location.y}) to ({newLocation.x},{newLocation.y})"); + System.Console.WriteLine($"Morg {entity.Id} Paddles from ({entity.Location.x},{entity.Location.y}) to ({newLocation.x},{newLocation.y})"); - morg.Location = newLocation; + entity.Location = newLocation; } } } diff --git a/MorgSimulator/Program.cs b/MorgSimulator/Program.cs index 29fd971..3cb336b 100644 --- a/MorgSimulator/Program.cs +++ b/MorgSimulator/Program.cs @@ -11,7 +11,7 @@ int id = 1; while (!morgReader.EndOfStream) { - var morg = morgReader.ReadMorg(id++); + var morg = morgReader.ReadEntity(id++); if (morg != null) dish.AddMorg(morg); @@ -21,26 +21,4 @@ morgReader.Close(); 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(); - } +dish.Run(RUN_TIME); diff --git a/MorgSimulator/Reader/MorgReader.cs b/MorgSimulator/Reader/MorgReader.cs index 2bf9a30..56c229b 100644 --- a/MorgSimulator/Reader/MorgReader.cs +++ b/MorgSimulator/Reader/MorgReader.cs @@ -1,13 +1,12 @@ #nullable enable using MorgSimulator.Factory; +using MorgSimulator.Framework; namespace MorgSimulator.Reader { - public class MorgReader(Reader reader, IMorgFactory factory) : ReaderDecorator(reader) + public class MorgReader(Reader reader, IEntityFactory<Morg> factory) : EntityReader<Morg>(reader, factory) { - private readonly IMorgFactory _factory = factory; - - public Morg? ReadMorg(int id) + public override Morg? ReadEntity(int id) { if (_reader is not CSVReader csvReader) return null; @@ -25,7 +24,7 @@ namespace MorgSimulator.Reader !int.TryParse(yString, out int y)) return null; - return _factory.CreateMorg(id, type, x, y, movement, feeding); + return _factory.CreateEntity(id, type, x, y, movement, feeding); } } } |