برنامج تمثيلي لمصعد في ++C
برنامج تمثيلي لمصعد
ملحوظة : لا يستخدم لهذا البرنامج البرنامج EasyWin .
هل تساءلت مرة كيف يمكن للمصاعد في الأبنية الحديثة أن تعرف وجهتها ؟ كان ذلك ينفذ عن طريق عامل المصعد ولكن مباني اليوم قد زودت بإمكانيات للذكاء تغنينا عن الوسائل الأدمية .
تري ما هي عناصر نظام كهذا ؟ في مبني نمطي حديث يوجد عدة مصاعد , ومجموعة من الضواغط تشير لأعلي ولأسفل . من الممكن أن يكون لكل طابق ضاغطان فقط , فلا تعلم أي مصعد سوف يخدمك , وبداخل المصعد مجموعة من الضواغط بقدر عدد الطوابق , ويقوم المستخدمون بالضرب علي الضاغط المطلوب لهم , سوف يقوم برنامجنا التمثيلي بتشخيص كل هذه الأوضاع .
تشغيل البرنامج :
عندما يبدأ تشغيل البرنامج , تري علي الشاشة قائمة بعشرين طابقا وأربعة مصاعد في الطابق الأرضي المرقم 1 (أنظر الشكل )
شكل الشاشة الإفتتاحية لبرنامج 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 . تميز الطوابق المطلوبة بمستطيل إلي يسار المصعد . ويخزن النظام كافة الطوابق المطلوبة , ويحاول خدمتها جميعا (أنظر الشكل) .
شكل المصاعد تتحرك
تصميم النظام
المصاعد جميعها متماثلة , فمن المنطقي أن نجعل لها فئة تضم البيانات المطلوبة لأي مصعد : الوضع الحالي , الطوابق المطلوبة له , الاتجاه , وهكذا .
كما أن لدينا بيانات للمبني ككل , وكما رأينا في البرنامج 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() أن تميز بين الاستدعاءات لأعلي ولأسفل , عند اختبارها إذا ما كان هناك استدعاءات من أعلي أو من أسفل . ولكن ذلك سوف يجعل من الدالة أكثر تعقيدا عما هي عليه بالفعل .
ونترك مثل هذه التعديلات للقارئ .
تعليقات
إرسال تعليق