Добавил:
Upload
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:ООП / Задание 01 / Псевдографика / Псевдографика / elev
.cpp// elev.cpp
// содержит определения данных и методов класса
#include "elev.h" // включить объявление класса
///////////////////////////////////////////////////////////
// определения функций для класса building
///////////////////////////////////////////////////////////
building::building() // конструктор
{
char ustring[BUF_LENGTH]; // строка для номеров этажей
init_graphics(); // инициализация графики
clear_screen(); // очистка экрана
num_cars = 0;
for(int k = 0; k < NUM_CARS; k++) // создать лифты
{
car_list[k] = new elevator(this, num_cars);
num_cars++;
}
for(int j = 0; j < NUM_FLOORS; j++) // для каждого этажа
{
set_cursor_pos(3, NUM_FLOORS - j);// вывести номер этажа
itoa(j + 1, ustring, 10); // на экран
cout << setw(3) << ustring;
floor_request[UP][j] = false; // запросов еще не было
floor_request[DN][j] = false;
}
} // конец конструктора
//---------------------------------------------------------
building::~building() // деструктор
{
for(int k = 0; k < NUM_CARS; k++) // удалить лифты
delete car_list[k];
}
//---------------------------------------------------------
void building::master_tick() // метроном
{
int j;
show_floor_reqs(); // вывести запросы с этажей
for(j = 0; j < NUM_CARS; j++) // для каждого лифта
car_list[j]->car_tick1(); // послать временную метку 1
for(j = 0; j < NUM_CARS; j++) // для каждого лифта
car_list[j]->car_tick2(); // послать временную метку 2
} // конец master_tick()
//---------------------------------------------------------
void building::show_floor_reqs() const // вывод запросов
{
for(int j = 0; j < NUM_FLOORS; j++)
{
set_cursor_pos(SPACING, NUM_FLOORS - j);
if(floor_request[UP][j] == true)
cout << '\x1E'; // стрелка вверх
else
cout << ' ';
set_cursor_pos(SPACING + 3, NUM_FLOORS - j);
if(floor_request[DN][j] == true)
cout << '\x1F'; // стрелка вниз
else
cout << ' ';
}
} // конец show_floor_reqs()
//---------------------------------------------------------
// record_floor_reqs() - получение запросов снаружи
void building::record_floor_reqs()
{
char ch = 'x'; // рабочий символ для ввода
char ustring[BUF_LENGTH]; // рабочая строка ввода
int iFloor; // этаж, с которого был запрос
char chDirection; // 'u' или 'd' для выбора направления
set_cursor_pos(1, 22); // низ экрана
cout << "Нажмите [Enter] для вызова лифта: ";
if(!kbhit()) // ожидание нажатия (должен быть CR,
return; // возврат каретки)
cin.ignore(10, '\n');
if(ch == '\x1B') // при нажатии escape выход из программы
exit(0);
set_cursor_pos(1, 22); clear_line(); // очистить от старого текста
set_cursor_pos(1, 22); // низ экрана
cout << "На каком Вы этаже? ";
cin.get(ustring, BUF_LENGTH); // получить этаж
cin.ignore(10, '\n'); // съесть символы, включая разделитель
iFloor = atoi(ustring); // преобразовать в int
cout << "В каком направлении будете двигаться (u/d): ";
cin.get(chDirection); // (избежать повтора новых строк)
cin.ignore(10, '\n'); // съесть символы, включая разделитель
if(chDirection == 'u' || chDirection == 'U')
floor_request[UP][iFloor - 1] = true; // запрос «вверх»
if(chDirection == 'd' || chDirection == 'D')
floor_request[DN][iFloor - 1] = true; // запрос «вниз»
set_cursor_pos(1, 22); clear_line(); // стереть старый текст
set_cursor_pos(1, 23); clear_line();
set_cursor_pos(1, 24); clear_line();
} // end record_floor_reqs()
//---------------------------------------------------------
// get_floor_req() - проверка наличия запросов
bool building::get_floor_req(const int dir,
const int floor) const
{
return floor_request[dir][floor];
}
//---------------------------------------------------------
// set_floor_req() - установить запрос
void building::set_floor_req(const int dir, const int floor,
const bool updown)
{
floor_request[dir][floor] = updown;
}
//---------------------------------------------------------
// get_cars_floor() - найти кабинку
int building::get_cars_floor(const int carNo) const
{
return car_list[carNo]->get_floor();
}
//---------------------------------------------------------
// get_cars_dir() - определение направления
direction building::get_cars_dir(const int carNo) const
{
return car_list[carNo]->get_direction();
}
//---------------------------------------------------------
///////////////////////////////////////////////////////////
// определения функций класса elevator
///////////////////////////////////////////////////////////
// конструктор
elevator::elevator(building* ptrB, int nc) :
ptrBuilding(ptrB), car_number(nc)
{
current_floor = 0; // начать с 0 (для пользователя - 1)
old_floor = 0; // запомнить предыдущий этаж
current_dir = STOP; // вначале стоит на месте
for(int j = 0; j < NUM_FLOORS; j++) // пассажиры еще не
destination[j] = false; // нажимали кнопки
loading_timer = 0; // еще не началась посадка
unloading_timer = 0; // еще не началась высадка
} // конец конструктора
//---------------------------------------------------------
int elevator::get_floor() const // получение текущего этажа
{
return current_floor;
}
//---------------------------------------------------------
direction elevator::get_direction() const // получение
{ // текущего направления
return current_dir;
}
//---------------------------------------------------------
void elevator::car_tick1() // метроном-1 для каждого лифта
{
car_display(); // нарисовать кабинку
dests_display(); // нарисовать конечные этажи
if(loading_timer) // счет времени посадки
--loading_timer;
if(unloading_timer) // счет времени высадки
--unloading_timer;
decide(); // принятие решения
} // конец car_tick()
//---------------------------------------------------------
// все лифты должны знать, что делать, до начала движения
void elevator::car_tick2() // метроном-2 для каждого лифта
{
move(); // двигать лифт, если нужно
}
//---------------------------------------------------------
void elevator::car_display() // вывод образа лифта
{
set_cursor_pos(SPACING + (car_number + 1) * SPACING, NUM_FLOORS - old_floor);
cout << " "; // стереть со старой позиции
set_cursor_pos(SPACING - 1 + (car_number + 1) * SPACING,
NUM_FLOORS - current_floor);
switch(loading_timer)
{
case 3:
cout << "\x01\xDB \xDB "; // лифт с открытыми дверями
break; // слева - мордочка
case 2:
cout << " \xDB\x01\xDB "; // мордочка в дверях
get_destinations(); // получить конечный этаж
break;
case 1:
cout << " \xDB\xDB\xDB "; // нарисовать с закрытыми
break; // дверями без мордочки
case 0:
cout << " \xDB\xDB\xDB "; // двери закрыты,
break; // мордочки нет (по умолчанию)
}
set_cursor_pos(SPACING + (car_number + 1) * SPACING,
NUM_FLOORS - current_floor);
switch(unloading_timer)
{
case 3:
cout << "\xDB\x01\xDB "; // двери открыты,
break; // мордочка слева
case 2:
cout << "\xDB \xDB\x01"; // двери открыты,
break; // мордочка справа
case 1:
cout << "\xDB\xDB\xDB "; // двери закрыты
break; // мордочки нет
case 0:
cout << "\xDB\xDB\xDB "; // двери закрыты,
break; // мордочки нет (по умолчанию)
}
old_floor = current_floor; // запомнить старый этаж
} // конец car_display()
//---------------------------------------------------------
void elevator::dests_display() const // вывести конечные
{ // этажи, выбранные кнопками
for(int j = 0; j < NUM_FLOORS; j++) // внутри лифта
{
set_cursor_pos(SPACING - 2 + (car_number + 1) * SPACING, NUM_FLOORS - j);
if(destination[j] == true)
cout << '\xFE'; // маленький квадратик
else
cout << ' '; // пробел
}
} // конец dests_display()
//---------------------------------------------------------
void elevator::decide() // принятие решения
{
int j;
// флаги показывают, сверху или снизу запросы или назначения
bool destins_above, destins_below; // конечные пункты
bool requests_above, requests_below; // запросы
// ближайший запрос снизу и сверху
int nearest_higher_req = 0;
int nearest_lower_req = 0;
// флаги указывают, есть ли другие лифты, движущиеся в том
// же направлении между нами и ближайшим запросом с этажа (ЗЭ)
bool car_between_up, car_between_dn;
// флаги указывают, есть ли лифты противоположного
// направления с другой стороны от ближайшего ЗЭ
bool car_opposite_up, car_opposite_dn;
// этаж и направление другого лифта
int ofloor; // этаж
direction odir; // направление
// убедиться, что мы не слишком высоко или низко
if((current_floor == NUM_FLOORS - 1 && current_dir == UP)
|| (current_floor == 0 && current_dir == DN))
current_dir = STOP;
// если этаж назначения - текущий, начать высадку
if(destination[current_floor] == true)
{
destination[current_floor] = false;// удалить это назначение
if(!unloading_timer) // высадка
unloading_timer = LOAD_TIME;
return;
}
// если есть запрос «вверх» с этого этажа и если
// мы едем вверх или стоим, произвести посадку на борт
if((ptrBuilding->get_floor_req(UP, current_floor) &&
current_dir != DN))
{
current_dir = UP; // (если была остановка)
// удалить ЗЭ в данном направлении движения
ptrBuilding->set_floor_req(current_dir,
current_floor, false);
if(!loading_timer) // посадка
loading_timer = LOAD_TIME;
return;
}
// проверка других назначений или ЗЭ
// расстояние считать до ближайшего запроса
if((ptrBuilding->get_floor_req(DN, current_floor) &&
current_dir != UP))
{
current_dir = DN; //(в случае, если это была ОСТАНОВКА)
// удалите запрос пола на направление, мы идем
ptrBuilding->set_floor_req(current_dir,
current_floor, false);
if( !loading_timer) // загрузка пассажиров
loading_timer = LOAD_TIME;
return;
}
// проверьте, есть ли другие места назначения или запросы
// расстояние записи до самого близкого запроса
destins_above = destins_below = false;
requests_above = requests_below = false;
for(j = current_floor + 1; j < NUM_FLOORS; j++)
{ // проверять верхние этажи
if(destination[j]) // если они - назначения
destins_above = true; // установить флаг
if(ptrBuilding->get_floor_req(UP, j) ||
ptrBuilding->get_floor_req(DN, j))
{ // если ЗЭ
requests_above = true; // установить флаг
if(!nearest_higher_req) // если еще не установлен
nearest_higher_req = j; // установить ближайший ЗЭ
}
}
for(j = current_floor - 1; j >= 0; j--) // проверка нижних этажей
{
if(destination[j]) // если назначения
destins_below = true; // установить флаг
if(ptrBuilding->get_floor_req(UP, j) ||
ptrBuilding->get_floor_req(DN, j))
{ // если запросы
requests_below = true; // установить флаг
if(!nearest_lower_req) // если еще не установлен
nearest_lower_req = j; // установить ближайший ЗЭ
}
}
// если нет запросов сверху/снизу, остановиться
if(!destins_above && !requests_above &&
!destins_below && !requests_below)
{
current_dir = STOP;
return;
}
// если есть назначение, а мы стоим или движемся к нему,
// начать/продолжать движение
if(destins_above && (current_dir == STOP || current_dir == UP))
{
current_dir = UP;
return;
}
if(destins_below && (current_dir == STOP || current_dir == DN))
{
current_dir = DN;
return;
}
// проверка, есть ли другие лифты, (a) того же направления
// между нами и ближайшим ЗЭ, или
// (b) встречного направления с другой стороны ЗЭ
car_between_up = car_between_dn = false;
car_opposite_up = car_opposite_dn = false;
for(j = 0; j < NUM_CARS; j++) // проверить каждый лифт
{
if(j != car_number) // если это не наш лифт
{ // получить его этаж
ofloor = ptrBuilding->get_cars_floor(j); // и
odir = ptrBuilding->get_cars_dir(j); // направление
// если едет вверх, и ЗЭ вверху
if((odir == UP || odir == STOP) && requests_above)
// если он при этом между нами и ЗЭ
if((ofloor > current_floor
&& ofloor <= nearest_higher_req)
// или там же, но его номер ниже
|| (ofloor == current_floor && j < car_number))
car_between_up = true;
// если он едет вниз, и ЗЭ внизу
if((odir == DN || odir == STOP) && requests_below)
// если он снизу, но над ближайшим ЗЭ
if((ofloor < current_floor
&& ofloor >= nearest_lower_req)
// или на том же этаже, но с меньшим номером
|| (ofloor == current_floor && j < car_number))
car_between_dn = true;
// если идет вверх, а ЗЭ снизу
if((odir == UP || odir == STOP) && requests_below)
// и он ниже ЗЭ и ближе к нему, чем мы
if(nearest_lower_req >= ofloor
&& nearest_lower_req - ofloor
< current_floor - nearest_lower_req)
car_opposite_up = true;
// если идет вниз, а ЗЭ сверху
if((odir == DN || odir == STOP) && requests_above)
// и он над ЗЭ и ближе к нему, чем мы
if(ofloor >= nearest_higher_req
&& ofloor - nearest_higher_req
< nearest_higher_req - current_floor)
car_opposite_dn = true;
} // конец if(не для нашего лифта)
} // конец for(для каждого лифта)
// если идем вверх или остановились, а ЗЭ над нами
// и между нами и ЗЭ нет идущих вверх лифтов
// или идущих вниз над ЗЭ и ближе к нему, чем мы, тогда
// ехать вверх
if((current_dir == UP || current_dir == STOP)
&& requests_above && !car_between_up && !car_opposite_dn)
{
current_dir = UP;
return;
}
// если идем вниз или остановились, и снизу есть ЗЭ,
// и нет лифтов, идущих вниз, между нами и ЗЭ
// или под ЗЭ, идущих вверх и ближе нас к ЗЭ
if((current_dir == DN || current_dir == STOP)
&& requests_below && !car_between_dn && !car_opposite_up)
{
current_dir = DN;
return;
}
// если ничто иное случай, не остановиться
current_dir = STOP;
} // конец decide(), наконец
//--------------------------------------------------------------
void elevator::move()
{ // если посадка или высадка,
if(loading_timer || unloading_timer) // не двигаться
return;
if(current_dir == UP) // если идем вверх, идти вверх
current_floor++;
else if(current_dir == DN) // если идем вниз, идти вниз
current_floor--;
} // end move()
//---------------------------------------------------------
void elevator::get_destinations() // остановка, получение пунктов назначения
{
char ustring[BUF_LENGTH]; // входной рабочий буфер
int dest_floor; // этаж назначения
set_cursor_pos(1, 22); clear_line(); // удалить верхнюю строку
set_cursor_pos(1, 22);
cout << "Лифт " << (car_number + 1)
<< " остановился на этаже " << (current_floor + 1)
<< "\nЭтаж назначения (0 для окончания ввода)";
for(int j = 1; j < NUM_FLOORS; j++) // получить запросы этажей
{ // максимум; обычно меньше
set_cursor_pos(1, 24);
cout << "Этаж назначения " << j << ": ";
cin.get(ustring, BUF_LENGTH); // (во избежание дублирования
// пустых строк)
cin.ignore(10, '\n'); // съесть символы, включая
// ограничитель
dest_floor = atoi(ustring);
set_cursor_pos(1, 24); clear_line(); // стереть старую строку
if(dest_floor == 0) // если больше нет запросов
{ // стереть нижние три строки
set_cursor_pos(1, 22); clear_line();
set_cursor_pos(1, 23); clear_line();
set_cursor_pos(1, 24); clear_line();
return;
}
--dest_floor; // начинать с 0, а не 1
if(dest_floor == current_floor) // выбрать текущий этаж
{ --j; continue; } // забыть его
// если мы остановились, первый запрос выбирает
// направление движения
if(j == 1 && current_dir == STOP)
current_dir = (dest_floor < current_floor) ? DN : UP;
destination[dest_floor] = true;// записать выбор
dests_display(); // вывести этажи назначения
}
} // конец get_destinations()
//---------------------------------------------------------
Соседние файлы в папке Псевдографика