X-Git-Url: https://irasnyder.com/gitweb/?a=blobdiff_plain;f=elevator.cpp;h=4a5eb37561ba85c667635aea5c0bd826ce012e95;hb=a897a1cb95028e3dbfa370ddafcc9a27110f96a7;hp=5543b0215dc3a9cfced8039b3b2f610495f18d38;hpb=dd9988b5db6dc820c5fcd07f88513d126e926d22;p=cs356-p1-elevator.git diff --git a/elevator.cpp b/elevator.cpp index 5543b02..4a5eb37 100644 --- a/elevator.cpp +++ b/elevator.cpp @@ -1,125 +1,489 @@ #include "elevator.hpp" -Elevator::Elevator () - : _stops() - , _pos() - , _direction(IDLE) - , _door_status(CLOSED) +Elevator::Elevator (int elevator_number) + : state_(STATE_IDLE) + , wait_(0) + , direction_(IDLE) + , position_() + , stops_() + , number_(elevator_number) { // Intentionally Left Empty } -void Elevator::stop_at (int floor, enum direction _direction) +Elevator::Elevator (int starting_floor, int elevator_number) + : state_(STATE_IDLE) + , wait_(0) + , direction_(IDLE) + , position_(starting_floor) + , stops_() + , number_(elevator_number) { - std::cout << "Adding Stop: Floor=" << floor << " Dir=" << _direction << std::endl; + // Intentionally Left Empty +} + +bool Elevator::currently_at_stop () const +{ + StopList::const_iterator it; + Stop current(position_, direction_); + + /* Calculate the number of Stops above and below our current position */ + int stops_above = 0; + int stops_below = 0; + + for (it = stops_.begin(); it != stops_.end(); it++) + { + if (current < *it) + ++stops_above; + + if (current > *it) + ++stops_below; + } + + /* Check if we are at the top. If so, only the position needs to match */ + if (direction_ == UP && stops_above == 0) + { + for (it = stops_.begin (); it != stops_.end (); it++) + if (it->getPosition() == position_) + return true; + } + + /* Check if we are at the bottom. If so, only the position needs to match */ + if (direction_ == DOWN && stops_below == 0) + { + for (it = stops_.begin (); it != stops_.end (); it++) + if (it->getPosition() == position_) + return true; + } + + /* Check if we match exactly */ + for (it = stops_.begin (); it != stops_.end (); it++) + if (*it == current) + return true; - _stops.push_back (Stop(floor, _direction)); + /* No match */ + return false; } -/* - * Will check if direction needs to be changed, then change it. - * - * Will move this Elevator one step in the correct direction. - * - * The correct direction is defined based on the current direction: - * - * IDLE: Move in the direction that has the most stops - * - Ex: if there are 10 stops above us, and two below, move DOWN - * - * UP: Move upwards - * - * DOWN: Move downwards - */ -void Elevator::move () +void Elevator::stop_at (Stop &stop) { - /* Check if we are at a stop. If we are: - * 1) Open the doors - * 2) Clear the call button - */ - if (currently_at_stop ()) + StopList::iterator it; + + /* If this is an "ALL" Stop, it supercedes all others */ + if (stop.getDirection() == ALL) { - std::cout << "At a stop, right now" << std::endl; + stops_.remove (stop); + stops_.push_back (stop); return; } - /* Check if we have any more stops to attend to. If we do not, go IDLE */ - if (_stops.size() == 0) + /* Check if this stop already exists. If so, just leave */ + for (it = stops_.begin(); it != stops_.end(); it++) + if (*it == stop) + return; + + /* The stop did not already exist, so add it */ + stops_.push_back (stop); +} + +float Elevator::distance_from (Position &pos) const +{ + if (position_ > pos) + return position_ - pos; + + return pos - position_; +} + +float Elevator::distance_from (Stop &s) const +{ + Direction d = s.getDirection(); + Position p = s.getPosition (); + + /* If direction doesn't matter, then only position does */ + if (d == ALL || direction_ == IDLE) + return distance_from (p); + + /* If we're not in the same direction, then we're "really far" away */ + if (d != direction_) + return INT_MAX; + + /* We must be in the correct direction, so pure distance is fine */ + return distance_from (p); +} + +void Elevator::transition_move_up () +{ + direction_ = UP; + position_ += ELEVATOR_STEP; + + // TODO: Call into the GUI to update the position + std::cout << "Updating the GUI with our position: " << position_ << std::endl; +} + +void Elevator::transition_move_down () +{ + direction_ = DOWN; + position_ -= ELEVATOR_STEP; + + // TODO: Call into the GUI to update the position + std::cout << "Updating the GUI with our position: " << position_ << std::endl; +} + +void Elevator::transition_move_idle () +{ + direction_ = IDLE; + // do not change position while IDLE +} + +void Elevator::transition_open_door () +{ + /* Calculate the number of Stops above and below our + * current position */ + StopList::const_iterator it; + Stop current = Stop(position_, direction_); + int stops_above = 0; + int stops_below = 0; + + for (it = stops_.begin(); it != stops_.end(); it++) + { + if (current < *it) + ++stops_above; + + if (current > *it) + ++stops_below; + } + + /* If we are going to switch direction, clear all stops here, + * regardless of direction. + * + * Otherwise, just clear this stop */ + if (direction_ == UP && stops_above == 0) + stops_.remove (Stop(position_, ALL)); + else if (direction_ == DOWN && stops_below == 0) + stops_.remove (Stop(position_, ALL)); + else + stops_.remove (Stop(position_, direction_)); + + // TODO: Call into the GUI to open the door + std::cout << "Opening Door" << std::endl; +} + +void Elevator::transition_close_door () +{ + // TODO: Call into the GUI to close the door + std::cout << "Closing Door" << std::endl; +} + +void Elevator::transition_begin_wait () +{ + wait_ = 10; +} + +void Elevator::transition_continue_wait () +{ + --wait_; +} + +#include +static void debug (const std::string& s) +{ + std::cout << s << std::endl; +} + +static std::string get_state_name (State s) +{ + std::string sname; + + switch (s) { - _direction = IDLE; - return; + case STATE_IDLE: + sname = "STATE_IDLE"; + break; + case STATE_UP: + sname = "STATE_UP"; + break; + case STATE_DOWN: + sname = "STATE_DOWN"; + break; + case STATE_WAIT: + sname = "STATE_WAIT"; + break; + case STATE_OPEN_DOOR: + sname = "STATE_OPEN_DOOR"; + break; + case STATE_CLOSE_DOOR: + sname = "STATE_CLOSE_DOOR"; + break; + default: + sname = "BAD STATE"; + break; } - /* Find the best direction to move in, and set our direction to that */ - if (_direction == IDLE) - _direction = find_best_direction (); + return sname; +} + +static std::string get_event_name (Event e) +{ + std::string ename; - /* Move */ - switch (_direction) + switch (e) { - case UP: - _pos += elevator_step; + case EVT_IDLE: + ename = "EVT_IDLE"; + break; + case EVT_UP: + ename = "EVT_UP"; + break; + case EVT_DOWN: + ename = "EVT_DOWN"; + break; + case EVT_WAIT: + ename = "EVT_WAIT"; break; - case DOWN: - _pos -= elevator_step; + case EVT_OPEN_DOOR: + ename = "EVT_OPEN_DOOR"; + break; + case EVT_CLOSE_DOOR: + ename = "EVT_CLOSE_DOOR"; break; default: - throw bad_direction (); + ename = "BAD EVENT"; break; } - std::cout << "at position: " << _pos << std::endl; + return ename; } -enum direction Elevator::find_best_direction () +static void bad_transition (State s, Event e) { - /* Make sure that the current direction is IDLE */ - if (_direction != IDLE) - throw bad_direction(); + std::cout << "Bad State Transition: " << get_state_name (s) + << " -> " << get_event_name (e) << std::endl; +} - std::vector::const_iterator it; - int above, below; +Event Elevator::find_next_event () const +{ + /* Calculate the number of Stops above and below our + * current position */ + StopList::const_iterator it; + Stop current = Stop(position_, direction_); + int stops_above = 0; + int stops_below = 0; - /* Find out how many are above and below our current position */ - for (above=0, below=0, it = _stops.begin(); it != _stops.end(); it++) + for (it = stops_.begin(); it != stops_.end(); it++) { - if (_pos < (*it)) - above++; + if (current < *it) + ++stops_above; - if (_pos > (*it)) - below++; + if (current > *it) + ++stops_below; } - /* If we have nothing, then stay IDLE */ - if (above == 0 && below == 0) - return IDLE; + /* Now figure out which state transition to make */ + switch (state_) + { + case STATE_IDLE: - /* If they are the same, always go up first. - * - * This comes from the design meeting on 2007-10-03 */ - if (above == below) - return UP; + if (currently_at_stop ()) + return EVT_OPEN_DOOR; + + if (stops_above > 0) + return EVT_UP; + + if (stops_below > 0) + return EVT_DOWN; + + return EVT_IDLE; + + break; + case STATE_UP: + + if (currently_at_stop ()) + return EVT_OPEN_DOOR; + + return EVT_UP; + + break; + case STATE_DOWN: + + if (currently_at_stop ()) + return EVT_OPEN_DOOR; + + return EVT_DOWN; + + break; + case STATE_WAIT: + + if (wait_ > 0) + return EVT_WAIT; + + return EVT_CLOSE_DOOR; + + break; + case STATE_OPEN_DOOR: + + return EVT_WAIT; + + break; + case STATE_CLOSE_DOOR: + + if (currently_at_stop ()) + return EVT_OPEN_DOOR; + + if (direction_ == UP && stops_above > 0) + return EVT_UP; + + if (direction_ == DOWN && stops_below > 0) + return EVT_DOWN; + + /* We need to switch directions */ + if (direction_ == UP && stops_above == 0 && stops_below > 0) + return EVT_DOWN; + + if (direction_ == DOWN && stops_below == 0 && stops_above > 0) + return EVT_UP; - /* Otherwise, go in the direction that has the most stops */ - return above > below ? UP : DOWN; + return EVT_IDLE; + + break; + default: + std::cout << "find_next_event(): Bad State" << std::endl; + break; + } } -bool Elevator::currently_at_stop () +void Elevator::move () { - std::vector::iterator it; - Stop current (_pos, _direction); + /* Generate Events */ + Event e = find_next_event (); + + std::cout << "State Transition: " << get_state_name (state_) << " with " + << get_event_name (e) << std::endl; - for (it = _stops.begin (); it != _stops.end (); it++) + switch (state_) { - std::cout << "cas(): current=" << current << " it=" << *it << std::endl; - if (*it == current) - return true; - } + case STATE_IDLE: + switch (e) + { + case EVT_UP: + state_ = STATE_UP; + transition_move_up (); + break; + case EVT_DOWN: + state_ = STATE_DOWN; + transition_move_down (); + break; + case EVT_IDLE: + state_ = STATE_IDLE; + transition_move_idle (); + break; + case EVT_OPEN_DOOR: + state_ = STATE_OPEN_DOOR; + transition_open_door (); + break; + default: + bad_transition (state_, e); + break; + } // end switch (e) + break; - return false; -} + case STATE_UP: + switch (e) + { + case EVT_UP: + state_ = STATE_UP; + transition_move_up (); + break; + case EVT_OPEN_DOOR: + state_ = STATE_OPEN_DOOR; + transition_open_door (); + break; + default: + bad_transition (state_, e); + break; + } // end switch (e) + break; + case STATE_DOWN: + switch (e) + { + case EVT_DOWN: + state_ = STATE_DOWN; + transition_move_down (); + break; + case EVT_OPEN_DOOR: + state_ = STATE_OPEN_DOOR; + transition_open_door (); + break; + default: + bad_transition (state_, e); + break; + } // end switch (e) + break; + case STATE_WAIT: + switch (e) + { + case EVT_WAIT: + state_ = STATE_WAIT; + transition_continue_wait (); + break; + case EVT_CLOSE_DOOR: + state_ = STATE_CLOSE_DOOR; + transition_close_door (); + break; + default: + bad_transition (state_, e); + break; + } // end switch (e) + break; + case STATE_OPEN_DOOR: + switch (e) + { + case EVT_WAIT: + state_ = STATE_WAIT; + transition_begin_wait (); + break; + default: + bad_transition (state_, e); + break; + } // end switch (e) + break; + case STATE_CLOSE_DOOR: + switch (e) + { + case EVT_OPEN_DOOR: + state_ = STATE_OPEN_DOOR; + transition_open_door (); + break; + case EVT_UP: + state_ = STATE_UP; + transition_move_up (); + break; + case EVT_DOWN: + state_ = STATE_DOWN; + transition_move_down (); + break; + case EVT_IDLE: + state_ = STATE_IDLE; + transition_move_idle (); + break; + default: + bad_transition (state_, e); + break; + } // end switch (e) + break; + + default: + std::cout << "Bad State: " << get_state_name (state_) << std::endl; + break; + } +} + +bool Elevator::is_idle () const +{ + return direction_ == IDLE; +} /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */