Subversion Repositories programming

Rev

Rev 346 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
338 ira 1
/*******************************************************************************
2
 * controller.cpp
3
 *
4
 * Implementation for the Controller class.
5
 *
6
 * Copyright 2006, Ira W. Snyder (devel@irasnyder.com)
7
 ******************************************************************************/
321 ira 8
 
9
#include "controller.h"
10
 
11
Controller::Controller (int num_floors, int num_elevators) : num_floors (num_floors), num_elevators (num_elevators)
12
{
347 ira 13
    assert (num_floors >= 2);
321 ira 14
    assert (num_elevators > 0);
15
 
344 ira 16
    // Connect to the dispatcher
17
    dispatcher.connect (sigc::mem_fun (*this, &Controller::dispatch_handler));
18
 
19
    // Create all of the elevators
334 ira 20
    elevator.reserve (num_elevators);
331 ira 21
 
22
    for (int i=0; i<num_elevators; i++)
332 ira 23
    {
334 ira 24
        elevator.push_back (new Elevator (num_floors));
25
        elevator.at(i) -> set_controller (this);
344 ira 26
        elevator.at(i) -> set_dispatcher (&dispatcher);
332 ira 27
    }
335 ira 28
 
29
    // Seed the RNG
30
    srandom (time(NULL));
321 ira 31
}
32
 
33
Controller::~Controller ()
34
{
35
}
36
 
329 ira 37
void Controller::request_elevator (int on_floor, int direction)
321 ira 38
{
334 ira 39
    assert (on_floor < num_floors);
40
    assert (on_floor >= 0);
331 ira 41
    assert (direction == MOVE_UP || direction == MOVE_DOWN);
328 ira 42
 
43
    float distance = INT_MAX;
44
    int elevator_number;
45
 
46
    // check that there is not already an elevator requested
47
    // to this floor. If there is already one, ignore this
48
    // request.
49
    if (floor_already_requested (on_floor))
50
        return;
51
 
52
    // find elevator that is closest, AND NOT moving away
53
    // "push" it's button
332 ira 54
    elevator_number = find_closest_elevator (on_floor, direction);
334 ira 55
    elevator.at(elevator_number) -> push_button (on_floor);
332 ira 56
 
339 ira 57
    //printf ("elevator[%d] gets queued for floor: %d\n", elevator_number, on_floor);
321 ira 58
}
59
 
328 ira 60
/**
61
 * Check if there is an elevator already in the queue to stop
62
 * at the floor given as a parameter.
63
 */
64
bool Controller::floor_already_requested (int on_floor)
65
{
336 ira 66
    assert (on_floor >= 0);
67
    assert (on_floor < num_floors);
68
 
328 ira 69
    int i;
70
 
71
    for (i=0; i<num_elevators; i++)
334 ira 72
        if (elevator.at(i) -> button_is_pushed (on_floor))
328 ira 73
            return true;
74
 
75
    return false;
76
}
77
 
78
/**
79
 * Return the number of the closest elevator to the
80
 * floor given as a parameter.
81
 *
82
 * We only want to choose elevators that are close and
83
 * heading in the right direction, or the closest elevator
84
 * if it is sitting idle.
85
 */
332 ira 86
int Controller::find_closest_elevator (int to_floor, int in_direction)
328 ira 87
{
336 ira 88
    assert (to_floor >= 0);
89
    assert (to_floor < num_floors);
90
    assert (in_direction == MOVE_UP || in_direction == MOVE_DOWN);
91
 
328 ira 92
    int i;
93
    float distance = INT_MAX;
94
    float temp_distance;
335 ira 95
    int answer = -1;
328 ira 96
 
97
    float cur_floor;
335 ira 98
    int   cur_direction;
328 ira 99
 
339 ira 100
    //printf ("finding closest elevator: to_floor=%d -- in_direction=%d\n", to_floor, in_direction);
335 ira 101
 
328 ira 102
    for (i=0; i<num_elevators; i++)
103
    {
334 ira 104
        cur_floor = elevator.at(i) -> get_current_floor ();
335 ira 105
        cur_direction = elevator.at(i) -> get_direction ();
328 ira 106
        temp_distance = fabsf (cur_floor - to_floor);
107
 
339 ira 108
        //printf ("cur_floor=%e -- direc=%d -- t_dist=%e\n", cur_floor, cur_direction, temp_distance);
334 ira 109
 
332 ira 110
        // Automatically discard elevators that are moving in the wrong
111
        // direction, but DO consider ones that are idle.
335 ira 112
        if (cur_direction == MOVE_DOWN && in_direction == MOVE_UP)
113
        {
339 ira 114
            //printf ("type 1: skipped elevator[%d]\n", i);
332 ira 115
            continue;
335 ira 116
        }
332 ira 117
 
335 ira 118
        if (cur_direction == MOVE_UP && in_direction == MOVE_DOWN)
119
        {
339 ira 120
            //printf ("type 2: skipped elevator[%d]\n", i);
334 ira 121
            continue;
335 ira 122
        }
334 ira 123
 
335 ira 124
        if (cur_floor < to_floor && cur_direction == MOVE_UP)
328 ira 125
        {
339 ira 126
            //printf ("good cantidate type 1\n");
335 ira 127
            // GOOD CANTIDATE
128
            if (temp_distance < distance)
328 ira 129
            {
130
                answer = i;
131
                distance = temp_distance;
132
            }
335 ira 133
        }
134
 
135
        if (cur_floor > to_floor && cur_direction == MOVE_DOWN)
136
        {
339 ira 137
            //printf ("good cantidate type 2\n");
335 ira 138
            // GOOD CANTIDATE
139
            if (temp_distance < distance)
328 ira 140
            {
141
                answer = i;
142
                distance = temp_distance;
143
            }
144
        }
335 ira 145
 
146
        if (cur_direction == IDLE && temp_distance < distance)
147
        {
339 ira 148
            //printf ("idle cantidate\n");
335 ira 149
            answer = i;
150
            distance = temp_distance;
151
        }
328 ira 152
    }
153
 
335 ira 154
    // If we failed to find an elevator, then we need to
155
    // pick at random.
156
    if (answer == -1)
157
    {
158
        // Pick a random number in the range [0,num_elevators-1]
159
        answer = (int) (0.0 + ((num_elevators - 1.0) * (random() / (RAND_MAX + 1.0))));
160
 
161
        printf ("picked at random: %d\n", answer);
162
 
163
        assert (answer >= 0);
164
        assert (answer < num_elevators);
165
    }
166
 
328 ira 167
    return answer;
168
}
169
 
331 ira 170
void Controller::start_all_elevators ()
171
{
172
    int i;
173
 
174
    for (i=0; i<num_elevators; i++)
334 ira 175
        elevator.at(i) -> thread_start ();
331 ira 176
}
177
 
178
void Controller::stop_all_elevators ()
179
{
180
    int i;
181
 
182
    for (i=0; i<num_elevators; i++)
334 ira 183
        elevator.at(i) -> thread_stop ();
331 ira 184
}
185
 
186
void Controller::pause_all_elevators ()
187
{
188
    int i;
189
 
190
    for (i=0; i<num_elevators; i++)
334 ira 191
        elevator.at(i) -> thread_pause ();
331 ira 192
}
193
 
194
void Controller::unpause_all_elevators ()
195
{
196
    int i;
197
 
198
    for (i=0; i<num_elevators; i++)
334 ira 199
        elevator.at(i) -> thread_unpause ();
331 ira 200
}
201
 
340 ira 202
int Controller::which_elevator_is (Elevator *e)
203
{
204
    int i;
334 ira 205
 
340 ira 206
    for (i=0; i<num_elevators; i++)
207
        if (elevator.at (i) == e)
208
            return i;
209
 
210
    return -1;
211
}
212
 
346 ira 213
void Controller::stop_at_floor (Elevator *e, int floor, int direction)
340 ira 214
{
215
    int elevator_num = which_elevator_is (e);
216
 
217
    assert (elevator_num != -1);
218
 
219
    pause_all_elevators ();
220
 
221
    // Open the elevator door
222
    gui->open_elevator_at (num_floors-(floor+1), elevator_num);
223
 
346 ira 224
    // FIXME -- always unsets up button
340 ira 225
    if (floor >= 0 && floor <= 8)
226
        gui->unset_up_button (floor);
227
 
346 ira 228
    // FIXME -- always unsets down button
340 ira 229
    if (floor >= 1 && floor <= 9)
230
        gui->unset_down_button (floor-1);
231
 
232
    // Get the floors from the user
233
    gui->get_floors_from_user (elevator_num);
234
 
344 ira 235
    // Close the elevator door
340 ira 236
    gui->close_elevator_at (num_floors-(floor+1), elevator_num);
237
 
238
    unpause_all_elevators ();
239
}
240
 
241
void Controller::set_gui (Elevator_Window *gui)
242
{
243
    this->gui = gui;
244
}
245
 
344 ira 246
void Controller::update_elevator_position (Elevator *e, float new_floor)
340 ira 247
{
248
    std::ostringstream strstrm;
249
    int elevator_num = which_elevator_is (e);
250
 
251
    assert (elevator_num != -1);
252
 
344 ira 253
    // Create the label
254
    strstrm << std::setiosflags (std::ios_base::showpoint | std::ios_base::fixed)
255
            << std::setprecision (1) << new_floor;
340 ira 256
 
257
    gui->set_label (elevator_num, strstrm.str());
258
}
259
 
344 ira 260
void Controller::push_to_gui_queue (Dispatch_Data data)
261
{
262
    gui_events.push (data);
263
}
264
 
265
void Controller::dispatch_handler ()
266
{
267
    assert (gui_events.empty() == false);
268
 
269
    // Pop the first variable off of the queue
270
    Dispatch_Data temp = gui_events.front ();
271
    gui_events.pop ();
272
 
273
    switch (temp.type)
274
    {
275
        case DISPATCH_DATA_STOP_AT_FLOOR:
346 ira 276
            stop_at_floor (temp.elev, temp.iarg, temp.direc);
344 ira 277
            break;
278
 
279
        case DISPATCH_DATA_UPDATE_LABEL:
280
            update_elevator_position (temp.elev, temp.farg);
281
            break;
282
 
283
        default:
284
            std::cout << "Bad value in dispatch_handler()" << std::endl;
285
            break;
286
    }
287
}
288
 
289
void Controller::push_button_in_elevator (int elevator_num, int floor)
290
{
291
    assert (elevator_num < num_elevators);
292
    assert (elevator_num >= 0);
293
 
294
    assert (floor < num_floors);
295
    assert (floor >= 0);
296
 
297
    elevator.at (elevator_num)->push_button (floor);
298
}
299