109 lines
2.8 KiB
C#
109 lines
2.8 KiB
C#
namespace ElevatorDiag;
|
|
|
|
public enum ElevatorState
|
|
{
|
|
Idle,
|
|
MovingUp,
|
|
MovingDown,
|
|
DoorOpen,
|
|
Faulted
|
|
}
|
|
|
|
public class Elevator
|
|
{
|
|
public int CurrentFloor { get; private set; } = 1;
|
|
public double CurrentPosition { get; private set; } = 1.0;
|
|
public ElevatorState State { get; private set; } = ElevatorState.Idle;
|
|
public List<int> TargetFloors { get; } = new();
|
|
public string? LastFault { get; private set; }
|
|
|
|
private const double Speed = 0.5; // floors per tick
|
|
private const int DoorHoldTicks = 3;
|
|
private int _doorTimer = 0;
|
|
|
|
public void RequestFloor(int floor)
|
|
{
|
|
if (State == ElevatorState.Faulted) return;
|
|
if (!TargetFloors.Contains(floor))
|
|
{
|
|
TargetFloors.Add(floor);
|
|
// No automatic sort here, we'll handle direction in GetNextTarget
|
|
}
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (State == ElevatorState.Faulted) return;
|
|
|
|
if (State == ElevatorState.DoorOpen)
|
|
{
|
|
_doorTimer++;
|
|
if (_doorTimer >= DoorHoldTicks)
|
|
{
|
|
_doorTimer = 0;
|
|
State = ElevatorState.Idle;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (TargetFloors.Count == 0)
|
|
{
|
|
State = ElevatorState.Idle;
|
|
return;
|
|
}
|
|
|
|
int target = GetNextTarget();
|
|
|
|
if (CurrentPosition < target)
|
|
{
|
|
State = ElevatorState.MovingUp;
|
|
CurrentPosition += Speed;
|
|
}
|
|
else if (CurrentPosition > target)
|
|
{
|
|
State = ElevatorState.MovingDown;
|
|
CurrentPosition -= Speed;
|
|
}
|
|
|
|
CurrentFloor = (int)Math.Round(CurrentPosition);
|
|
|
|
if (Math.Abs(CurrentPosition - target) < 0.01)
|
|
{
|
|
CurrentPosition = target;
|
|
CurrentFloor = target;
|
|
TargetFloors.Remove(target);
|
|
State = ElevatorState.DoorOpen;
|
|
}
|
|
}
|
|
|
|
private int GetNextTarget()
|
|
{
|
|
// Simple logic: if moving, keep moving in same direction if targets exist
|
|
if (State == ElevatorState.MovingUp)
|
|
{
|
|
var up = TargetFloors.Where(f => f > CurrentPosition).OrderBy(f => f).FirstOrDefault();
|
|
if (up != 0) return up;
|
|
}
|
|
if (State == ElevatorState.MovingDown)
|
|
{
|
|
var down = TargetFloors.Where(f => f < CurrentPosition).OrderByDescending(f => f).FirstOrDefault();
|
|
if (down != 0) return down;
|
|
}
|
|
|
|
// Closest if idle or changed direction
|
|
return TargetFloors.OrderBy(f => Math.Abs(f - CurrentPosition)).First();
|
|
}
|
|
|
|
public void TriggerFault(string reason)
|
|
{
|
|
State = ElevatorState.Faulted;
|
|
LastFault = reason;
|
|
}
|
|
|
|
public void ResetFault()
|
|
{
|
|
State = ElevatorState.Idle;
|
|
LastFault = null;
|
|
}
|
|
}
|