Current section
Files
Jump to
Current section
Files
lib/costFunction.ex
defmodule CostFunction do
@moduledoc """
A module for calculating the cost of taking a new order.
"""
@timeBetweenFloors Application.compile_env(:elevator, :timeBetweenFloors)
@waitTimeOnFloor Application.compile_env(:elevator, :waitTimeOnFloor)
# Public functions
# --------------------------------------------
def calculate({_newFloor, _buttonType}, _orderQueue, :unknownFloor, _availability), do: Inf
@doc "Calculates the cost of taking a new order (as button press) given the current queue of orders."
def calculate({newFloor, buttonType}, orderQueue, floor, availability)
when buttonType != :cab do
cond do
availability == :unavailable ->
Inf
Enum.any?(orderQueue, fn {floor, _, _} -> floor == newFloor end) ->
0
true ->
fullOrderQueue = [{newFloor, buttonType, node()} | orderQueue] |> Enum.reverse()
calculateCostRec(fullOrderQueue, floor)
end
end
# Private functions
# --------------------------------------------
# Calculates recursively the cost (time) of handling a given orderQueue if the elevator is currently on a given floor.
defp calculateCostRec([], _) do
0
end
defp calculateCostRec(orderQueue, startFloor) do
[nextOrder | _] = orderQueue
{nextFloor, _, _} = nextOrder
travelDirection =
with floorDiff <- nextFloor - startFloor do
cond do
floorDiff < 0 -> :down
floorDiff > 0 -> :up
floorDiff == 0 -> :idle
end
end
intermediateStoppingFloors =
orderQueue
|> Enum.filter(fn {floor, orderType, _} ->
floor in startFloor..nextFloor && !(floor in [startFloor, nextFloor]) &&
orderType in [travelDirection, :cab]
end)
|> Enum.map(fn {floor, _, _} -> floor end)
|> Enum.uniq()
stoppingFloors = [nextFloor | intermediateStoppingFloors]
floorsTraveled = abs(nextFloor - startFloor)
floorsWaitedOn = Enum.count(stoppingFloors)
remainingOrderQueue = Enum.reject(orderQueue, fn {floor, _, _} -> floor in stoppingFloors end)
@timeBetweenFloors * floorsTraveled + @waitTimeOnFloor * floorsWaitedOn +
calculateCostRec(remainingOrderQueue, nextFloor)
end
end