ElevatorDiag/Elevator.cs

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;
}
}