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 PreyTypes { get; protected set; } = new List(); #nullable enable public Morg? Prey { get; set; } #nullable disable private readonly List _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); } } }