-
Notifications
You must be signed in to change notification settings - Fork 1
/
order_manager.erl
157 lines (133 loc) · 5.09 KB
/
order_manager.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
-module(order_manager).
-export([start/0, find_position/3, ideal_first/4, ideal/4]).
start() ->
order_manager([]).
order_manager(Orders) ->
% keeps all local orders in a node, i.e. the orders scheduled
% for completion locally within the node.
receive
{add, Order} ->
io:format("order_manager: adding order: ~p~n", [Order]),
worldview ! {request, wv, order_manager},
receive {response, wv, WorldView} -> ok end,
NewOrders = add_order(Orders, Order, WorldView),
fsm ! {ev_new_order},
worldview ! {orders, NewOrders},
io:format("order_manager: new orders: ~p~n", [NewOrders]),
order_manager(NewOrders);
{remove, Floor} ->
io:format("order_manager: removing order: ~p~n", [Floor]),
NewOrders = remove_order(Orders, Floor),
worldview ! {orders, NewOrders},
io:format("order_manager: new orders: ~p~n", [NewOrders]),
order_manager(NewOrders);
{clear} ->
io:format("order_manager: clearing orders ~n"),
worldview ! {orders, []},
order_manager([]);
{get_first, Pid} ->
Pid ! get_first(Orders),
order_manager(Orders);
{get_all, Pid} ->
Pid ! {orders, Orders},
order_manager(Orders);
{request_new_order} ->
case get_first(Orders) of
-1 -> fsm ! {no_orders};
_ -> fsm ! {ev_new_order}
end
end,
order_manager(Orders).
add_order([], NewOrder, _) ->
[NewOrder];
add_order(Orders, NewOrder, WorldView) ->
[First|_] = Orders,
OrderFloor = element(1, NewOrder),
OrderDir = element(2, NewOrder),
driver:set_order_button_light(driver, OrderDir, OrderFloor, on),
case lists:member(NewOrder, Orders) of
true ->
Orders;
false ->
case ideal_first(First, WorldView, OrderFloor, OrderDir) of
true ->
NewOrders = hf:list_insert(Orders, NewOrder, 1);
false ->
NewOrders = hf:list_insert(Orders, NewOrder, find_position(Orders, NewOrder, 2))
end
end.
remove_order([], _) ->
[];
remove_order(Orders, Floor) ->
[First|_] = Orders,
case (element(1, First) == Floor) of
true ->
OrderFloor = element(1, First),
OrderDir = element(2, First),
driver:set_order_button_light(driver, OrderDir, OrderFloor, off),
network:send_to_all(order_receiver, {order, remove, First}),
NewOrders = lists:keydelete(Floor, 1, Orders),
remove_order(NewOrders, Floor);
false ->
Orders
end.
find_position([_|[]], _, Position) ->
Position;
find_position([PrevOrder|NextOrders], Order, Position) ->
% returns position for Order to be inserted in current orders.
% NB! START WITH Position = 2, as ideal_first is used for the edge
% case of checking if the order can be placed at the very beginning.
% Calling it with Position = 1 would return one value too low.
OrderFloor = element(1, Order),
OrderDir = element(2, Order),
[NextOrder|_] = NextOrders,
case ideal(PrevOrder, NextOrder, OrderFloor, OrderDir) of
true -> Position;
false -> find_position(NextOrders, Order, Position + 1)
end.
ideal_first(NextOrder, WorldView, OrderFloor, OrderDir) ->
% returns true if the order can be placed at the front of list, i.e. it
% can do the order before the initial first order
Position = element(3, WorldView),
NextFloor = element(1, NextOrder),
NextDir = element(2, NextOrder),
Between = ((OrderFloor > Position) and (OrderFloor < NextFloor)) or
((OrderFloor < Position) and (OrderFloor > NextFloor)),
Cab = ((NextFloor == OrderFloor) and (OrderDir == cab)),
Down = ((NextDir == hall_down) and (OrderDir == hall_down) and (OrderFloor > NextFloor)),
Up = ((NextDir == hall_up) and (OrderDir == hall_up) and (OrderFloor < NextFloor)),
case Position < NextFloor of
true -> Dir = hall_up;
false -> Dir = hall_down
end,
(Between and ((OrderDir == Dir) or (OrderDir == cab))) or Cab or Down or Up.
ideal(PrevOrder, NextOrder, OrderFloor, hall_down) ->
% returns true if position between prevorder and nextorder is gucci
LastFloor = element(1, PrevOrder),
LastDir = element(2, PrevOrder),
NextFloor = element(1, NextOrder),
NextDir = element(2, NextOrder),
Normal = (LastDir == hall_down) and (OrderFloor >= NextFloor) and (OrderFloor =< LastFloor),
Special = (LastDir == hall_up) and (NextDir == hall_down) and (OrderFloor >= NextFloor),
Cab = (LastFloor > NextFloor) and (OrderFloor =< LastFloor) and (OrderFloor >= NextFloor),
Cab or Normal or Special;
ideal(PrevOrder, NextOrder, OrderFloor, hall_up) ->
LastFloor = element(1, PrevOrder),
LastDir = element(2, PrevOrder),
NextFloor = element(1, NextOrder),
NextDir = element(2, NextOrder),
Normal = (LastDir == hall_up) and (OrderFloor =< NextFloor) and (OrderFloor >= LastFloor),
Special = (LastDir == hall_down) and (NextDir == hall_up) and (OrderFloor =< NextFloor),
Cab = (LastFloor < NextFloor) and (OrderFloor >= LastFloor) and (OrderFloor =< NextFloor),
Cab or Normal or Special;
ideal(PrevOrder, NextOrder, OrderFloor, cab) ->
LastFloor = element(1, PrevOrder),
NextFloor = element(1, NextOrder),
Equal = (OrderFloor == NextFloor),
Up = (LastFloor < NextOrder) and (OrderFloor >= LastFloor) and (OrderFloor =< NextFloor),
Down = (LastFloor > NextOrder) and (OrderFloor =< LastFloor) and (OrderFloor >= NextFloor),
Up or Down or Equal.
get_first([]) ->
-1;
get_first([H|_]) ->
H.