برنامج تمثيلي لمصعد في ++C

برنامج تمثيلي لمصعد

ملحوظة : لا يستخدم لهذا البرنامج البرنامج EasyWin .

هل تساءلت مرة كيف يمكن للمصاعد في الأبنية الحديثة أن تعرف وجهتها ؟ كان ذلك ينفذ عن طريق عامل المصعد ولكن مباني اليوم قد زودت بإمكانيات للذكاء تغنينا عن الوسائل الأدمية .

تري ما هي عناصر نظام كهذا ؟ في مبني نمطي حديث يوجد عدة مصاعد , ومجموعة من الضواغط تشير لأعلي ولأسفل . من الممكن أن يكون لكل طابق ضاغطان فقط , فلا تعلم أي مصعد سوف يخدمك , وبداخل المصعد مجموعة من الضواغط بقدر عدد الطوابق , ويقوم المستخدمون بالضرب علي الضاغط المطلوب لهم , سوف يقوم برنامجنا التمثيلي بتشخيص كل هذه الأوضاع .

تشغيل البرنامج :

عندما يبدأ تشغيل البرنامج , تري علي الشاشة قائمة بعشرين طابقا وأربعة مصاعد في الطابق الأرضي المرقم 1 (أنظر الشكل )

Object-Oriented Programming in C   _Page_0685_Image_0001

شكل الشاشة الإفتتاحية لبرنامج elev.cpp .

طلب طابق معين

عند ضربك علي أي مفتاح تري الرسالة التالية التي تطلب منك إدخال الطابق الذي أنت به :

Enter the floor you're on :

ثم رسالة بالإتجاه الذي تريده (صعود أم هبوط) :

Enter direction you want to go (u or d):

وعند الاستجابة لهاتين الرسالتين , تري مثلتا بجوار الطابق الذي اخترته , يشير إما لأعلي أو لأسفل . وكلما حدث طلب جديد , ظهرت مثلثات بهذه الطريقة بجوار الطوابق المطلوبة .

إذا كان هناك مصعد موجود بالفعل أمام الطابق المختار , يفتح الباب علي التو , في ذلك تري وجها سعيدا خارج المصعد , ثم يدخل من خلال الباب المفتوح . وإذا لم يكن هناك مصعد عند ذلك الطابق , تحرك إليه أحد المصاعد إما صعودا أو هبوطا .

تحديد الوجهة

بمجرد وصول المصعد للطابق المحدد , ودخول الراكب الوجه السعيد فيه , تظهر الرسائل الحوارية التي تحدد موقع توقف المصعد , وتستحث المستخدم

ان يدخل الطابق الذي يريده , مثلا :

Car 1 has stopped at floor 1

Enter destination floors (0 when finished)

Destination 1 : 13

و بإمكانك هنا أن تدخل أي عدد من الطريق , علي أساس أنه يوجد أكثر من راكب , علي ألا تريد عن 20 ) . بعد الإنتهاء , تضرب علي الرقم 0 . تميز الطوابق المطلوبة بمستطيل إلي يسار المصعد . ويخزن النظام كافة الطوابق المطلوبة , ويحاول خدمتها جميعا (أنظر الشكل) .

Object-Oriented Programming in C   _Page_0686_Image_0001

شكل المصاعد تتحرك

تصميم النظام

المصاعد جميعها متماثلة , فمن المنطقي أن نجعل لها فئة تضم البيانات المطلوبة لأي مصعد : الوضع الحالي , الطوابق المطلوبة له , الاتجاه , وهكذا .

كما أن لدينا بيانات للمبني ككل , وكما رأينا في البرنامج horse.cpp فإن هذه البيانات مشتركة لكافة الكائنات , ومن ثم يجب أن تعرف كبيانات استاتيكية . وفي مثالنا هذا لدينا ثلاثة من هذه البيانات : مصفوفة بالطوابق المطلوب من المصاعد التوقف عندها . هذه المصفوفة علي الصورة ثنائية , وتضم في بعد بيانا بوليا لحالتي الصعود والهبوط .

كما يجب أن يعرف أي مصعد بأماكن تواجد المصاعد الأخري , فلو أن مصعدا في الطابق الأول , فليس له أن يصعد لتلبيه نداء من الطابق الثالث عشر إذا كان هناك مصعد أخر في الطابق العاشر . ولتحقيق ذلك وضعت مصفوفة مؤشرات لأماكن المصاعد , يخزن فيها كل مصعد عنوانه بمجرد إنشائه .

أما البيان الاستاتيكي الثالث فهو رقم المصعد الذي ينشأ , وبهذه الطريقة يتاح لكل مصعد أن يرقم نفسه بمجرد إنشائه .

التحكم في الزمن

كما فعلنا في البرنامج horse.cpp , فإن الدالة الأصلية main() تستدعي دالة تسمي master_tick عند فترات منتظمة , تتحكم في كافة عناصر تشغيل البرنامج . تستدعي تلك الدالة دالة أخري car_tick1() تقوم بالإضافة لأشياء أخري , بإظهار المصعد علي الشاشة ثم تستدعي دالة أخري لتقرير ما يحدث بعد ذلك . والخيارات هنا هي : الصعود , الهبوط , التوقف , دخول مستخدم , خروج مستخدم .

وقبل تحريك مصعد لمكان ما يجب عليه أن يأخذ تصورا لأماكن بقية المصاعد ولتحقيق ذلك تدخل كافة المصاعد في عملية تقرير قبل أن يتحرك أي منها . نستخدم لهذا الغرض دالتين زمنيتين لكل مصعد . فبعد استدعاء car_tick1() لتقرر إلي أين يجب أن يتجه المصعد , تستدعي دالة أخري car_tick1() لتقرر إلي أن يجب أن يتجه المصعد , تستدعي دالة أخري car_tick2() تقوم بتحريك المصعد , وهي تجعل المصاعد تتحرك بواسطة تغيير المتغير current_floor .

وتتبع عملية إدخال المستخدمين تتابعا ثابتا , يكون المصعد خلاله متوقفا عند الطابق المطلوب , فيرسم البرنامج :

1- مصعدا ذا باب مغلق , دون وجه باسم .

2- مصعدا ذا باب مفتوح , ووجه باسم لليسار .

3- مصعدا ذا باب مفتوح ووجه باسم , ثم يؤخذ طلب المستخدم .

4- مصعدا ذا باب مغلق , دون وجه باسم .

ويطبق توال مشابه في حالة خروج المستخدم . هذه التتابعات تستخدم لها مؤقتا timer (متغير من نوع عدد صحيح ) يتناقص من 3 إلي 0 . و تستخدم دوارة case للتحكم في خطوات الرسم المشار إليها .

تنظيم البرنامج :

قسمنا البرنامج إلي أربعة ملفات , اثنان منهما يمكن أن يضعهما منتج هذا النوع من البرامج التطبيقية , وهما elev.h, elev.cpp . هذان البرنامجان يمكن لشركة مصاعد أن تشتريهما , لتطبيقهما علي أي مبني تتعاقد عليه (هذا البرنامج غير معتمد من هيئة المصاعد القومية , فلا تحاول أن تجربه حقيقة) . يقوم مبرمجو الشركة بكتابة ملفين أخرين : الملف elev_app.h

elev_app.h

 

elev_app.h




 




// elev_app.h




// provides constants to specify building characteristics




 




const int NUM_FLOORS = 20;   // number of floors




const int NUM_CARS = 4; // number of elevator cars




ويوجد به توصيف المبني , والمفروض أن يكون ملفا منفصلا لأن هذه المواصفات يجب أن تكون معلومة للدوال المنتمية لفئة المصعد , وأفضل طريقة لذلك هو أن يضمن هذا الملف في الملف elev.h , والملف elev_app.cpp الذي يستهل المصاعد في يستدعي دوال المصعد علي فترات محددة ليمثل مرور الوقت .



توصيف الفئة



يضم الملف elev.h توصيفا للفئة elevator , وتلعب بعض عناصرها مثل num_cars, car_numbers نفس دور المتغيرات في برنامج الأحصنة الذي قدمناه في الفصل 13 . وتفيد مصفوفة المؤشرات إلي المصاعد car_list[] في أن يوالي كل مصعد الاستعلام عن أوضاع واتجاهات المصاعد الأخري .







Elev.h


elev.h




 




// elev.h




// header file for elevators -- contains class declarations




// UCS Laboratories




 




#include "elev_app.h"                // provided by client




#include <iostream.h>




#include <iomanip.h>                 // for setw()




#include <dos.h>                     // for delay()




#include <conio.h>                   // for screen output




#include <stdlib.h>                  // for itoa()




#include <process.h>                 // for exit()




 




enum direction { UP, DN, STOP };




enum boolean { FALSE, TRUE };




const int LOAD_TIME =    3;   // loading/unloading time (ticks)




const int SPACING =      7;   // visual spacing between cars




const int BUF_LENGTH =  80;   // length of utility string buffer




 




////////////////////////////////////////////////////////////////




class elevator




   {




   private:




      // data shared by all elevator cars




      static elevator* car_list[NUM_CARS];  // ptrs to cars




      static int num_cars;           // cars created so far




                                     // array of up/down buttons




      static boolean floor_request[2][NUM_FLOORS];




      // data specific to each car




      int car_number;                // our number (0 to n-1)




      int current_floor;             // where are we? (0 to n-1)




      int old_floor;                 // where were we? (0 to n-1)




      direction current_dir;         // which way are we going?




      boolean destination[NUM_FLOORS];  // selected by occupants




      int loading_timer;             // non-zero if loading




      int unloading_timer;           // non-zero if unloading




      // functions for specific cars




      void car_tick1();              // time tick 1 for each car




      void car_tick2();              // time tick 2 for each car




      void car_display();            // display elevator




      void dests_display();          // display elevator requests




      void decide();                 // decide what to do




      void move();                   // move the car




      void get_destinations();       // get destinations




      // functions for data shared by all cars




      static void show_floor_reqs(); // show floor requests




 




   public:




      // functions for data of specific cars




      elevator();                    // constructor




      // functions for data shared by all cars




      static void init();            // initialize static data




      static void master_tick();     // send ticks to all cars




      static void get_floor_reqs();  // get floor requests




   };




elev_app.h




 




// elev_app.h




// provides constants to specify building characteristics




 




const int NUM_FLOORS = 20;   // number of floors




const int NUM_CARS = 4;      // number of elevator cars






الدوال المنتمية



يضم الملف elev.cpp الدوال المنتمية للفئة , والبيانات الاستاتيكية . وتقوم الدوال الاستاتيكية باستهلاك النظام , وتقدم التوقيت الأساسي , وتظهر طلبات الطوابق , وتتقبل طلبات الطوابق من المستخدمين . و تقوم الدوال المعتادة (غير الاستاتيكية) باستهلاك المصاعد (عن طريق البادئة) , وتقدم توقيتين لكل مصعد , وتظهره , وتظهر وجهته , وتقرر ما يحدث , وتحرك المصعد للمكان الجديد , ثم تحصل علي طلب المستخدم .



Elev.cpp




Elev.cpp




 




// elev.cpp




// contains class data and member function definitions




// UCS Laboratories




 




#include "elev.h"     // include class declarations




 




/////////////////////////////////////////////////////////////////




// static data definitions




/////////////////////////////////////////////////////////////////




elevator* elevator::car_list[NUM_CARS];  // list of ptrs to cars




int elevator::num_cars = 0;          // elevs created to date




                                     // array of up/down buttons




boolean elevator::floor_request[2][NUM_FLOORS]; // [0]=UP, [1]=DN




 




/////////////////////////////////////////////////////////////////




// static function definitions




/////////////////////////////////////////////////////////////////




 




void elevator::init()                // initialize static data




   {




   char ustring[BUF_LENGTH];         // string for floor numbers




 




//   clrscr();                         // clear screen




   for(int j=0; j<NUM_FLOORS; j++)   // for each floor




      {




//      gotoxy(3, NUM_FLOORS-j);       // put floor number




      itoa(j+1, ustring, 10);        // on screen




      cout << setw(3) << ustring;




      floor_request[UP][j] = FALSE;  // no floor requests yet




      floor_request[DN][j] = FALSE;




      }




   }




 




void elevator::master_tick(void)     // master time tick




   {




   show_floor_reqs();                // display floor requests




   for(int j=0; j<NUM_CARS; j++)     // for each elevator




      car_list[j]->car_tick1();      // send it time tick 1




   for(j=0; j<NUM_CARS; j++)         // for each elevator




      car_list[j]->car_tick2();      // send it time tick 2




   }




 




void elevator::show_floor_reqs()     // display floor requests




   {




   for(int j=0; j<NUM_FLOORS; j++)




      {




//      gotoxy(SPACING, NUM_FLOORS-j);




      if(floor_request[UP][j]==TRUE)




         cout << '\x1E';             // up arrow




      else




         cout << ' ';




     // gotoxy(SPACING+3, NUM_FLOORS-j);




      if(floor_request[DN][j]==TRUE)




         cout << '\x1F';             // down arrow




      else




         cout << ' ';




      }




   }




// get_floor_reqs() -- get floor requests from user outside car




void elevator::get_floor_reqs()




   {




   char ch;                   // utility char for input




   char ustring[BUF_LENGTH];  // utility string for input **************




   int iFloor;                // floor from which request made




   char chDirection;          // 'u' or 'd' for up or down




   




   if( !kbhit() )             // wait for keypress




      return;




   ch = getch();




   if(ch=='\x1B')             // if escape key, end program




      exit(0);




//   gotoxy(1,22);              // bottom of screen




   cout << "Enter the floor you're on: ";




   cin.get(ustring, BUF_LENGTH);  // get floor




   cin.ignore(10, '\n');      // eat chars, including newline




   iFloor = atoi(ustring);    // convert to integer




 




   cout << "Enter direction you want to go (u or d): ";




   cin.get(chDirection);      // (avoid multiple linefeeds)




   cin.ignore(10, '\n');      // eat chars, including newline




 




   if(chDirection=='u' || chDirection=='U')




      floor_request[UP][iFloor-1] = TRUE;  // up floor request




   if(chDirection=='d' || chDirection=='D')




      floor_request[DN][iFloor-1] = TRUE;  // down floor request




  // gotoxy(1,22); clreol();                 // clear old text




   //gotoxy(1,23); clreol();




   //gotoxy(1,24); clreol();




   }




 




/////////////////////////////////////////////////////////////////




// non-static function definitions




/////////////////////////////////////////////////////////////////




 




elevator::elevator()                 // constructor




   {




   car_list[num_cars] = this;        // put our address on list




   car_number = num_cars++;          // set our number




   current_floor = 0;                // start at 0 (user's 1)




   old_floor = 0;                    // remember previous floor




   current_dir = STOP;               // stationary at start




   for(int j=0; j<NUM_FLOORS; j++)   // occupants have not pushed




      destination[j] = FALSE;        //    any buttons yet




   loading_timer = 0;                // not loading yet




   unloading_timer = 0;              // not unloading yet




   }




 




void elevator::car_tick1()           // tick 1 for each car




   {




   car_display();                    // display elevator box




   dests_display();                  // display destinations




   if(loading_timer)                 // count down load time




      --loading_timer;




   if(unloading_timer)               // count down unload time




      --unloading_timer;




   decide();                         // decide what to do




   }




// all cars must decide before any of them move




void elevator::car_tick2()           // tick 2 for each car




   {




   move();                           // move car if appropriate




   }




 




void elevator::car_display()         // display elevator image




   {




//   gotoxy(SPACING+(car_number+1)*SPACING, NUM_FLOORS-old_floor);




   cout << "   ";                    // erase old position




   //gotoxy(SPACING-1+(car_number+1)*SPACING,




//                                      NUM_FLOORS-current_floor);




   switch(loading_timer)




      {




      case 3:




         cout << "\x01\xDB \xDB ";   // draw car with open door




         break;                      // happy face on left




      case 2:




         cout << " \xDB\x01\xDB ";   // happy face in open door




         get_destinations();         // get destinations




         break;




      case 1:




         cout << " \xDB\xDB\xDB ";   // draw with closed door




         break;                      // no happy face




      case 0:




         cout << " \xDB\xDB\xDB ";   // draw with closed door, no




         break;                      // happy face (default)




      }




//   gotoxy(SPACING+(car_number+1)*SPACING,




  //                                  NUM_FLOORS-current_floor);




   switch(unloading_timer)




      {




      case 3:




         cout << "\xDB\x01\xDB ";    // draw car with open door




         break;                      // happy face in car




      case 2:




         cout << "\xDB \xDB\x01";    // draw car with open door




         break;                      // happy face on right




      case 1:




         cout << "\xDB\xDB\xDB ";    // draw with closed door




         break;                      // no happy face




      case 0:




         cout << "\xDB\xDB\xDB ";    // draw with closed door, no




         break;                      // happy face (default)




      }




   old_floor = current_floor;        // remember old floor




   }




 




void elevator::dests_display()       // display destinations




   {                                 //    selected by buttons




   for(int j=0; j<NUM_FLOORS; j++)   //    inside the car




      {




//      gotoxy(SPACING-2+(car_number+1)*SPACING, NUM_FLOORS-j);




      if( destination[j] == TRUE )




         cout << '\xFE';             // small box




      else




         cout << ' ';                // blank




      }




   }




 




void elevator::decide()                // decide what to do




   {




   // flags indicate if destinations or requests above/below us




   boolean destins_above, destins_below;    // destinations




   boolean requests_above, requests_below;  // requests




   // floor number of closest request above us and below us




   int nearest_higher_req = 0;




   int nearest_lower_req = 0;




   // flags indicate if there is another car, going in the same




   // direction, between us and the nearest floor request (FR)




   boolean car_between_up, car_between_dn;




   // flags indicate if there is another car, going in the




   // opposite direction, on the opposite side of the nearest FR




   boolean car_opposite_up, car_opposite_dn;




   // floor and direction of other car (not us)




   int ofloor;                              // floor




   direction odir;                          // direction




 




   // ensure we don't go too high or too low




   if( (current_floor==NUM_FLOORS-1 && current_dir==UP)




      || (current_floor==0 && current_dir==DN) )




      current_dir = STOP;




 




   // if there's a destination on this floor, unload passengers




   if( destination[current_floor]==TRUE )




      {




      destination[current_floor] = FALSE;  // erase destination




      if( !unloading_timer)                // unload




         unloading_timer = LOAD_TIME;




      return;




      }




   // if there's an UP floor request on this floor,




   // and if we're going up or stopped, load passengers




   if( (floor_request[UP][current_floor] && current_dir != DN) )




      {




      current_dir = UP;  // (in case it was STOP)




      // remove floor request for direction we're going




      floor_request[current_dir][current_floor] = FALSE;




      if( !loading_timer)                  // load




         loading_timer = LOAD_TIME;




      return;




      }




   // if there's a down floor request on this floor,




   // and if we're going down or stopped, load passengers




   if( (floor_request[DN][current_floor] && current_dir != UP) )




      {




      current_dir = DN;  // (in case it was STOP)




      // remove floor request for direction we're going




      floor_request[current_dir][current_floor] = FALSE;




      if( !loading_timer)                  // load passengers




         loading_timer = LOAD_TIME;




      return;




      }




   // check if there are other destinations or requests




   // record distance to nearest request




   destins_above = destins_below = FALSE;




   requests_above = requests_below = FALSE;




   for(int j=current_floor+1; j<NUM_FLOORS; j++)




      {                                   // check floors above




      if( destination[j] )                // if destinations




         destins_above = TRUE;            // set flag




      if( floor_request[UP][j] || floor_request[DN][j] )




         {                                // if requests




         requests_above = TRUE;           // set flag




         if( !nearest_higher_req )        // if not set before




            nearest_higher_req = j;       //    set nearest req




         }




      }




   for(j=current_floor-1; j>=0; j--)      // check floors below




      {




      if(destination[j] )                 // if destinations




         destins_below = TRUE;            // set flag




      if( floor_request[UP][j] || floor_request[DN][j] )




         {                                // if requests




         requests_below = TRUE;           // set flag




         if( !nearest_lower_req )         // if not set before




            nearest_lower_req = j;        //    set nearest req




         }




      }




   // if no requests or destinations above or below, stop




   if( !destins_above && !requests_above &&




       !destins_below && !requests_below)




       {




       current_dir = STOP;




       return;




       }




   // if destinations and we're stopped, or already going the




   // right way, go toward destinations




   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;




      }




   // find out if there are other cars, (a) going in the same




   // direction, between us and the nearest floor request;




   // or (b) going in the opposite direction, on the other




   // side of the floor request




   car_between_up = car_between_dn = FALSE;




   car_opposite_up = car_opposite_dn = FALSE;




 




   for(j=0; j<NUM_CARS; j++)              // check each car




      {




      if(j != car_number)                 // if it's not us




         {                                // get its floor




         ofloor = car_list[j]->current_floor;   // and




         odir = car_list[j]->current_dir; // direction




 




         // if it's going up and there are requests above us




         if( (odir==UP || odir==STOP) && requests_above )




            // if it's above us and below the nearest request




            if( (ofloor > current_floor




                && ofloor <= nearest_higher_req)




            // or on same floor as us but is lower car number




              || (ofloor==current_floor && j < car_number) )




               car_between_up = TRUE;




         // if it's going down and there are requests below us




         if( (odir==DN || odir==STOP) && requests_below )




            // if it's below us and above the nearest request




            if( (ofloor < current_floor




                && ofloor >= nearest_lower_req)




               // or on same floor as us but is lower car number




               || (ofloor==current_floor && j < car_number) )




               car_between_dn = TRUE;




         // if it's going up and there are requests below us




         if( (odir==UP || odir==STOP) && requests_below )




            // it's below request and closer to it than we are




            if(nearest_lower_req >= ofloor




               && nearest_lower_req - ofloor




                  < current_floor - nearest_lower_req)




               car_opposite_up = TRUE;




         // if it's going down and there are requests above us




         if( (odir==DN || odir==STOP) && requests_above )




            // it's above request and closer to it than we are




            if(ofloor >= nearest_higher_req




               && ofloor - nearest_higher_req




                  < nearest_higher_req - current_floor)




               car_opposite_dn = TRUE;




         }  // end if(not us)




      }  // end for(each car)




 




   // if we're going up or stopped, and there is an FR above us,




   // and there are no other cars going up between us and the FR,




   // or above the FR going down and closer than we are,




   // then go up




   if( (current_dir==UP || current_dir==STOP)




       && requests_above && !car_between_up && !car_opposite_dn )




      {




      current_dir = UP;




      return;




      }




 




   // if we're going down or stopped, and there is an FR below




   // us, and there are no other cars going down between us and




   // the FR, or below the FR going up and closer than we are,




   // then go down




   if( (current_dir==DN || current_dir==STOP)




       && requests_below && !car_between_dn && !car_opposite_up )




      {




      current_dir = DN;




      return;




      }




   // if nothing else happening, stop




   current_dir = STOP;




   }




 




void elevator::move()




   {                          // if loading or unloading,




   if(loading_timer || unloading_timer)  // don't move




      return;




   if(current_dir==UP)        // if going up, go up




      current_floor++;




   else if(current_dir==DN)   // if going down, go down




      current_floor--;




   }




 




void elevator::get_destinations()     // stop, get destinations




   {




   char ch;                           // utility char for input




   char ustring[BUF_LENGTH];          // utility buffer for input  ********




   int dest_floor;                    // destination floor




 




//   gotoxy(1, 22);




   cout << "Car " << (car_number+1)




        << " has stopped at floor " << (current_floor+1)




        << "\nEnter destination floors (0 when finished)";




   for(int j=1; j<NUM_FLOORS; j++)    // get floor requests




      {                               // maximum; usually fewer




    //  gotoxy(1, 24);




      cout << "Destination " << j << ": ";




 




//   cin.unsetf(ios::skipws);   // do not skip white space




//   cin >> dest_floor;             // get floor number




// cin >> ustring;




      cin.get(ustring, BUF_LENGTH);   // (avoid multiple LFs)




   cin.ignore(10, '\n');      // eat chars, including newline




//      cin.get(ch);                    // eat the newline




      dest_floor = atoi(ustring);




//      gotoxy(1,24); clreol();         // clear old input line




      if(dest_floor==0)               // no more requests




         {




//         gotoxy(1,22); clreol();      // clear bottom three lines




  //       gotoxy(1,23); clreol();




    //     gotoxy(1,24); clreol();




         return;




         }




      --dest_floor;                   // start at 0, not 1




      if(dest_floor==current_floor)   // chose this very floor




         { --j; continue; }           //    so forget it




      // if we're stopped, first choice made sets direction




      if(j==1 && current_dir==STOP)




         current_dir = (dest_floor < current_floor) ? DN : UP;




      destination[dest_floor] = TRUE; // record selection




      dests_display();                // display destinations




      }




}





التطبيق



الملفان التاليان يضعهما شخص يستخدم النظام مطورا لمواصفاته الخاصة , ويتضمن الملف الأول عدد الطوابق وعدد المصاعد .



Elev_app.h




elev_app.h




 




// elev_app.h




// provides constants to specify building characteristics




 




const int NUM_FLOORS = 20;   // number of floors




const int NUM_CARS = 4; // number of elevator cars





ويقوم برنامج الملف الثاني باستهلاك البيانات الاستاتيكية في الفئة elevator , وينشئ عددا من كائناتها عن طريق المؤثر new , ثم يدخل في دوارة تستدعي الدالتين master_tick(), get_floor_request() . وتقوم الدالة المكتبية delay() بإبطاء التشغيل بما يوائم العين البشرية . كما تقوم الدالة sound() بإعطاء مؤثر صوتي يبين مرور الزمن . وعندما يستجيب إلي استحثاث من البرنامج , فإن زمن البرنامج (في مقابل زمن المستخدم) يتوقف , وذلك باختفاء التأثير الصوتي .



Elev_app.cpp




elev_app.cpp


 


// elev_app.cpp


// client-supplied file


 


#include "elev.h"                 // for class declarations


 


void main(void)


   {


   elevator::init();              // initialize static data


   new elevator[NUM_CARS];        // create elevators


   while(TRUE)


      {


      elevator::master_tick();    // send time tick to all cars


      sound(200); delay(30); nosound();  // beep


      delay(1000);                // pause


      elevator::get_floor_reqs(); // get floor requests from user


      }


   }




الاستراتيجية العامة



إن بناء نظام ذكي لإدارة تشغيل المصاعد ليس بالأمر السهل . وفي برنامجنا يتولي ذلك الدالة decide() التي تتضمن بعضا من القواعد مرتبة بحسب أولويتها , فإذا تصادف وجود قاعدة , طبقت , ولا ينظر لما يليها من قواعد . وإليك صورة مبسطة إلي حد ما :



1- إذا كان المصعد علي وشك الارتطام بأرضية البدروم أو بالسقف , توقف .



2- إذا كان هذا هو الطابق المقصود , أنزل المستخدمين .



3- إذا كان هناك طابق علوي مطلوب , وكانت الوجهة لأعلي , أدخل المستخدمين .



4- إذا كان هناك طابق سفلي مطلوب , وكانت الوجهة لأسفل , أدخل المستخدمين .



5- إذا لم توجد وجهة أو طلب من أعلي أو من أسفل , توقف .



6- إذا وجد طلب أعلي منا أتجه لأعلي .



7- إذا وجد طلب أسفل كمنا توجه لأسفل .



8- إذا كنا متوقفين أو متجهين لأعلي , وكان هناك طلب من أعلي , وليس هناك مصاعد متجهة بيننا وبين الطالب , أو أعلاه و متجة لأسفل , أقرب منا , أتجه لأعلي .



9- إذا كنا متوقفين أو متجهين لأسفل , وكان هناك طلب من أسفل , وليس هناك مصاعد متجهة بيننا وبين الطالب , أو أسفله ومتجهة لأعلي , أقرب منا أتجه لأعلي .



10- إذا لم توجد قواعد للتطبيق , توقف .



والقاعدتان 8,9 معقدتان بعض الشئ , تحاولان منع أكثر من مصعد أن يتجه لنفس الاستدعاء . علي أن النتيجة ليست مضمونة تماما , ففي بعض الأحايين تبطئ المصاعد في تلبية الاستدعاء خشية وجود مصاعد أخري بطريقها إليه , بينما قد تكون هذه الأخيرة ملبية لاستدعاءات أخري . ويمكن تحسين أداء البرنامج بأن يسمح للدالة decide() أن تميز بين الاستدعاءات لأعلي ولأسفل , عند اختبارها إذا ما كان هناك استدعاءات من أعلي أو من أسفل . ولكن ذلك سوف يجعل من الدالة أكثر تعقيدا عما هي عليه بالفعل .



ونترك مثل هذه التعديلات للقارئ .

التسميات: