Rev 344 | Rev 347 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*******************************************************************************
* controller.cpp
*
* Implementation for the Controller class.
*
* Copyright 2006, Ira W. Snyder (devel@irasnyder.com)
******************************************************************************/
#include "controller.h"
Controller::Controller (int num_floors, int num_elevators) : num_floors (num_floors), num_elevators (num_elevators)
{
assert (num_floors > 2);
assert (num_elevators > 0);
// Connect to the dispatcher
dispatcher.connect (sigc::mem_fun (*this, &Controller::dispatch_handler));
// Create all of the elevators
elevator.reserve (num_elevators);
for (int i=0; i<num_elevators; i++)
{
elevator.push_back (new Elevator (num_floors));
elevator.at(i) -> set_controller (this);
elevator.at(i) -> set_dispatcher (&dispatcher);
}
// Seed the RNG
srandom (time(NULL));
}
Controller::~Controller ()
{
}
void Controller::request_elevator (int on_floor, int direction)
{
assert (on_floor < num_floors);
assert (on_floor >= 0);
assert (direction == MOVE_UP || direction == MOVE_DOWN);
float distance = INT_MAX;
int elevator_number;
// check that there is not already an elevator requested
// to this floor. If there is already one, ignore this
// request.
if (floor_already_requested (on_floor))
return;
// find elevator that is closest, AND NOT moving away
// "push" it's button
elevator_number = find_closest_elevator (on_floor, direction);
elevator.at(elevator_number) -> push_button (on_floor);
//printf ("elevator[%d] gets queued for floor: %d\n", elevator_number, on_floor);
}
/**
* Check if there is an elevator already in the queue to stop
* at the floor given as a parameter.
*/
bool Controller::floor_already_requested (int on_floor)
{
assert (on_floor >= 0);
assert (on_floor < num_floors);
int i;
for (i=0; i<num_elevators; i++)
if (elevator.at(i) -> button_is_pushed (on_floor))
return true;
return false;
}
/**
* Return the number of the closest elevator to the
* floor given as a parameter.
*
* We only want to choose elevators that are close and
* heading in the right direction, or the closest elevator
* if it is sitting idle.
*/
int Controller::find_closest_elevator (int to_floor, int in_direction)
{
assert (to_floor >= 0);
assert (to_floor < num_floors);
assert (in_direction == MOVE_UP || in_direction == MOVE_DOWN);
int i;
float distance = INT_MAX;
float temp_distance;
int answer = -1;
float cur_floor;
int cur_direction;
//printf ("finding closest elevator: to_floor=%d -- in_direction=%d\n", to_floor, in_direction);
for (i=0; i<num_elevators; i++)
{
cur_floor = elevator.at(i) -> get_current_floor ();
cur_direction = elevator.at(i) -> get_direction ();
temp_distance = fabsf (cur_floor - to_floor);
//printf ("cur_floor=%e -- direc=%d -- t_dist=%e\n", cur_floor, cur_direction, temp_distance);
// Automatically discard elevators that are moving in the wrong
// direction, but DO consider ones that are idle.
if (cur_direction == MOVE_DOWN && in_direction == MOVE_UP)
{
//printf ("type 1: skipped elevator[%d]\n", i);
continue;
}
if (cur_direction == MOVE_UP && in_direction == MOVE_DOWN)
{
//printf ("type 2: skipped elevator[%d]\n", i);
continue;
}
if (cur_floor < to_floor && cur_direction == MOVE_UP)
{
//printf ("good cantidate type 1\n");
// GOOD CANTIDATE
if (temp_distance < distance)
{
answer = i;
distance = temp_distance;
}
}
if (cur_floor > to_floor && cur_direction == MOVE_DOWN)
{
//printf ("good cantidate type 2\n");
// GOOD CANTIDATE
if (temp_distance < distance)
{
answer = i;
distance = temp_distance;
}
}
if (cur_direction == IDLE && temp_distance < distance)
{
//printf ("idle cantidate\n");
answer = i;
distance = temp_distance;
}
}
// If we failed to find an elevator, then we need to
// pick at random.
if (answer == -1)
{
// Pick a random number in the range [0,num_elevators-1]
answer = (int) (0.0 + ((num_elevators - 1.0) * (random() / (RAND_MAX + 1.0))));
printf ("picked at random: %d\n", answer);
assert (answer >= 0);
assert (answer < num_elevators);
}
return answer;
}
void Controller::start_all_elevators ()
{
int i;
for (i=0; i<num_elevators; i++)
elevator.at(i) -> thread_start ();
}
void Controller::stop_all_elevators ()
{
int i;
for (i=0; i<num_elevators; i++)
elevator.at(i) -> thread_stop ();
}
void Controller::pause_all_elevators ()
{
int i;
for (i=0; i<num_elevators; i++)
elevator.at(i) -> thread_pause ();
}
void Controller::unpause_all_elevators ()
{
int i;
for (i=0; i<num_elevators; i++)
elevator.at(i) -> thread_unpause ();
}
int Controller::which_elevator_is (Elevator *e)
{
int i;
for (i=0; i<num_elevators; i++)
if (elevator.at (i) == e)
return i;
return -1;
}
void Controller::stop_at_floor (Elevator *e, int floor, int direction)
{
int elevator_num = which_elevator_is (e);
assert (elevator_num != -1);
pause_all_elevators ();
// Open the elevator door
gui->open_elevator_at (num_floors-(floor+1), elevator_num);
// FIXME -- always unsets up button
if (floor >= 0 && floor <= 8)
gui->unset_up_button (floor);
// FIXME -- always unsets down button
if (floor >= 1 && floor <= 9)
gui->unset_down_button (floor-1);
// Get the floors from the user
gui->get_floors_from_user (elevator_num);
// Close the elevator door
gui->close_elevator_at (num_floors-(floor+1), elevator_num);
unpause_all_elevators ();
}
void Controller::set_gui (Elevator_Window *gui)
{
this->gui = gui;
}
void Controller::update_elevator_position (Elevator *e, float new_floor)
{
std::ostringstream strstrm;
int elevator_num = which_elevator_is (e);
assert (elevator_num != -1);
// Create the label
strstrm << std::setiosflags (std::ios_base::showpoint | std::ios_base::fixed)
<< std::setprecision (1) << new_floor;
gui->set_label (elevator_num, strstrm.str());
}
void Controller::push_to_gui_queue (Dispatch_Data data)
{
gui_events.push (data);
}
void Controller::dispatch_handler ()
{
assert (gui_events.empty() == false);
// Pop the first variable off of the queue
Dispatch_Data temp = gui_events.front ();
gui_events.pop ();
switch (temp.type)
{
case DISPATCH_DATA_STOP_AT_FLOOR:
stop_at_floor (temp.elev, temp.iarg, temp.direc);
break;
case DISPATCH_DATA_UPDATE_LABEL:
update_elevator_position (temp.elev, temp.farg);
break;
default:
std::cout << "Bad value in dispatch_handler()" << std::endl;
break;
}
}
void Controller::push_button_in_elevator (int elevator_num, int floor)
{
assert (elevator_num < num_elevators);
assert (elevator_num >= 0);
assert (floor < num_floors);
assert (floor >= 0);
elevator.at (elevator_num)->push_button (floor);
}