今天為大家帶來一個超級好玩的電梯模擬系統
·題目概要
模擬某校九層教學樓的電梯系統。該樓有一個自動電梯,能在每層停留,其中第一層是大樓的進出層,即是電梯的“本壘層”,電梯“空閑”時,將來到該層候命。
電梯一共有七個狀態,即正在開門(Opening)、已開門(Opened)、正在關門(Closing)、已關門(Closed)、等待(Waiting)、移動(Moving)、減速(Decelerate)。
乘客可隨機地進出於任何層。對每個人來說,他有一個能容忍的最長等待時間,一旦等候電梯時間過長,他將放棄。
模擬時鍾從0開始,時間單位為0.1秒。人和電梯的各種動作均要消耗一定的時間單位(簡記為t),比如:
有人進出時,電梯每隔40t測試一次,若無人進出,則關門;
關門和開門各需要20t;
每個人進出電梯均需要25t;
電梯加速需要15t;
上升時,每一層需要51t,減速需要14t;
下降時,每一層需要61t,減速需要23t;
如果電梯在某層靜止時間超過300t,則駛回1層候命。
電梯調度規則:
1)就近原則:電梯的主要調度策略是首先響應沿當前行進方向上最近端的請求直到滿足最遠端請求。若該方向上無請求時,就改變移動方向;
2)在就近原則無法滿足的情況下,首先滿足更高層的請求;
3)電梯的最大承載人數為13人,電梯人數達到13人后,在有人出電梯之前,不接受進入電梯的請求;
4)乘客上下電梯時先出后進。進電梯時乘客是按發出乘坐請求的順序依次進入,每次只能進入一人且每個人花費的時間都為25t;
5)電梯在關門期間(電梯離開之前)所在層提出請求的乘客同樣允許進入。
要求:
按時序顯示系統狀態的變化過程,即發生的全部人和電梯的動作序列。
擴展要求:
實現電梯模擬的可視化界面。用動畫顯示電梯的升降,人進出電梯。設計有下列對象:電梯、人、電梯控制板及其上各種按鈕、定時器等。
·思路
電梯運行的原則,依據單向最大請求原則。
即:在電梯類中設定兩個分別記錄上和下的最遠請求,初始值分別設為(上)0和(下)10。最大請求即為某一方向上運動的最遠樓層,例如:如果是向上,則最大請求最大為9,如 果是向下,則最大請求最遠為1
注:此記錄量不能合並為一個,即不能只記錄當前運行方向的最遠層數(最大請求)。因為會出現這種情況:當電梯正在向下,而你只記錄了當前的運動方向(下)的最大請求,如 果該值為3,當你運動到樓之后,如果沒有記錄反向(即向上)的最大請求,那么此時就要遍歷3樓以上的所有樓層的請求情況,以確定是否向上,此時就需要遍歷!!(而我們 應該盡量避免遍歷),如果那樣,可想而知,我們要遍歷多少次!
將這個大前提說明完之后,我們來規定幾個原則
1)最大請求包括外面乘客搭乘需求以及電梯里面的人的出門請求
2)先完成當前方向的運送任務再反過來完成反方向的任務
3)進門的乘客一定是他的需求方向與電梯當前運動方向一致的,最大請求層的乘客情況除外(因為走到最遠處了,無論乘客去哪里都應該接,無論其想上樓還是想下樓)
電梯能夠順利運行所依照的機制為狀態轉換。
即:電梯的運行邏輯全都在各個狀態中,通過狀態的切換而使電梯能夠正常運行。
這樣的話,就把電梯的邏輯分成幾個部分去單獨思考,出錯也很容易找到位置,並進行局部的整改。
即:每一個狀態下應該完成什么樣的操作,例如:closing狀態,依據題意,電梯正在關門的時候是可以允許有人請求進入的,所以,該狀態首先要判斷是否要有人進入,也就是是否 要重新開門。如果沒有,到適合的時間順利轉換為closed狀態,然后接下來的動作就交給closed狀態模塊進行處理了。
其次就是一個狀態轉換時間點的問題
總的思路就是記錄下一個狀態的觸發時間,從而合理地控制狀態轉換時間點
即:在進入某一個狀態的時候,通過給出的每個狀態的延續時間,計算出下一個狀態的觸發時間點(開始時間),當總的時間點打到此觸發時間點,那么就進行相應的狀態轉換。
這是一個總的思路,當然在寫的時候要根據實際情況去合理地控制觸發時間點,比如說closing狀態,當你轉換到此狀態的時候,就應該算出下一個狀態(closed)的觸發時間點(第一次進入closing的時間點+closing的延續時間長度),但是有一個問題,就是closing狀態下是可以允許乘客請求進入的,所以當這種情況發生時,目標狀態(下一個狀態)和時間點都要做改變,以保證程序邏輯的正確性。
整個程序,電梯運行過程只有當有人放棄時,才會整個數據進行遍歷,重新刷新請求,除此之外,都不會進行遍歷的操作。
·程序優化
1)存儲結構:
運用類似開散列表的結構,有時候也叫縱向鏈表。就是一個二維的存儲結構,高維是一個數組,低維是一個鏈表。
即 LinkNode* table[10];
用此結構來存儲所有的等待乘客,即 9層樓,每層樓都對應一個鏈表存儲其乘客信息。
而針對電梯里面的乘客的出門信息,則是用一個一維數組來統計。我們可以想一下,只要乘客進入電梯內,那么只有他的目標層這一個數據是有用信息,其余的所有的信息均為無用信息,所以,針對電梯內部的乘客,並不需要存儲他的完整信息,即只需要知道他去哪一層即可,反過來再想一下,電梯到達某一層,要把乘客送出去,即有幾個人就出去幾個即可。所以,我們只需要存9個數,即每個樓對應的出門人數即可。到此,針對電梯內部信息的優化,我覺得已經差不多了
盡量避免了不必要的遍歷,在時間上進行了優化,盡量減少不必要的信息存儲,在內存優化上達到了不錯的效果
2)語法:
應用了Qt有關C++11語法中的常量表達式進行優化程序,以及內聯等的一些語法技巧。
·程序代碼
關於每個文件的作用,在注釋中做了說明
objectors.h

#ifndef OBJECTORS_H #define OBJECTORS_H /************************************************************************ //! [ objectors 頭文件 ] //! [ 定義了一些 最基礎的 枚舉類型 以及 自定義類型 ] //! [ 枚舉類型包括: 電梯的狀態常量 時間控制常量 ] //! [ 最基礎的自定義類型 電梯類 乘客類 ] //! [ 基礎的類中的成員函數絕大部分為內聯函數 為了各方面的方便考慮 統一將聲明寫在類內 ] //! [ 將其實現以內聯形式寫在本文件的類外 ] ************************************************************************/ #include<QtCore/qmargins.h> //! [枚舉類型聲明] enum Ele_Statue { Waiting , Opening , Opened , Closing , Closed , Moving , Decelerate //! [減速] , Short_Wait //! [暫時停留300t] }; enum Time_List { T_v_Udece = 14 //! [上升時減速] , T_v_up = 15 , T_close_open = 20 , T_v_Ddece = 23 //! [下降時減速] , T_in_out = 25 , T_test = 40 //! [測試有無人進出的時間] , T_ele_up = 51 , T_ele_down = 61 , T_wait = 300 }; //! [ 電梯類 ] class _elevator_ { private: Ele_Statue m_statue; //! [電梯的狀態] bool m_curDire; //! [當前方向,上為真] short m_curfloor, in_number; //! [當前層,電梯內人數] Q_DECL_CONSTEXPR short m_call[2]{10, 0}; //! [下、上的最大請求] Q_DECL_CONSTEXPR short m_out[10]{0, }; //! [出門人數記錄] public: Q_DECL_CONSTEXPR explicit _elevator_(const Ele_Statue& statue = Waiting) :m_statue(statue), m_curDire(true), m_curfloor(1), in_number(0) { } Q_DECL_CONSTEXPR static constexpr short MAX_people{ 13 }, floor_num{ 9 }; Q_DECL_CONSTEXPR inline const Ele_Statue& get_statue()const; //! [獲取狀態] Q_DECL_CONSTEXPR inline short& get_call(const bool); //! [獲取最大請求] Q_DECL_CONSTEXPR inline const short get_curfloor()const; //! [獲取當前層] Q_DECL_CONSTEXPR inline const short getnum_in()const; //! [獲取人數] Q_DECL_CONSTEXPR inline short& get_out(const short); //! [設置某層出門人數] const short get_Dire(const bool = true); //! [獲取下一步的方向] void num_change(bool); //! [電梯內人數變化] void set_statue(const Ele_Statue&); //! [設定狀態] void update_call(const int); //! [更新最大請求] void set_curfloor(const short); }; //! [ 乘客類 ] class _people_ { private: int m_wait; //! [等待時間] int m_appear; //! [出現的時間點] short m_from, m_to; //! [進出樓層] public: Q_DECL_CONSTEXPR explicit _people_(const int t = 0, const int wait = 500) :m_wait(wait) ,m_appear(t) ,m_from(0) ,m_to(0) { } Q_DECL_CONSTEXPR inline const short get_wait()const; Q_DECL_CONSTEXPR inline const short get_from()const; Q_DECL_CONSTEXPR inline const short get_to()const; Q_DECL_CONSTEXPR inline const int get_appear()const; Q_DECL_CONSTEXPR inline const bool IsGiveUp(const int)const; void set_wait(const int); void set_from(const short); void set_to(const short); void set_time(const int); }; //! [ 電梯類的內聯函數實現 ] Q_DECL_CONSTEXPR inline const short _elevator_::getnum_in() const { return in_number; } Q_DECL_CONSTEXPR inline short &_elevator_::get_out(const short floor) { return m_out[floor]; } inline void _elevator_::num_change(bool add) { add ? in_number++ : in_number--; } Q_DECL_CONSTEXPR inline const Ele_Statue& _elevator_::get_statue()const { return m_statue; } Q_DECL_CONSTEXPR inline short &_elevator_::get_call(const bool dir) { return m_call[dir]; } Q_DECL_CONSTEXPR inline const short _elevator_::get_curfloor() const { return m_curfloor; } inline void _elevator_::set_statue(const Ele_Statue& s) { m_statue = s; } inline void _elevator_::update_call(const int call) { if(call > m_call[true] && call > m_curfloor)m_call[true] = call; if(call < m_call[false] && call < m_curfloor)m_call[false] = call; } inline void _elevator_::set_curfloor(const short f) { m_curfloor = f; } inline const short _elevator_::get_Dire(const bool change) { if(m_call[1] == 0 && m_call[0] == 10) //! [如果當前在一層,且沒有上請求,則返回-1] return -1; //! [如果正在上升,最大上請求不大於當前層,反向;如果正在下降,存在向上請求,反向] if(change) if(m_curDire ? m_call[1] <= m_curfloor : (m_call[1] && m_call[0] == 10)) m_curDire = !m_curDire; return m_curDire; } //! [ 乘客類的內聯函數實現 ] Q_DECL_CONSTEXPR inline const short _people_::get_wait() const { return m_wait; } Q_DECL_CONSTEXPR inline const short _people_::get_from() const { return m_from; } Q_DECL_CONSTEXPR inline const short _people_::get_to() const { return m_to; } Q_DECL_CONSTEXPR inline const int _people_::get_appear() const { return m_appear; } Q_DECL_CONSTEXPR inline const bool _people_::IsGiveUp(const int t) const { return m_appear + m_wait <= t; } inline void _people_::set_wait(const int w) { m_wait = w; } inline void _people_::set_from(const short f) { m_from = f; } inline void _people_::set_to(const short t) { m_to = t; } inline void _people_::set_time(const int t) { m_appear = t; } #endif // OBJECTORS_H
element.h

#ifndef ELEMENT_H #define ELEMENT_H /**************************************************************** //! [ element 頭文件 ] //! [ 定義圖元 電梯圖元 乘客圖元 ] //! [ 相關的坐標運算 ] ****************************************************************/ #include <QtCore/qmargins.h> enum ItemShape { NoShape, _Elevator, _People, }; class _item_ { private: //! [data_Member] Q_DECL_CONSTEXPR static constexpr short point_number{ 10 }; static const short coordList[3][point_number][2]; short coordinate[point_number][2]; ItemShape m_Shape; //! [Member-functions] inline void resetX(const short Index, const short x); inline void resetY(const short Index, const short y); public: explicit _item_(const ItemShape& shape = NoShape); inline void resetShape(const ItemShape&); Q_DECL_CONSTEXPR inline const ItemShape& get_shape()const; Q_DECL_CONSTEXPR inline const short get_x(const short Index) const; Q_DECL_CONSTEXPR inline const short get_y(const short Index) const; }; //! [inine-functions defination] inline void _item_::resetX(const short Index, const short x) { coordinate[Index][0] = x; } inline void _item_::resetY(const short Index, const short y) { coordinate[Index][1] = y; } Q_DECL_CONSTEXPR inline const ItemShape& _item_::get_shape()const { return m_Shape;} Q_DECL_CONSTEXPR inline const short _item_::get_x(const short Index) const { return coordinate[Index][0]; } Q_DECL_CONSTEXPR inline const short _item_::get_y(const short Index) const { return coordinate[Index][1]; } #endif // ELEMENT_H
element.cpp

#include <QtCore> #include "element.h" const short _item_::coordList[3][point_number][2] { { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } , { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 }, { 0, 2 }, { 2, 2 }, { 0, 3 }, { 1, 3 }, { 2, 3 } } , { { 0, 0 }, { 0, 2 }, { 1, 1 }, { 1, 2 }, { 1, 3 }, { 2, 0 }, { 2, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } }; //! [*--------------------------- _item_ 類 實現 ---------------------------*] _item_::_item_(const ItemShape &shape) { resetShape(shape); } void _item_::resetShape(const ItemShape& shape) { for(short i = 0; i < point_number; ++i) { coordinate[i][0] = coordList[shape][i][0]; coordinate[i][1] = coordList[shape][i][1]; } m_Shape = shape; }
board.h

#ifndef BOARD_H #define BOARD_H /********************************************************************* //! [ Board 類 ] //! [ 面板類 用於繪圖 控制圖像顯示 事件響應 信號-槽定義 ] *********************************************************************/ #include <QFrame> #include <QBasicTimer> #include <QPointer> #include "objectors.h" #include "element.h" QT_BEGIN_NAMESPACE class QLabel; class QFont; class QColor; class _item_; enum ItemShape; enum Ele_Statue; enum Time_List; struct LinkNode { _people_ m_data; LinkNode* link; Q_DECL_CONSTEXPR explicit LinkNode(const int t):m_data(t),link(Q_NULLPTR){} }; QT_END_NAMESPACE class _board_ : public QFrame { Q_OBJECT public slots: void SLOT_start(); void SLOT_appear(); void SLOT_paused(); void SLOT_statue(); signals: void _time_change(const int); //! [時間改變信號] void _ele_statue(); //! [電梯狀態信號] void _from_floor(const int); //! [層數信息信號] void _to_floor(const int); //! [層數信息信號] void _people_appear(const int); //! [乘客狀態信號] void _in_number(const int); //! [人數計數信號] private: //! [Data-Member] Q_DECL_CONSTEXPR static constexpr short Board_W{ 30 }, Board_H{ 36 }; static const QColor colorList[3]; bool ispaused, isstart; QBasicTimer m_timer; int timerElapsed, start_t; //! [兩個計時量:總時以及下一個動作開始的時間] int ele_X, ele_Y; _elevator_ m_ele; LinkNode* people_List[_elevator_::floor_num + 1]; _item_* next_item; ItemShape m_board[Board_W * Board_H]; //! [inline-functions] Q_DECL_CONSTEXPR inline ItemShape& Item_type(const int x, const int y); Q_DECL_CONSTEXPR inline const int grid_W()const; Q_DECL_CONSTEXPR inline const int grid_H()const; //! [Member-functions] void clearBoard(); void showPeople(const short); void draw(QPainter&,const int,const int,const ItemShape&); //! [描繪小格子] void disappear(const int floor); int Check_GiveUp(); void Move(); //! [移動多少個點] void update_call(); void go_in(); void go_out(); const bool Is_open(); protected: void paintEvent(QPaintEvent*)Q_DECL_OVERRIDE; void timerEvent(QTimerEvent*)Q_DECL_OVERRIDE; public: explicit _board_(QWidget *parent = 0); QPointer<QLabel> statue_L; ~_board_(); }; Q_DECL_CONSTEXPR inline ItemShape &_board_::Item_type(const int x, const int y) { return m_board[y * Board_W + x]; } Q_DECL_CONSTEXPR inline const int _board_::grid_W() const { return contentsRect().width() / Board_W; } Q_DECL_CONSTEXPR inline const int _board_::grid_H() const { return contentsRect().height() / Board_H; } #endif // BOARD_H
board.cpp

#include <QtWidgets> #include <QPainter> #include <QMessageBox> #include "board.h" const QColor _board_::colorList[3] = { QColor(255,255,255), QColor(255, 0 , 0 ), QColor( 0 , 0 , 0 ), }; _board_::_board_(QWidget *parent) :QFrame(parent), ele_X(0), ele_Y(0), start_t(0), timerElapsed(0), ispaused(false), isstart(false) { for(int i = 0; i < Board_H; ++i) //! [初始化面板] for(int j = 0; j < Board_W; ++j) Item_type(j, i) = NoShape; for(short i = 0; i < 10; ++i) //! [初始化表] { people_List[i] = new LinkNode(0); people_List[i]->link = Q_NULLPTR; } QFont font; font.setFamily("Microsoft YaHei"); font.setPointSize(12); font.setItalic(true); statue_L = new QLabel(this); statue_L->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); statue_L->setFont(font); next_item = new _item_(_Elevator); //! [將電梯圖元初始化在面板上] for(short i = 0; i < 10; ++i) Item_type(next_item->get_x(i), next_item->get_y(i)) = next_item->get_shape(); } _board_::~_board_() { delete next_item; //釋放開散列結構 LinkNode* t; for(short i = 0; i < 10; ++i) { t = people_List[i]; while(t->link != Q_NULLPTR) { LinkNode* r = t->link; t->link = r->link; delete r; } delete t; } } void _board_::SLOT_start() { emit _ele_statue(); if(isstart)return; m_timer.start(20,this); isstart = true; clearBoard(); } void _board_::SLOT_paused() { if(!isstart)return; ispaused = !ispaused; if(ispaused) m_timer.stop(); else m_timer.start(20,this); } void _board_::SLOT_statue() { switch(m_ele.get_statue()) { case 0: statue_L->setText("Waiting"); break; case 1: statue_L->setText("Opening"); break; case 2: statue_L->setText("Opened"); break; case 3: statue_L->setText("Closing"); break; case 4: statue_L->setText("Closed"); break; case 5: statue_L->setText("Moving"); break; case 6: statue_L->setText("Decelerate"); break; case 7: statue_L->setText("Short_Wait"); break; default: break; } } void _board_::clearBoard() { for(int i = 0; i < Board_H * Board_W; ++i) m_board[i] == _People ? m_board[i] = NoShape : 0 ; } void _board_::showPeople(const short from) { short i = 0, j = 1; next_item->resetShape(_People); while(Item_type((j++) * 3, (from - 1) * 4)); for(--j; i < 7; ++i) Item_type(j * 3 + next_item->get_x(i), (from - 1) * 4 + next_item->get_y(i)) = next_item->get_shape(); update(); } void _board_::SLOT_appear() { if(!isstart || ispaused) return; short from_floor = qrand() % 9 + 1, to_floor; while((to_floor = qrand() % 9 + 1) == from_floor); LinkNode* newNode = new LinkNode(timerElapsed); newNode->link = Q_NULLPTR; emit _people_appear(newNode->m_data.get_appear()); emit _from_floor(from_floor); emit _to_floor(to_floor); m_ele.update_call(from_floor); newNode->m_data.set_from(from_floor); newNode->m_data.set_to(to_floor); LinkNode* t = people_List[from_floor]; while(t->link != Q_NULLPTR) t = t->link; t->link = newNode; showPeople(from_floor); } void _board_::paintEvent(QPaintEvent* event) { Q_UNUSED(event); //! [ 繪制背景線條 ] QPainter _painter(this); QRect rect = contentsRect(); int LineLeftX = rect.left() + 3 * grid_W(); _painter.setPen(QPen(QColor(128, 36, 221).light())); _painter.drawLine(LineLeftX,rect.bottom(),LineLeftX, rect.top()); _painter.drawLine(rect.left(),rect.bottom(),rect.left(), rect.top()); _painter.setPen(QPen(QColor(128, 36, 221).dark())); for(int i = 0; i < _elevator_::floor_num; ++i) _painter.drawLine(LineLeftX + 2, rect.bottom() - 4 * grid_H() * i, rect.right(), rect.bottom() - 4 * grid_H() * i); //! [ 繪制圖像小格子 ] for(short i = 0; i < Board_H; ++i) for(short j = 0; j < Board_W; ++j) { const ItemShape shape = Item_type(j, i); if(shape != NoShape) draw(_painter, rect.left() + grid_W() * j, rect.bottom() - grid_H() * (i + 1), shape); } } void _board_::timerEvent(QTimerEvent* event) { if(event->timerId() == m_timer.timerId()) { timerElapsed++; emit _time_change(timerElapsed); int f = Check_GiveUp(); if(f)disappear(f); switch(m_ele.get_statue()) //! [狀態轉換] { case Waiting: //Waiting must be in one-floor if(people_List[1]->link != Q_NULLPTR) //! [如果有人想進去] { m_ele.set_statue(Opening); emit _ele_statue(); break; } if(m_ele.get_Dire() != -1) m_ele.set_statue(Moving); emit _ele_statue(); break; case Short_Wait: if(timerElapsed > start_t) start_t = timerElapsed + T_wait; if(timerElapsed == start_t || m_ele.get_Dire() != -1) m_ele.set_statue(Moving); emit _ele_statue(); break; case Closed: if(timerElapsed > start_t) { emit _ele_statue(); update_call(); if(m_ele.get_Dire() == -1) //! [什么請求都沒有] if(m_ele.get_curfloor() == 1) //! [如果在1層] m_ele.set_statue(Waiting); else m_ele.set_statue(Short_Wait); else m_ele.set_statue(Moving); } break; case Moving: if(timerElapsed > start_t) //! [說明下一個動作開始的時間沒有刷新] start_t = timerElapsed + (m_ele.get_Dire(false) ? T_ele_up - T_v_Udece : T_ele_down - T_v_Ddece); Move(); emit _ele_statue(); break; case Opening: if(timerElapsed > start_t) start_t = timerElapsed + T_close_open; if(timerElapsed == start_t && start_t) m_ele.set_statue(Opened); emit _ele_statue(); break; case Opened: if(timerElapsed > start_t) go_out(); if(timerElapsed > start_t) go_in(); if(timerElapsed > start_t) m_ele.set_statue(Closing); emit _ele_statue(); break; case Closing: //! [如果正在關的時候有人進,那么就重新開門] if(Is_open()) { m_ele.set_statue(Opening); start_t = 0; //! [把下一個動作的時間定為0,方便Opening處設定下一個動作Opened的開始時間,不然的話start_t代表的是Closed的開始時間] emit _ele_statue(); break; } if(timerElapsed > start_t) { start_t = timerElapsed + T_close_open; m_ele.set_statue(Closed); } break; case Decelerate: //! [防止正在向下減速,上方突然有請求,此時一定要堅持當前運動方向] Move(); emit _ele_statue(); break; default: break; } } else QFrame::timerEvent(event); } void _board_::draw(QPainter& painter, const int X, const int Y, const ItemShape& shape) { QColor color = colorList[shape]; painter.setPen(QColor(128, 36, 221)); painter.setBrush(color); painter.drawRect(X, Y, grid_W(), grid_H()); } void _board_::disappear(const int floor) { int index = 3, height = 4*(floor - 1); while(index+=3) if(Item_type(index, height) == NoShape)break; //采用尾部刪除,下一個位置為空,則刪除當前 for(int i = index - 3; i < index; ++i) for(int j = height; j < height + 4; ++j) Item_type(i, j) = NoShape; update(); } int _board_::Check_GiveUp() { for(int i = 1; i < 10; ++i) { LinkNode* t = people_List[i]; while(t->link != Q_NULLPTR) { if(t->link->m_data.IsGiveUp(timerElapsed)) { QMessageBox::information(this, "Notice", QString("%1 t 出現的[ %2 ]樓的一個乘客已經放棄等待\(==)/").arg(t->link->m_data.get_appear()).arg(t->link->m_data.get_from())); int r = t->link->m_data.get_from(); LinkNode* t0 = t->link; //! [刪除該節點] t->link = t0->link; delete t0; update_call(); return r; } t = t->link; } } return 0; } void _board_::update_call() { if(m_ele.get_Dire(false) == -1)return; //! [當前已無任何請求] int dir = m_ele.get_Dire(false), max_call = m_ele.get_call(dir); if(people_List[max_call]->link == Q_NULLPTR && !m_ele.get_out(max_call)) { m_ele.get_call(0) = 10, m_ele.get_call(1) = 0; for(int i = 1; i <= 9; ++i) if(people_List[i]->link != Q_NULLPTR || m_ele.get_out(i)) m_ele.update_call(i); } } void _board_::Move() { if(m_ele.get_statue() == Moving && timerElapsed == start_t && start_t) m_ele.set_statue(Decelerate); emit _ele_statue(); static int grid = 0, floor = 0; static bool key = true; grid += grid_H() * 4 / T_ele_up; //! [走過的小點數] if(grid % grid_H() == 0) //! [移動一格] { floor++; next_item->resetShape(_Elevator); if(m_ele.get_Dire(false) == 1) for(short x = ele_X, y = ++ele_Y, i = 9; i >= 0; --i) { Item_type(x + next_item->get_x(i), y + next_item->get_y(i)) = _Elevator; Item_type(x + next_item->get_x(i), y + next_item->get_y(i) - 1) = NoShape; } else for(short x = ele_X, y = --ele_Y, i = 0; i < 10; ++i) { Item_type(x + next_item->get_x(i), y + next_item->get_y(i)) = _Elevator; Item_type(x + next_item->get_x(i), y + next_item->get_y(i) + 1) = NoShape; } update(); } if(floor % 4)key = true; if(floor && floor % 4 == 0 && key) //! [防止進入某層一直循環,因為floor+1要經過很多小點的積累] { key = false; if(m_ele.get_Dire(false) == 1) //! [設定當前層] m_ele.set_curfloor(m_ele.get_curfloor() + 1); else m_ele.set_curfloor(m_ele.get_curfloor() - 1); if(Is_open()) m_ele.set_statue(Opening); //! [有人進出,開門] else if(m_ele.get_curfloor() == 1 && m_ele.get_Dire() == -1) //! [如果到1層且沒有請求,停止] m_ele.set_statue(Waiting); else m_ele.set_statue(Moving); //! [如果沒有人進出那么繼續走] emit _ele_statue(); } } const bool _board_::Is_open() { if(m_ele.getnum_in() >= _elevator_::MAX_people)return false; //! [超載] LinkNode* t = people_List[m_ele.get_curfloor()]; while(t->link != Q_NULLPTR) //! [如果到達最大請求處,無論此人去哪里,都要開門 || 反之 必須需求方向與運動方向一致] { if(m_ele.get_curfloor() == m_ele.get_call(m_ele.get_Dire(false)) || t->link->m_data.get_to()>m_ele.get_curfloor() == m_ele.get_Dire()) return true; t = t->link; } if(m_ele.get_out(m_ele.get_curfloor())) return true; return false; } void _board_::go_in() { LinkNode* t = people_List[m_ele.get_curfloor()]; if(t->link != Q_NULLPTR) { //! [如果到達最大請求處,無論此人去哪里,都要開門 || 反之 必須需求方向與運動方向一致] if(m_ele.get_curfloor() == m_ele.get_call(m_ele.get_Dire(false)) || t->link->m_data.get_to()>m_ele.get_curfloor() == m_ele.get_Dire()) { start_t = timerElapsed + T_in_out; disappear(m_ele.get_curfloor()); m_ele.update_call(t->link->m_data.get_to()); //! [刷新請求] m_ele.get_out(t->link->m_data.get_to())++; LinkNode* t0 = t->link; //! [刪除節點] t->link = t0->link; delete t0; m_ele.num_change(true); emit _in_number(m_ele.getnum_in()); } } } void _board_::go_out() { int num = m_ele.get_out(m_ele.get_curfloor()); if(num) //! [有的人都出去] { m_ele.num_change(false); m_ele.get_out(m_ele.get_curfloor())--; emit _in_number(m_ele.getnum_in()); QMessageBox::information(this, "Notice", "go out one people"); start_t = timerElapsed + T_in_out; } }
elevator.h

#ifndef ELEVATOR_H #define ELEVATOR_H /******************************************************************** //! [ ELEVATOR 類 ] //! [ 主窗口 ] //! [ 協調各個控件單元的布局 顯示 ] ********************************************************************/ #include <QWidget> #include <QPointer> #include "board.h" QT_BEGIN_NAMESPACE class QFrame; class QString; class QLCDNumber; class QLabel; class QPushButton; QT_END_NAMESPACE class ELEVATOR : public QWidget { Q_OBJECT private: const QPointer<QLabel> newLabel(const QString&); _board_* m_boardPtr; QPointer<QLabel> m_L; QPointer<QLCDNumber> time_lcd, from_lcd, to_lcd, num_lcd, apear_time_lcd; QPointer<QPushButton> appear_btn, start_btn, quit_btn, pause_btn; public: explicit ELEVATOR(QWidget *parent = Q_NULLPTR); }; #endif // ELEVATOR_H
elevator.cpp

#include <QtWidgets> #include "elevator.h" ELEVATOR::ELEVATOR(QWidget *parent) : QWidget(parent) { m_boardPtr = new _board_; time_lcd = new QLCDNumber(5); apear_time_lcd = new QLCDNumber(5); from_lcd = new QLCDNumber(1); to_lcd = new QLCDNumber(1); num_lcd = new QLCDNumber(5); time_lcd->setSegmentStyle(QLCDNumber::Filled); from_lcd->setSegmentStyle(QLCDNumber::Filled); to_lcd->setSegmentStyle(QLCDNumber::Filled); num_lcd->setSegmentStyle(QLCDNumber::Filled); apear_time_lcd->setSegmentStyle(QLCDNumber::Filled); appear_btn = new QPushButton(tr("appear")); start_btn = new QPushButton(tr("Start")); pause_btn = new QPushButton(tr("Pause")); quit_btn = new QPushButton(tr("Quit")); start_btn->setFocusPolicy(Qt::NoFocus); appear_btn->setFocusPolicy(Qt::NoFocus); pause_btn->setFocusPolicy(Qt::NoFocus); quit_btn->setFocusPolicy(Qt::NoFocus); connect(start_btn, SIGNAL(clicked()), m_boardPtr, SLOT(SLOT_start())); connect(pause_btn, SIGNAL(clicked()),m_boardPtr,SLOT(SLOT_paused())); connect(quit_btn, SIGNAL(clicked()), qApp, SLOT(quit())); connect(appear_btn, SIGNAL(clicked()), m_boardPtr, SLOT(SLOT_appear())); connect(m_boardPtr, SIGNAL(_time_change(int)), time_lcd, SLOT(display(int))); connect(m_boardPtr, SIGNAL(_from_floor(int)), from_lcd, SLOT(display(int))); connect(m_boardPtr, SIGNAL(_to_floor(int)), to_lcd, SLOT(display(int))); connect(m_boardPtr, SIGNAL(_in_number(int)), num_lcd, SLOT(display(int))); connect(m_boardPtr, SIGNAL(_ele_statue()), m_boardPtr, SLOT(SLOT_statue())); connect(m_boardPtr, SIGNAL(_people_appear(int)), apear_time_lcd, SLOT(display(int))); QGridLayout* layout = new QGridLayout; layout->addWidget(newLabel(tr("Time")),0,0,1,2); layout->addWidget(time_lcd,1,0,1,2); layout->addWidget(newLabel(tr("Ele Statue")),2,0,1,2); layout->addWidget(m_boardPtr->statue_L,3,0,1,2); layout->addWidget(newLabel(tr("number")),4,0,1,2); layout->addWidget(num_lcd,5,0,1,2); layout->addWidget(appear_btn,6,0); layout->addWidget(pause_btn,6,1); layout->addWidget(m_boardPtr,0,2,7,14); layout->addWidget(newLabel(tr("From Floor")),0,16,1,2); layout->addWidget(from_lcd,1,16,1,2); layout->addWidget(newLabel(tr("To Floor")),2,16,1,2); layout->addWidget(to_lcd,3,16,1,2); layout->addWidget(newLabel(tr("Apear Time")),4,16,1,2); layout->addWidget(apear_time_lcd,5,16,1,2); layout->addWidget(start_btn,6,16); layout->addWidget(quit_btn,6,17); setLayout(layout); setWindowTitle("windows"); resize(840,507); } const QPointer<QLabel> ELEVATOR::newLabel(const QString &label) { QPointer<QLabel> lab = new QLabel(label); lab->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); return lab; }
main.cpp

#include "elevator.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); ELEVATOR elevator; elevator.show(); return a.exec(); }
·運行效果
插入視頻的話,可能會導致網頁卡頓或打不開,所以還是給大家提供靜態圖片比較好
上面展示的測試情況不是很多,但是,自己測試的時候測了很多種情況,運行上都沒問題,可以放心。
·項目過程中遇到的bug
# 常成員函數里面好像不能使用QMessengeBox, 會出現不存在匹配的參數
# 內聯函數如果在類外.h中定義沒有關鍵字inline會出現重定義,即使有類作用域符也不好使
# 賦值號兩邊的類型不是完全等價或不能隱式轉化(特別是指針),會出現exit code with 255
那么今天的內容就介紹到這里。
感謝您的閱讀,生活愉快~