From ed352d2d9ec8b297b6c8687b3e754d9610734697 Mon Sep 17 00:00:00 2001 From: Magnus Date: Thu, 19 Mar 2026 18:26:53 +0100 Subject: [PATCH 1/5] fix: don't use stupid type aliasing --- lib/elevator/cab_orders.ex | 16 ++++++------- lib/elevator/communicator.ex | 7 ++---- lib/elevator/fsm/state.ex | 3 +-- lib/elevator/hall_orders.ex | 22 +++++++++--------- lib/elevator/hall_orders/cost.ex | 15 +++++++------ lib/elevator/hall_orders/order.ex | 31 +++++++++++++------------- lib/elevator/hall_orders/simulation.ex | 18 ++++++++------- 7 files changed, 55 insertions(+), 57 deletions(-) diff --git a/lib/elevator/cab_orders.ex b/lib/elevator/cab_orders.ex index 3a0ec42..8751027 100644 --- a/lib/elevator/cab_orders.ex +++ b/lib/elevator/cab_orders.ex @@ -4,11 +4,9 @@ defmodule Elevator.CabOrders do """ use GenServer - @type floor :: Elevator.floor() - @type cab_orders_snapshot :: %{ version: non_neg_integer(), - orders: MapSet.t(floor()) + orders: MapSet.t(Elevator.floor()) } @type cab_order_map :: %{Node.t() => cab_orders_snapshot()} @@ -33,7 +31,7 @@ defmodule Elevator.CabOrders do @doc """ Retrieve *this* node's current cab orders. """ - @spec get_my_orders() :: MapSet.t(floor()) + @spec get_my_orders() :: MapSet.t(Elevator.floor()) def get_my_orders(), do: GenServer.call(__MODULE__, :get_my_orders) @doc """ @@ -47,13 +45,13 @@ defmodule Elevator.CabOrders do @doc """ Add a cab order and increment our own version number. """ - @spec button_press(floor()) :: :ok + @spec button_press(Elevator.floor()) :: :ok def button_press(floor), do: GenServer.cast(__MODULE__, {:button_press, floor}) @doc """ Remove a cab order and increment our own version number. """ - @spec arrived_at_floor(floor()) :: :ok + @spec arrived_at_floor(Elevator.floor()) :: :ok def arrived_at_floor(floor), do: GenServer.cast(__MODULE__, {:arrived_at_floor, floor}) # Calls -------------------------------------------------- @@ -85,7 +83,8 @@ defmodule Elevator.CabOrders do end @impl true - @spec handle_cast({:button_press, floor()}, cab_order_map()) :: {:noreply, cab_order_map()} + @spec handle_cast({:button_press, Elevator.floor()}, cab_order_map()) :: + {:noreply, cab_order_map()} def handle_cast({:button_press, floor}, order_map) do new_order_map = Map.update!(order_map, Node.self(), fn %{version: old_version, orders: old_orders} -> @@ -96,7 +95,8 @@ defmodule Elevator.CabOrders do end @impl true - @spec handle_cast({:arrived_at_floor, floor()}, cab_order_map()) :: {:noreply, cab_order_map()} + @spec handle_cast({:arrived_at_floor, Elevator.floor()}, cab_order_map()) :: + {:noreply, cab_order_map()} def handle_cast({:arrived_at_floor, floor}, order_map) do new_order_map = Map.update!(order_map, Node.self(), fn %{version: old_version, orders: old_orders} -> diff --git a/lib/elevator/communicator.ex b/lib/elevator/communicator.ex index c02c917..4e056b0 100644 --- a/lib/elevator/communicator.ex +++ b/lib/elevator/communicator.ex @@ -11,9 +11,6 @@ defmodule Elevator.Communicator do require Logger use GenServer - @type hall_order_map :: Elevator.HallOrders.hall_order_map() - @type cab_order_map :: Elevator.CabOrders.cab_order_map() - @type peer_status_map :: %{ Node.t() => %{operational: boolean(), timestamp: Time.t()} } @@ -21,8 +18,8 @@ defmodule Elevator.Communicator do @type communicator_message :: %{ from: Node.t(), operational: boolean(), - hall_order_map: hall_order_map(), - cab_order_map: cab_order_map() + hall_order_map: HallOrders.hall_order_map(), + cab_order_map: CabOrders.cab_order_map() } @type communicator_options :: [do_resend: boolean()] diff --git a/lib/elevator/fsm/state.ex b/lib/elevator/fsm/state.ex index 91b7278..30b0978 100644 --- a/lib/elevator/fsm/state.ex +++ b/lib/elevator/fsm/state.ex @@ -16,7 +16,6 @@ defmodule Elevator.FSM.State do motor_timed_out: false, obstructed: false - @type floor :: Elevator.floor() @type elev_behavior :: :moving | :idle | :door_open @type t :: %__MODULE__{ @@ -48,7 +47,7 @@ defmodule Elevator.FSM.State do @doc """ Updates floor and between_floors status. """ - @spec set_floor(:between_floors | floor()) :: :ok + @spec set_floor(:between_floors | Elevator.floor()) :: :ok def set_floor(floor), do: GenServer.cast(__MODULE__, {:set_floor, floor}) @doc """ diff --git a/lib/elevator/hall_orders.ex b/lib/elevator/hall_orders.ex index 78f0400..3bc4832 100644 --- a/lib/elevator/hall_orders.ex +++ b/lib/elevator/hall_orders.ex @@ -13,16 +13,14 @@ defmodule Elevator.HallOrders do require Logger use GenServer - @type floor :: Elevator.floor() - @type hall_button_type :: :hall_down | :hall_up - @type hall_button :: {floor(), hall_button_type()} + @type hall_button :: {Elevator.floor(), hall_button_type()} - @type hall_order_cost_map :: %{Node.t() => non_neg_integer()} + @type cost_map :: %{Node.t() => non_neg_integer()} @type hall_order_state :: :idle | {:pending, MapSet.t()} - | {:handling, hall_order_map()} + | {:handling, cost_map()} | {:arrived, MapSet.t()} @type hall_order_map :: %{hall_button() => hall_order_state()} @@ -66,14 +64,14 @@ defmodule Elevator.HallOrders do @doc """ Places the corresponding order in pending state if it is in idle. """ - @spec button_press(floor(), hall_button_type()) :: :ok + @spec button_press(Elevator.floor(), hall_button_type()) :: :ok def button_press(floor, button_type), do: GenServer.cast(__MODULE__, {:button_press, floor, button_type}) @doc """ Advances the order to arrived if it is in handling. """ - @spec arrived_at_floor(floor(), :up | :down) :: :ok + @spec arrived_at_floor(Elevator.floor(), :up | :down) :: :ok def arrived_at_floor(floor, direction), do: GenServer.cast(__MODULE__, {:arrived_at_floor, floor, direction}) @@ -86,14 +84,14 @@ defmodule Elevator.HallOrders do @doc """ Retrieve only the orders we are going to take. """ - @spec get_my_orders() :: %{floor() => MapSet.t(hall_button_type())} + @spec get_my_orders() :: %{Elevator.floor() => MapSet.t(hall_button_type())} def get_my_orders(), do: GenServer.call(__MODULE__, :get_my_orders) @doc """ Get all orders in handling state, in the same format as get_my_orders. These are the orders we turn the light on for. """ - @spec get_handling_orders() :: %{floor() => MapSet.t(hall_button_type())} + @spec get_handling_orders() :: %{Elevator.floor() => MapSet.t(hall_button_type())} def get_handling_orders(), do: GenServer.call(__MODULE__, :get_handling_orders) # Calls -------------------------------------------------- @@ -184,7 +182,9 @@ defmodule Elevator.HallOrders do # Return the orders where we have the lowest cost among serving nodes. # Only consider orders where all serving nodes have a cost. - @spec my_orders_from_order_map(hall_order_map()) :: %{floor() => MapSet.t(hall_button_type())} + @spec my_orders_from_order_map(hall_order_map()) :: %{ + Elevator.floor() => MapSet.t(hall_button_type()) + } defp my_orders_from_order_map(order_map) do who_can_serve = Communicator.who_can_serve() @@ -202,7 +202,7 @@ defmodule Elevator.HallOrders do @type enum_orders :: hall_order_map() | Enumerable.t({hall_button(), any()}) - @spec orders_by_floor(enum_orders()) :: %{floor() => MapSet.t(hall_button())} + @spec orders_by_floor(enum_orders()) :: %{Elevator.floor() => MapSet.t(hall_button_type())} defp orders_by_floor(orders) do # Restructure order map to the format floor => MapSet(button_type) orders diff --git a/lib/elevator/hall_orders/cost.ex b/lib/elevator/hall_orders/cost.ex index 9367fd6..81ec8bd 100644 --- a/lib/elevator/hall_orders/cost.ex +++ b/lib/elevator/hall_orders/cost.ex @@ -3,22 +3,23 @@ defmodule Elevator.HallOrders.Cost do Hall order cost utilities. Cost is estimated by simulating the local elevator with current orders plus the candidate hall order. + See `m:Elevator.HallOrders.Simulation` for simulation logic. """ + alias Elevator.HallOrders alias Elevator.CabOrders alias Elevator.FSM.State alias Elevator.OrderUtils alias Elevator.HallOrders.Simulation require Logger - @type floor :: Elevator.floor() - @type hall_button_type :: Elevator.HallOrders.hall_button_type() - @type cost_map :: Elevator.HallOrders.hall_order_cost_map() - @doc """ Compute the cost (time to serve) of a candidate hall order by simulating single elevator logic. """ - @spec compute_cost({floor(), hall_button_type()}, %{floor() => MapSet.t(hall_button_type())}) :: + @spec compute_cost( + {Elevator.floor(), Elevator.HallOrders.hall_button_type()}, + %{Elevator.floor() => MapSet.t(Elevator.HallOrders.hall_button_type())} + ) :: non_neg_integer() def compute_cost({floor, hall_button_type}, my_hall_orders) do state = State.get_state() @@ -42,7 +43,7 @@ defmodule Elevator.HallOrders.Cost do Merge two cost maps. Uses pessimistic merge: If two conflicting costs for the same node are found, keep the higher one. """ - @spec merge_cost(cost_map(), cost_map()) :: cost_map() + @spec merge_cost(HallOrders.cost_map(), HallOrders.cost_map()) :: HallOrders.cost_map() def merge_cost(cost_map, other_cost_map) do Map.merge(cost_map, other_cost_map, fn _node, cost, other_cost -> max(cost, other_cost) @@ -53,7 +54,7 @@ defmodule Elevator.HallOrders.Cost do Returns if we are supposed to take the order given the cost map. Assumes who_can_serve is a subset of cost_map keys. """ - @spec assigned_to_me?(cost_map(), MapSet.t(node())) :: boolean() + @spec assigned_to_me?(HallOrders.cost_map(), MapSet.t(node())) :: boolean() def assigned_to_me?(cost_map, who_can_serve) do {min_node, _} = Enum.filter(cost_map, fn {node, _} -> MapSet.member?(who_can_serve, node) end) diff --git a/lib/elevator/hall_orders/order.ex b/lib/elevator/hall_orders/order.ex index 6deee3f..ec82953 100644 --- a/lib/elevator/hall_orders/order.ex +++ b/lib/elevator/hall_orders/order.ex @@ -9,24 +9,22 @@ defmodule Elevator.HallOrders.Order do - pending: Someone pressed a button, but everyone does not know it. Light: off - handling: All alive nodes know about the order and has indicated their cost to serve it. Light: on. - arrived: A node is signalling that the order has been served. Light: off + + This module contains functions for transitioning between states. """ + alias Elevator.HallOrders alias Elevator.HallOrders.Cost alias Elevator.Communicator - @type floor :: Elevator.floor() - @type hall_button :: Elevator.HallOrders.hall_button() - @type hall_button_type :: Elevator.HallOrders.hall_button_type() - @type hall_order_state :: Elevator.HallOrders.hall_order_state() - @doc """ Update a hall order based on an incoming hall order from another node. """ @spec update_from_incoming( - hall_button(), - hall_order_state(), - hall_order_state(), - %{floor() => MapSet.t(hall_button_type())} - ) :: hall_order_state() + HallOrders.hall_button(), + HallOrders.hall_order_state(), + HallOrders.hall_order_state(), + %{Elevator.floor() => MapSet.t(HallOrders.hall_button_type())} + ) :: HallOrders.hall_order_state() def update_from_incoming(order_key, order_state, incoming_order_state, my_hall_orders) do order_state |> merge_with_incoming(incoming_order_state) @@ -39,10 +37,10 @@ defmodule Elevator.HallOrders.Order do Returns `{true, new_value}` if the state changed, `{false, old_value}` otherwise. """ @spec update_from_barrier_state( - hall_button(), - hall_order_state(), - %{floor() => MapSet.t(hall_button_type())} - ) :: hall_order_state() + HallOrders.hall_button(), + HallOrders.hall_order_state(), + %{Elevator.floor() => MapSet.t(HallOrders.hall_button_type())} + ) :: HallOrders.hall_order_state() def update_from_barrier_state(order_key, order_state, my_hall_orders) do order_state |> transition_from_barrier_state(Communicator.who_is_alive()) @@ -50,14 +48,15 @@ defmodule Elevator.HallOrders.Order do |> ensure_self_in_cost_map(order_key, my_hall_orders) end - @spec update_from_button_press(hall_order_state()) :: hall_order_state() + @spec update_from_button_press(HallOrders.hall_order_state()) :: HallOrders.hall_order_state() def update_from_button_press(:idle) do ensure_self_in_barriers({:pending, MapSet.new()}) end def update_from_button_press(order_state), do: order_state - @spec update_from_button_press(hall_order_state()) :: hall_order_state() + @spec update_from_arrived_at_floor(HallOrders.hall_order_state()) :: + HallOrders.hall_order_state() def update_from_arrived_at_floor({:handling, _}) do ensure_self_in_barriers({:arrived, MapSet.new()}) end diff --git a/lib/elevator/hall_orders/simulation.ex b/lib/elevator/hall_orders/simulation.ex index 459b61e..5e5087f 100644 --- a/lib/elevator/hall_orders/simulation.ex +++ b/lib/elevator/hall_orders/simulation.ex @@ -3,6 +3,8 @@ defmodule Elevator.HallOrders.Simulation do Pure hall-order cost simulation. """ + alias Elevator.HallOrders + alias Elevator.OrderUtils alias Elevator.FSM.State alias Elevator.FSM.Transition @@ -10,19 +12,15 @@ defmodule Elevator.HallOrders.Simulation do @max_simulation_steps 256 @unreachable_cost 30000 - @type floor :: Elevator.floor() - @type hall_button_type :: Elevator.HallOrders.hall_button_type() - @type combined_order_map :: Elevator.OrderUtils.combined_order_map() - defmodule SimState do @enforce_keys [:orders, :elevator_state, :target, :time_ms, :steps_left] defstruct [:orders, :elevator_state, :target, :time_ms, :steps_left] end @type simulation :: %SimState{ - orders: combined_order_map(), + orders: OrderUtils.combined_order_map(), elevator_state: State.t(), - target: {floor(), hall_button_type()}, + target: {Elevator.floor(), HallOrders.hall_button_type()}, time_ms: non_neg_integer(), steps_left: non_neg_integer() } @@ -33,7 +31,7 @@ defmodule Elevator.HallOrders.Simulation do @spec unreachable_cost() :: non_neg_integer() def unreachable_cost, do: @unreachable_cost - @spec initial_time_ms(State.t(), floor()) :: number() + @spec initial_time_ms(State.t(), Elevator.floor()) :: non_neg_integer() def initial_time_ms(elevator_state, target_floor) do cond do elevator_state.behavior == :door_open and target_floor != elevator_state.floor -> @@ -47,7 +45,11 @@ defmodule Elevator.HallOrders.Simulation do end end - @spec simulate_time_until_served(combined_order_map(), State.t(), {floor(), hall_button_type()}) :: + @spec simulate_time_until_served( + OrderUtils.combined_order_map(), + State.t(), + {Elevator.floor(), HallOrders.hall_button_type()} + ) :: non_neg_integer() def simulate_time_until_served(_orders, %{floor: :unknown} = _elevator_state, _target), do: @unreachable_cost From e85f4e2b97559002559bef960e24a2b205beb7b8 Mon Sep 17 00:00:00 2001 From: Magnus Date: Thu, 19 Mar 2026 18:40:38 +0100 Subject: [PATCH 2/5] chore: improve docs --- lib/elevator/application.ex | 6 ++++++ lib/elevator/cab_orders.ex | 10 +++++++++- lib/elevator/communicator.ex | 3 ++- lib/elevator/fsm/state.ex | 1 - lib/elevator/fsm/transition.ex | 3 +-- lib/elevator/hall_orders.ex | 8 +++++--- lib/elevator/hall_orders/cost.ex | 1 - lib/elevator/hardware/input_poller.ex | 1 - lib/elevator/hardware/outputs.ex | 2 +- 9 files changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/elevator/application.ex b/lib/elevator/application.ex index 57e7552..6a634ca 100644 --- a/lib/elevator/application.ex +++ b/lib/elevator/application.ex @@ -1,4 +1,10 @@ defmodule Elevator.Application do + @moduledoc """ + Main entry point, starting the supervisor. + Supervisor children ordering is somewhat based on abstraction level: + modules "closer" to hardware are started last because they are more likely to crash. + Combined with the rest_for_one strategy, this lets us keep high level state when a lower level module crashes. + """ use Application @spec start(Application.start_type(), term()) :: {:ok, pid()} | {:error, term()} diff --git a/lib/elevator/cab_orders.ex b/lib/elevator/cab_orders.ex index 8751027..d324916 100644 --- a/lib/elevator/cab_orders.ex +++ b/lib/elevator/cab_orders.ex @@ -1,6 +1,14 @@ defmodule Elevator.CabOrders do @moduledoc """ - Module responsible for all changes occuring to the cab_order part of the state. + Module responsible for all changes occurring to cab orders. + This is a stateful module, storing our current view of the cab order states. + + This module handles the following events that can change cab orders: + - Button is pressed. + - Arrived at floor. + - Received cab orders from another node *with a higher version number*. + + Only increments our own version number; peer's version numbers are kept as is. """ use GenServer diff --git a/lib/elevator/communicator.ex b/lib/elevator/communicator.ex index 4e056b0..09a2cc3 100644 --- a/lib/elevator/communicator.ex +++ b/lib/elevator/communicator.ex @@ -1,6 +1,8 @@ defmodule Elevator.Communicator do @moduledoc """ Module responsible for all communication with other elevators. + For each peer, their status and last message time is stored. + Runs a loop broadcasting our hall- and cab orders periodically. """ alias Elevator.FSM.State @@ -8,7 +10,6 @@ defmodule Elevator.Communicator do alias Elevator.CabOrders alias Elevator.HallOrders - require Logger use GenServer @type peer_status_map :: %{ diff --git a/lib/elevator/fsm/state.ex b/lib/elevator/fsm/state.ex index 30b0978..11d5e55 100644 --- a/lib/elevator/fsm/state.ex +++ b/lib/elevator/fsm/state.ex @@ -5,7 +5,6 @@ defmodule Elevator.FSM.State do Acts as the single source of truth for what the elevator *is* right now - its floor, direction, behavior, and fault conditions. """ - require Logger defstruct behavior: :moving, between_floors: true, diff --git a/lib/elevator/fsm/transition.ex b/lib/elevator/fsm/transition.ex index bfc7411..fe5c0ab 100644 --- a/lib/elevator/fsm/transition.ex +++ b/lib/elevator/fsm/transition.ex @@ -1,12 +1,11 @@ defmodule Elevator.FSM.Transition do @moduledoc """ - Loop handling FSM transitions. + Loop driving FSM transitions at a fixed interval. One iteration of the loop does the following: - Checks door and motor timeouts - Reads and updates state and orders - Sets hardware outputs """ - require Logger alias Elevator.CabOrders alias Elevator.FSM.State diff --git a/lib/elevator/hall_orders.ex b/lib/elevator/hall_orders.ex index 3bc4832..8d12924 100644 --- a/lib/elevator/hall_orders.ex +++ b/lib/elevator/hall_orders.ex @@ -1,7 +1,10 @@ defmodule Elevator.HallOrders do @moduledoc """ - Module responsible for all changes occuring to the hall_order part of the state. - The events that can change hall orders are: + Module responsible for all changes occurring to the hall orders. + This is a stateful module storing our current view on the hall order states. + See `m:Elevator.HallOrders.Order` for information about single hall order states. + + This module handles the following events that can change hall orders: - Button is pressed. - Arrived at floor. - Received hall orders from another node. @@ -10,7 +13,6 @@ defmodule Elevator.HallOrders do alias Elevator.HallOrders.Order alias Elevator.HallOrders.Cost alias Elevator.Communicator - require Logger use GenServer @type hall_button_type :: :hall_down | :hall_up diff --git a/lib/elevator/hall_orders/cost.ex b/lib/elevator/hall_orders/cost.ex index 81ec8bd..5e850e5 100644 --- a/lib/elevator/hall_orders/cost.ex +++ b/lib/elevator/hall_orders/cost.ex @@ -11,7 +11,6 @@ defmodule Elevator.HallOrders.Cost do alias Elevator.FSM.State alias Elevator.OrderUtils alias Elevator.HallOrders.Simulation - require Logger @doc """ Compute the cost (time to serve) of a candidate hall order by simulating single elevator logic. diff --git a/lib/elevator/hardware/input_poller.ex b/lib/elevator/hardware/input_poller.ex index 276aaae..1c9af08 100644 --- a/lib/elevator/hardware/input_poller.ex +++ b/lib/elevator/hardware/input_poller.ex @@ -5,7 +5,6 @@ defmodule Elevator.Hardware.InputPoller do """ use GenServer - require Logger alias Elevator.CabOrders alias Elevator.HallOrders diff --git a/lib/elevator/hardware/outputs.ex b/lib/elevator/hardware/outputs.ex index 5580a0c..7110961 100644 --- a/lib/elevator/hardware/outputs.ex +++ b/lib/elevator/hardware/outputs.ex @@ -1,9 +1,9 @@ defmodule Elevator.Hardware.Outputs do @moduledoc """ Sets driver outputs given state and orders. + The `Outputs.set_outputs/2` function is called by `m:Elevator.FSM.Transition` after each transition. """ - require Logger alias Elevator.Hardware.Driver alias Elevator.FSM From 160a5c5963d36f10557d2e9dbec992cf19561645 Mon Sep 17 00:00:00 2001 From: Magnus Date: Thu, 19 Mar 2026 18:49:05 +0100 Subject: [PATCH 3/5] chore: chore: chore --- lib/elevator/hall_orders.ex | 6 +++--- lib/elevator/hall_orders/order.ex | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/elevator/hall_orders.ex b/lib/elevator/hall_orders.ex index 8d12924..89f8865 100644 --- a/lib/elevator/hall_orders.ex +++ b/lib/elevator/hall_orders.ex @@ -159,6 +159,8 @@ defmodule Elevator.HallOrders do {:noreply, new_order_map, {:continue, :hall_update_state}} end + # Changes to who is alive can occur even if we receive no events. + # Therefore we periodically check if some barrier-set states should advance. @impl true def handle_info(:refresh_hall_orders, order_map) do Process.send_after(self(), :refresh_hall_orders, @hall_order_refresh_period_ms) @@ -167,9 +169,7 @@ defmodule Elevator.HallOrders do # Continues -------------------------------------------------- - @doc """ - May advance some states, in which case continue is called until convergence. - """ + # Some states may be advanced if their barrier sets are full. @impl true def handle_continue(:hall_update_state, order_map) do my_orders = my_orders_from_order_map(order_map) diff --git a/lib/elevator/hall_orders/order.ex b/lib/elevator/hall_orders/order.ex index ec82953..165713f 100644 --- a/lib/elevator/hall_orders/order.ex +++ b/lib/elevator/hall_orders/order.ex @@ -34,7 +34,6 @@ defmodule Elevator.HallOrders.Order do @doc """ Advances a pending or arrived order if the respective barrier set is full. - Returns `{true, new_value}` if the state changed, `{false, old_value}` otherwise. """ @spec update_from_barrier_state( HallOrders.hall_button(), From 61d7267c142b246621d5e39ced20c4b8e26cf3e3 Mon Sep 17 00:00:00 2001 From: Magnus Date: Thu, 19 Mar 2026 18:53:23 +0100 Subject: [PATCH 4/5] chore: update readme for handin --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 47bbda9..baf9d73 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # TTK4145 Elevator -### LOC stats (Elixir) -**Lib:** 1063\ -**Test:** 585 +Elevator application for controlling `n` elevators across `m` floors +in a distributed fashion, implemented in Elixir. + +## Documentation + +See `doc/index.html` for module documentation. ## Running nodes @@ -97,3 +100,8 @@ sudo ./scripts/packetloss.sh -ie - `-i` is incomming traffic - `-o`is outgoing - `-e`is Elixir/Erlang and autodetects Beam ports + +## LOC stats (Elixir) + +**Lib:** 1063\ +**Test:** 585 From 87367e4692d176fc2a1c25d8676b9ae69e41e1bf Mon Sep 17 00:00:00 2001 From: Magnus Date: Thu, 19 Mar 2026 18:56:39 +0100 Subject: [PATCH 5/5] super based fix --- lib/elevator/fsm/state.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/elevator/fsm/state.ex b/lib/elevator/fsm/state.ex index 11d5e55..791df23 100644 --- a/lib/elevator/fsm/state.ex +++ b/lib/elevator/fsm/state.ex @@ -6,8 +6,8 @@ defmodule Elevator.FSM.State do its floor, direction, behavior, and fault conditions. """ - defstruct behavior: :moving, - between_floors: true, + defstruct behavior: :idle, + between_floors: false, direction: :down, door_open_time: Time.utc_now(), floor: :unknown,