الخميس، 23 يونيو 2011

الكرات المتحركة - مثال بكلمات

نريد أن نبدأ بتحريك كرة واحدة، ثم بعد ذلك نتصرف في باقي الكرات.
إجراء حرك.الكرة ( طيف ، س ، ص ، السرعة ) :
-- سوف نكتب كود هنا
نهاية
(اعتبر الإجراء مثل void function).
هذا الإجراء يأخذ اربع عوامل:
  • طيف هو الطيف الذي يعبر عن رسمة الكرة؛ الطيف شكل متحرك يرسم على الشاشة (sprite) وسنعرف الآن كيف نتعامل معه
  • س، ص هو المكان الذي نريد أن يبدأ فيه رسم الكرة
  • السرعة هو مصفوفة (array) من عنصرين يعبر عن متجه vector فيه سرعة الكرة في الاتجاهين السيني والصادي
نبدأ في تفاصيل الإجراء:
إجراء حرك.الكرة ( طيف ، س ، ص ، السرعة ) :
    كرر :
        ارسم.طيف طيف في ( س ، ص )
        س = س + السرعة [ 1 ]
        ص = ص + السرعة [ 2 ]
        انتظر(15)
    تابع
نهاية
الأمر هنا بسيط: الأمر ارسم.طيف/في يأخذ طيفاً ويرسمة في نقطة محددة هي هنا نقطة البداية، ثم نغير هذه النقطة كل مرة حسب متجه السرعة، بأن نضيف السرعة في الاتجاه السيني إلى س ونفس الشيء في ص. لاحظ أن المصفوفات في كلمات تبدأ من الواحد.

نكرر هذه العملية باستمرار مع انتظار بسيط - 15 ميلليثانية - بين رسمة والأخرى

المشكلة هنا هي أن الكرة ستخرج من الشاشة بعد قليل وتختفي، نحن نريدها أن "تصطدم" بالشاشة ومن ثم تغير اتجاهها. خطتنا بسيطة:
  • إذا اصطدمت الكرة بقمة الشاشة أو قاعها، نقلب إشارة السرعة في الاتجاه الصادي فنحيلها من موجبة لسالبة أو بالعكس، وبذلك تنزل الكرة مثلاً إن كانت تصعد.
  • إذا اصطدمت بيمين الشاشة أو يسارها نغير إشارة المكون السيني للسرعة
  • في الحالتين إن كانت الكرة تكاد أن تُرسم خارج الشاشة نعيد مكانها لحافة الشاشة
كيف ينعكس ذلك على الكود؟ تعال نرى مثلاً ماذا يحدث لو تجاوزت الكرة الحافة اليمنى للشاشة.
إذا س < 0 :
    س = 0
    السرعة [ 1 ] = - السرعة [ 1 ]
تم
الحافة اليمنى هي النقطة س=صفر، فأن كانت س أقل من الصفر فمعنى هذا أن الكرة توشك أن تخرج، فنعيدها مرة أخرى إلى الحافة ونعكس إشارة المكون الأول للسرعة. لاحظ أن نظام الإحداثيات يساير الكتابة العربية (س تزداد من اليمين لليسار).

ماذا يحدث لو تجاوزت الكرة يسار الشاشة؟ هذا:
إذا س + عرض.الطيف ( طيف ) > 799 :
    س = 799 - عرض.الطيف ( طيف )
    السرعة [ 1 ] = - السرعة [ 1 ]
تم
شاشة الرسم في كلمات عرضها 800 نقطة وارتفاعها 600، لذلك النقطة في أقصى اليسار هي النقطة 799 لأن العد يبدأ من الصفر.

إذا تجاوزت حافة الكرة اليسرى (المحددة بقيمة س + عرض الكرة) هذا الحد نعيد الحافة اليسرى للنقطة الأخيرة. لاحظ أن التخصيص
س = 799 - عرض.الطيف ( طيف )
معناه اجعل س + عرض الطيف = 799، أي اجعل الحافة اليسرى بهذه القيمة.
سنفعل نفس الشيء مع قيم ص ليكون الإجراء الكامل كالآتي:
إجراء حرك.الكرة ( طيف ، س ، ص ، السرعة ) :
    كرر :
        ارسم.طيف طيف في ( س ، ص )
        س = س + السرعة [ 1 ]
        ص = ص + السرعة [ 2 ]
        إذا س < 0 :
            س = 0
            السرعة [ 1 ] = - السرعة [ 1 ]
        وإلا إذا س + عرض.الطيف ( طيف ) > 799 :
        س = 799 - عرض.الطيف ( طيف )
            السرعة [ 1 ] = - السرعة [ 1 ]
        تم
        إذا ص < 0 :
            ص = 0
            السرعة [ 2 ] = - السرعة [ 2 ]
        وإلا إذا ص + ارتفاع.الطيف ( طيف ) > 599 :
            ص = 599 - ارتفاع.الطيف ( طيف )
            السرعة [ 2 ] = - السرعة [ 2 ]
        تم
        انتظر ( 15 )
    تابع
نهاية
عظيم!! لقد أنهينا الإجراء. لم يتبق سوى استدعاؤه:
ط = حمل.طيف ( "ball1.bmp" )
س = عشوائي ( 800 )
ص = عشوائي ( 600 )
السرعة.س = عشوائي ( 20 ) + 1
السرعة.ص = عشوائي ( 20 ) + 1
السرعة = [ السرعة.س ، السرعة.ص ]
حرك.الكرة ( ط ، س ، ص ، السرعة )
هنا قمنا باستخدام الدالة الجاهزة حمل.طيف لنقوم بتحميل صورة للكرة وتكوين طيف منها، ثم ولدنا بعض القيمة العشوائية لمكان الكرة وسرعتها وقمنا بتمريرهم إلى الإجراء. لاحظ كيف يمكن عمل مصفوفة من عنصرين بالتعبير [ أ، ب] كما فعلنا للمتغير السرعة

يمكننا الآن أن ننفذ البرنامج:
للأسف لقطة الشاشة لا تبين روعة الكرة وهي تجري..كان ينبغي أن أضع فيديو لهذا المثال على اليوتيوب :]

الآن نريد أن نجعل البرنامج يتحرك فيه كرات كثيرة...هذا في الواقع أسهل مما نتخيل بسبب إمكانات البرمجة المتوازية في لغة كلمات. الأمر شغل يأخذ الصيغة التالية:
شغل <استدعاء إجراء>
ومعناه "استدع هذا الإجراء بحيث يعمل على التوازي مع باقي البرنامج وأي إجراءات أخرى". كل ما علينا الآن هو تشغيل عدة نسخ من الإجراء على التوازي ليكون لدينا كرات كثيرة!

(ملاحظة: تنفيذ الإجراءات في الواقع لن يكون متوازياً، بل ستقوم الآلة الافتراضية virtual machine الخاصة بكلمات بالانتقال بسرعة بين إجراء والآخر ليبدو الأمر كأنه على التوازي. في المستقبل ننوي تغيير الآلة الافتراضية لتحقيق توازٍ حقيقي).

سيبدو تنفيذ الإجراء الآن كالآتي، لنحرك عشر كرات عشوائياً:
لكل أ من 1 إلى 10 :
    ط = حمل.طيف ( "ball1.bmp" )
    س = عشوائي ( 800 )
    ص = عشوائي ( 600 )
    السرعة.س = عشوائي ( 20 ) + 1
    السرعة.ص = عشوائي ( 20 ) + 1
    السرعة = [ السرعة.س ، السرعة.ص ]
    شغل حرك.الكرة ( ط ، س ، ص ، السرعة ) 
تابع

جميل، لكن الكرات كلها من نفس اللون، نريد أن يكون الأمر متنوعاً قليلاً..نرى الآن البرنامج في صورته النهائية:
ملفات.الأطياف=["ball4.bmp"،"ball3.bmp"،"ball2.bmp"،"ball1.bmp"]

لكل أ من 1 إلى 10 :
    ط = حمل.طيف ( ملفات.الأطياف [ عشوائي ( 4 ) + 1 ] )
    س = عشوائي ( 800 )
    ص = عشوائي ( 600 )
    السرعة.س = عشوائي ( 20 ) + 1
    السرعة.ص = عشوائي ( 20 ) + 1
    السرعة = [ السرعة.س ، السرعة.ص ]
    شغل حرك.الكرة ( ط ، س ، ص ، السرعة )
تابع

إجراء حرك.الكرة ( طيف ، س ، ص ، السرعة ) :
    كرر :
    ارسم.طيف طيف في ( س ، ص )
        س = س + السرعة [ 1 ]
        ص = ص + السرعة [ 2 ]
        إذا س < 0 :
            س = 0
            السرعة [ 1 ] = - السرعة [ 1 ]
        وإلا إذا س + عرض.الطيف ( طيف ) > 799 :
        س = 799 - عرض.الطيف ( طيف )
            السرعة [ 1 ] = - السرعة [ 1 ]
        تم
        إذا ص < 0 :
            ص = 0
            السرعة [ 2 ] = - السرعة [ 2 ]
        وإلا إذا ص + ارتفاع.الطيف ( طيف ) > 599 :
            ص = 599 - ارتفاع.الطيف ( طيف )
            السرعة [ 2 ] = - السرعة [ 2 ]
        تم
        انتظر ( 15 )
    تابع
نهاية
لتحميل المثال كاملاً:
اضغط هذا الرابط

لتحميل لغة كلمات:
http://code.google.com/p/kalimat/downloads
أو من الموقع الرسمي http://www.kalimat-lang.com

الجمعة، 17 يونيو 2011

آلة حاسبة بلغة كلمات


لا تحتاج خبرة سابقة بالبرمجة بلغة كلمات لتتابع هذا المثال (لكن تحتاج لأن تعرف البرمجة بشكل عام). إذا أردت أن تجربه عملياً فيمكنك تحميل أحدث نسخة من اللغة من http://code.google.com/p/kalimat/downloads


هام: هذا المثال يحتاج نسخة يونيو 2011 أو أحدث ليعمل. لو كنت قد حملت نسخة قديمة من كلمات فستحتاج أن تحمل نسخة جديدة.

الآن هيا نبدأ!

رسم الأزرار على الشاشة
زر1 = زر جديد
زر1 : حدد.المكان ( 10 ، 10 )
زر1 : حدد.الحجم ( 30 ، 30 )
زر1 : حدد.النص ( "1" )
ن = النافذة.الحالية ( )
ن : اضف ( زر1 )

ستؤدي الكود السابقة لعرض زر على الشاشة. لاحظ ان علامة النقطتين ' : ' معناها method call، مثل علامة النقطة في لغات البرمجة المعروفة. الأمر جديد هنا هو نفسه operator new في اللغات الأخرى.

نحن سنرسم أزراراً كثيرة في البرنامج، لذلك هيا نكتب دالة (function) توفر علينا عناء الكتابة المتكررة:
دالة صنع.زر(س ، ص ، العرض ، الارتفاع ، النص ، النافذة):
   ز = زر جديد
   ز : حدد.المكان ( س ، ص )
   ز : حدد.الحجم ( العرض ، الارتفاع )
   ز : حدد.النص ( النص )
   النافذة : اضف ( ز )
   ارجع ب: ز
نهاية
لاحظ هنا أن العوامل (parameters) لا تأخذ تعريف للأنواع، بل فقط تأخذ اسماً، وذلك لأن اللغة dynamically typed مثل لغات البايثون مثلاً أو الجافاسكريبت. أيضاً لاحظ أن النقطة هي جزء من اسم الدالة، أي ان اسمها صنع.زر هكذا كلمة واحدة، النقطة في كلمات هي جزء من رموز المعرفات (identifier characters) ولا دور لها في معنى البرنامج.

الآن وقد صار لدينا دالة تسهل وضع الأزرار يمكننا أن نرسم شكل الآلة الحاسبة، نبدأ أولاً بالأزرار ثم نضيف لاحقاً 'شاشة العرض' التي ستظهر عليها النتيجة:
ن = النافذة.الحالية ( )
زر1 = صنع.زر (40 ، 130 ، 30 ، 30 ، "1" ، ن)
زر2 = صنع.زر (70 ، 130 ، 30 ، 30 ، "2" ، ن)
زر3 = صنع.زر (100، 130 ، 30 ، 30 ، "3" ، ن)
زر4 = صنع.زر (40 ، 100 ، 30 ، 30 ، "4" ، ن)
زر5 = صنع.زر (70 ، 100 ، 30 ، 30 ، "5" ، ن)
زر6 = صنع.زر (100، 100 ، 30 ، 30 ، "6" ، ن)
زر7 = صنع.زر (40 ، 70  ، 30 ، 30 ، "7" ، ن)
زر8 = صنع.زر (70 ، 70  ، 30 ، 30 ، "8" ، ن)
زر9 = صنع.زر (100 ، 70 ، 30 ، 30 ، "9" ، ن)
زر0 = صنع.زر (70 ، 160 ، 30 ، 30 ، "0" ، ن)

زر.الجمع = صنع.زر (10 ، 70  ، 30 ، 30 ، "+" ، ن)
زر.الطرح = صنع.زر (10 ، 100 ، 30 ، 30 ، "-" ، ن)
زر.الضرب = صنع.زر (10 ، 130 ، 30 ، 30 ، "×" ، ن)
زر.القسمة = صنع.زر(10 ، 160 ، 30 ، 30 ، "÷" ، ن )
زر.يساوي = صنع.زر (40 ، 160 ، 30 ، 30 ، "=" ، ن)
زر.الفاصلة.العشرية = صنع.زر(100، 160، 30، 30، "."، ن)

والآن حان دور شاشة العرض:
الشاشة = سطر.نصي جديد
الشاشة : حدد.المكان ( 10 ، 30 )
الشاشة : حدد.الحجم ( 120 ، 30 )
الشاشة : حدد.النص ( "" )
ن : اضف ( الشاشة )

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

الآن يمكننا تجربة البرنامج:

شكله ظريف، لكن هناك مشكلتان: النافذة حجمها الافتراضي أكبر من اللازم، كما أن عنوانها "تنفيذ البرنامج" عام أكثر مما ينبغي...من السهل تغيير ذلك على أية حال. أضف هذه السطور لآخر البرنامج:

ن : حدد.الحجم ( 150 ، 210 )
ن : حدد.العنوان ( "الحاسبة" )


هذا أفضل بكثير!

ادخال المستخدم للأرقام

الآن بعد عمل "شكل" البرنامج حان وقت اضافة "المضمون". أول شيء نريده هو عرض الأرقام حين يدخلها المستخدم. الأمر نلخصه في القواعد الآتية:
1- إذا ضغط المستخدم زر رقمي [0..9]، اضف الرقم المناظر للزر إلى شاشة العرض
2- إذا ضغط المستخدم زر الفاصلة العشرية اضفه لشاشة العرض إذا كانت هذه أول مرة يضغط فيها، وإلا لا تفعل شيئاً.

قبل أن نبدأ بتنفيذ كل ذلك علينا أن نأخذ جانباً ونعرف كيف نتعامل مع الحوادث (events) مثل ضغط زر او اختيار شيء من قائمة أو ما شابه. يحدث ذلك في كلمات عن طريق مفهوم القنوات.

اضف هذا الجزء لنهاية البرنامج:
كرر :
   تسلم إشارة من ضغط  زر1
   الشاشة : الحق.نص ( "1" )
تابع
هناك قناة في فصيلة الأزرار اسمها ضغط. القناة هي كائن يمكن عن طريقه لجزء من البرنامج (مثل الزر) أن يرسل إشارة لجزء آخر (مثل السطور السابقة) عندما يريد ابلاغه بحدث معين.

الأمر
تسلم إشارة من ضغط زر1
سوف يؤدي لأن ينتظر البرنامج حتى يرسل الزر الإشارة المطلوبة قبل المتابعة. سوف تأتي تلك الإشارة حين يضغط المستخدم زر ادخال الواحد1، في تلك الحالة سيضيف البرنامج الرمز "1" لشاشة العرض ويعود إلى حالة الانتظار في حلقة لا نهائية.

لو قمت بتجربة البرنامج الآن ستجد أنه يضيف "1" إلى الشاشة كلما ضغطت الزر المطلوب.

(دور القنوات أكثر بكثير مما قيل هنا، لكن لن نتوسع في الحديث عنها في هذا المثال المبدئي)

كيف نجعله يضيف باقي الأرقام؟ المشكلة أن هذه الكود لن تنفع:
كرر :
   تسلم إشارة من ضغط زر1
   الشاشة : الحق.نص ( "1" )

   تسلم إشارة من ضغط زر2
   الشاشة : الحق.نص ( "2" )
تابع
لماذا لن تنفع؟ لأننا هنا نأمره أن يتسلم الإشارات بالترتيب، أي أننا نقول للبرنامج "تسلم اشارة من ضغط زر1، ثم تسلم إشارة من زر2". هذا سيعمل فقط لو أراد المستخدم أن يدخل شيئاً مثل "12" أو "1212"، "121212"...الخ :(

ما الحل إذاً؟ لابد من طريقة نقول له أنه هناك أكثر من قناة وعليك استلام اشارة من أي واحدة منها حين تأتي. هذا هو دور الأمر تخير
كرر :
    تخير :
    تسلم إشارة من ضغط زر1 :
       الشاشة : الحق.نص ( "1" )
    أو تسلم إشارة من ضغط زر2 :
       الشاشة : الحق.نص ( "2" )
    تم
تابع
هنا سوف ينتظر البرنامج أي من الإشارتين، ضغط زر1 أو ضغط زر2، فإن جاءت الإشارة سينفذ جزء الكود المرتبط بها (أي يضيف 1 أو 2 إلى الشاشة حسب الإشارة القادمة) ثم يتابع في حلقة لا تنتهي.

من السهل تعميم ذلك لندخل الأرقام كلها:
كرر :
    تخير :
    تسلم إشارة من ضغط زر1 :
       الشاشة : الحق.نص ( "1" )
    أو تسلم إشارة من ضغط زر2 :
       الشاشة : الحق.نص ( "2" )
    أو تسلم إشارة من ضغط زر3 :
       الشاشة : الحق.نص ( "3" )
    أو تسلم إشارة من ضغط زر4 :
       الشاشة : الحق.نص ( "4" )
    أو تسلم إشارة من ضغط زر5 :
       الشاشة : الحق.نص ( "5" )
    أو تسلم إشارة من ضغط زر6 :
       الشاشة : الحق.نص ( "6" )
    أو تسلم إشارة من ضغط زر7 :
       الشاشة : الحق.نص ( "7" )
    أو تسلم إشارة من ضغط زر8 :
       الشاشة : الحق.نص ( "8" )
    أو تسلم إشارة من ضغط زر9 :
       الشاشة : الحق.نص ( "9" )
    أو تسلم إشارة من ضغط زر0 :
       الشاشة : الحق.نص ( "0" )
    تم
تابع
الكود طويلة لكن كلها تشبه بعضها؛ لا تعقيد كبير فيها. هناك طرق لجعلها أكثر تنظيماً لكن صورتها الحالية بسيطة، ونحن نريده مثالاً بسيطاً في الوقت الحالي...

الفاصلة العشرية

سوف نستخدم متغيراً منطقياً اسمه كتبنا.فاصلة.عشرية، في بداية البرنامج سوف تكون قيمته خطأ، ثم نجعل قيمته صحيح حين نضغط زر الفاصلة العشرية لأول مرة. لن يضف البرنامج الرمز "." إلى الشاشة إلا مرة واحدة فقط حين تكون قيمة هذا المتغير خطأ في بداية البرنامج.
كتبنا.فاصلة.عشرية = خطأ

كرر :
    تخير :
    تسلم إشارة من ضغط زر.الفاصلة.العشرية :
        إذا كتبنا.فاصلة.عشرية = خطأ :
            الشاشة : الحق.نص ( "." )
            كتبنا.فاصلة.عشرية = صحيح
        تم
    أو تسلم إشارة من ضغط زر1 :
        الشاشة : الحق.نص ( "1" )
    أو تسلم إشارة من ضغط زر2 :
        الشاشة : الحق.نص ( "2" )
    ........وهكذا وهكذا الخ الخ
    تم
تابع

العمليات

هيا الآن ننفذ عملية الجمع وسيكون من السهل تعميم الطريقة بعد ذلك لتشمل جميع العمليات. سوف نحتاج هنا متغيران جديدان: متغير اسمه العملية والآخر اسمه العدد.الأول

المتغير المسمى العملية يدل على العملية الحسابية الحالية. في البداية ستكون قيمته نصاً فارغاً، فإذا ضغط المستخدم زر الجمع سنعطيه القيمة "+"، بحيث نعرف ما المطلوب من الحاسبة عند ضغط زر 'يساوي'.

ستأخذ الكود الصورة التالية:
كتبنا.فاصلة.عشرية = خطأ
العملية = ""
العدد.الأول = لاشيء
 
كرر :
    تخير :
    تسلم إشارة من ضغط زر.الجمع :
        العملية = "+"
        العدد.الأول = الشاشة : نصه ( )
        العدد.الأول = كعدد ( العدد.الأول )
        كتبنا.فاصلة.عشرية = خطأ
        الشاشة : حدد.النص ( "" )

    أو تسلم إشارة من ضغط زر.يساوي :
        العدد.الثاني = الشاشة : نصه ( )
        العدد.الثاني = كعدد ( العدد.الثاني )
        إذا العملية = "+" :
            النتيجة = العدد.الأول + العدد.الثاني
            النتيجة = كنص ( النتيجة )
            الشاشة : حدد.النص ( النتيجة )
            العملية = ""
        تم
    أو تسلم إشارة من ضغط زر.الفاصلة.العشرية :
        ....وهكذا الكلام السابق الذي نعرفه....
    تم
تابع
تعال نأخذ كل جزء على حدىً.. أولاً زر الجمع نفسه:
...
تسلم إشارة من ضغط زر.الجمع :
    العملية = "+"
    العدد.الأول = الشاشة : نصه ( )
    العدد.الأول = كعدد ( العدد.الأول )
    كتبنا.فاصلة.عشرية = خطأ
    الشاشة : حدد.النص ( "" )
...
هذا الجزء يقوم بالآتي عند ضغط زر الجمع:
1- يحدد العملية بأنها "+"
2- يأخذ النص المكتوب على الشاشة، يحوله لعدد، ويخزنه في المتغير العدد.الأول لأننا سنحتاجه بعد ذلك لإجراء عملية الجمع
3- يفرغ الشاشة استعداداً لإدخال رقم جديد
4- يسمح لنا بإدخال فاصلة عشرية (إن أردنا) أثناء إدخال الرقم الثاني وذلك بأن يجعل قيمة كتبنا.فاصلة.عشرية تساوي خطأ

الجزء الآخر عند ضغط زر 'يساوي'
....
أو تسلم إشارة من ضغط زر.يساوي :
    العدد.الثاني = الشاشة : نصه ( )
    العدد.الثاني = كعدد ( العدد.الثاني )
    إذا العملية = "+" :
        النتيجة = العدد.الأول + العدد.الثاني
        النتيجة = كنص ( النتيجة )
        الشاشة : حدد.النص ( النتيجة )
        العملية = ""
    تم
....
هذا بدوره يقوم بالآتي:
1- يأخذ العدد الموجود على الشاشة ويخزنه في المتغير العدد.الثاني
2- يتأكد أن العملية عملية جمع (سيكون هذا مهماً حين نضيف باقي العمليات) ويحسب النتيجة المطلوبة
3- يعرض النتيجة على الشاشة بعد تحويلها إلى صورة نصية
4- يعيد العملية إلى القيمة غير المعرفة "" إلى أن نختار عملية جديدة

هناك فقط مشكلة هي أن البرنامج سيعمل بطريقة صحيحة مرة واحدة فقط: لو أدخلت 12 ثم + ثم 13 ثم = فستجد النتيجة 25، لكن إن ضغطت بعدها 1 فستجد مكتوب على الشاشة 251

هذا خطأ..كان المفروض أن يعتبر البرنامج اننا انتهينا من الحسبة القديمة ويفرّغ الشاشة قبل بدء الحسبة الجديدة، بحيث يظهر على الشاشة 1

أيضاً تصرف آلتنا الحاسبة ليس مثل الآلة العادية. نحن حين نضغط 12 ثم + سوف نجد الشاشة قد مسحت، بينما في الحاسبة العادية سوف نضغط 12 ثم + ولا يتم مسح الشاشة إلا عند بدء إدخال العدد الثاني.

نحن نحتاج طريقة نقول بها للبرنامج "نحن على وشك إدخال عدد جديد، لذلك قم بمسح الشاشة المرة القادمة لو ضغط المستخدم زر عددي، ثم اعرض ما ادخل".

لكي نحل المشكلة نحتاج لمتغير جديد اسمه تفريغ، معناه "هل علينا أن نفرغ الشاشة حين يضغط المستخدم على زر عددي في المرة القادمة"؟

سوف نحتاج أيضاً أن نعدّل البرنامج قليلاً (التعديلات بالخط الثقيل ولونها أحمر):
كتبنا.فاصلة.عشرية = خطأ
العملية = ""
العدد.الأول = لاشيء
تفريغ = خطأ 
 
كرر :
    تخير :
    تسلم إشارة من ضغط زر.الجمع :
        العملية = "+"
        العدد.الأول = الشاشة : نصه ( )
        العدد.الأول = كعدد ( العدد.الأول )
        كتبنا.فاصلة.عشرية = خطأ
        تفريغ = صحيح 
    أو تسلم إشارة من ضغط زر.يساوي :
        العدد.الثاني = الشاشة : نصه ( )
        العدد.الثاني = كعدد ( العدد.الثاني )

        إذا العملية = "+" :
            النتيجة = العدد.الأول + العدد.الثاني
            النتيجة = كنص ( النتيجة )
            الشاشة : حدد.النص ( النتيجة )
            العملية = ""
            تفريغ = صحيح 
        تم
    أو تسلم إشارة من ضغط زر.الفاصلة.العشرية :
        إذا كتبنا.فاصلة.عشرية = خطأ :
            الشاشة : الحق.نص ( "." )
            كتبنا.فاصلة.عشرية = صحيح
        تم
    أو تسلم إشارة من ضغط زر1 :
        إذا تفريغ = صحيح :
            الشاشة : حدد.النص ( "" ) 
            تفريغ = خطأ 
        تم
        الشاشة : الحق.نص ( "1" )
    أو تسلم إشارة من ضغط زر2 :
       ...باقي الأرقام مثلها مثل 1
    تم
تابع
الموضوع بسيط جداً:
1- في نهاية ضغط زر الجمع أو زر يساوي نقوم بتحديد قيمة تفريغ لتكون صحيح.
2- في أزرار الأرقام نتأكد من قيمة ذلك المتغير، فإن كانت صحيح نقوم بمسح الشاشة قبل عرض الرقم المكافيء للزر

يبقى شيء واحد هو تعميم العمليات لتشمل الطرح والقسمة والضرب. سوف نعرض هنا البرنامج كاملاً بعد إضافة هذا الجزء:
دالة صنع.زر(س، ص، العرض، الارتفاع، النص، النافذة):
    ز = زر جديد
    ز : حدد.المكان ( س ، ص )
    ز : حدد.الحجم ( العرض ، الارتفاع )
    ز : حدد.النص ( النص )
    النافذة : اضف ( ز )
    ارجع ب: ز
نهاية

ن = النافذة.الحالية ( )
زر1 = صنع.زر (40 ، 130 ، 30 ، 30 ، "1" ، ن)
زر2 = صنع.زر (70 ، 130 ، 30 ، 30 ، "2" ، ن)
زر3 = صنع.زر (00 ، 130 ، 30 ، 30 ، "3" ، ن)
زر4 = صنع.زر (40 ، 100 ، 30 ، 30 ، "4" ، ن)
زر5 = صنع.زر (70 ، 100 ، 30 ، 30 ، "5" ، ن)
زر6 = صنع.زر (100، 100 ، 30 ، 30 ، "6" ، ن)
زر7 = صنع.زر (40 ، 70  ، 30 ، 30 ، "7" ، ن)
زر8 = صنع.زر (70 ، 70  ، 30 ، 30 ، "8" ، ن)
زر9 = صنع.زر (100، 70  ، 30 ، 30 ، "9" ، ن)
زر0 = صنع.زر (70 ، 160 ، 30 ، 30 ، "0" ، ن)

زر.الجمع = صنع.زر (10،  70 ، 30 ، 30 ، "+" ، ن)
زر.الطرح = صنع.زر (10، 100 ، 30 ، 30 ، "-" ، ن)
زر.الضرب = صنع.زر (10، 130 ، 30 ، 30 ، "×" ، ن)
زر.القسمة = صنع.زر(10، 160 ، 30 ، 30 ، "÷" ، ن)
زر.يساوي = صنع.زر (40، 160 ، 30 ، 30 ، "=" ، ن)

زر.الفاصلة.العشرية = صنع.زر(100، 160، 30، 30، "."، ن)

الشاشة = سطر.نصي جديد
الشاشة : حدد.المكان ( 10 ، 30 )
الشاشة : حدد.الحجم ( 120 ، 30 )
الشاشة : حدد.النص ( "" )
ن : اضف ( الشاشة )

ن : حدد.الحجم ( 150 ، 210 )
ن : حدد.العنوان ( "الحاسبة" )
كتبنا.فاصلة.عشرية = خطأ
العملية = ""
العدد.الأول = لاشيء
تفريغ = خطأ

كرر :
    تخير :
    تسلم إشارة من ضغط زر.الجمع :
        العملية = "+"
        العدد.الأول = الشاشة : نصه ( )
        العدد.الأول = كعدد ( العدد.الأول )
        كتبنا.فاصلة.عشرية = خطأ
        تفريغ = صحيح
    أو تسلم إشارة من ضغط زر.الطرح :
        العملية = "-"
        العدد.الأول = الشاشة : نصه ( )
        العدد.الأول = كعدد ( العدد.الأول )
        كتبنا.فاصلة.عشرية = خطأ
        تفريغ = صحيح
    أو تسلم إشارة من ضغط زر.الضرب :
        العملية = "×"
        العدد.الأول = الشاشة : نصه ( )
        العدد.الأول = كعدد ( العدد.الأول )
        كتبنا.فاصلة.عشرية = خطأ
        تفريغ = صحيح
    أو تسلم إشارة من ضغط زر.القسمة :
        العملية = "÷"
        العدد.الأول = الشاشة : نصه ( )
        العدد.الأول = كعدد ( العدد.الأول )
        كتبنا.فاصلة.عشرية = خطأ
        تفريغ = صحيح
    أو تسلم إشارة من ضغط زر.يساوي :
        العدد.الثاني = الشاشة : نصه ( )
        العدد.الثاني = كعدد ( العدد.الثاني )
        النتيجة = لاشيء
        إذا العملية = "+" :
            النتيجة = العدد.الأول + العدد.الثاني
        وإلا إذا العملية = "-" :
            النتيجة = العدد.الأول - العدد.الثاني
        وإلا إذا العملية = "×" :
            النتيجة = العدد.الأول × العدد.الثاني
        وإلا إذا العملية = "÷" :
            النتيجة = العدد.الأول ÷ العدد.الثاني
        تم

        إذا ليس النتيجة = لاشيء :
            النتيجة = كنص ( النتيجة )
            الشاشة : حدد.النص ( النتيجة )
            العملية = ""
            تفريغ = صحيح
        تم
    أو تسلم إشارة من ضغط زر.الفاصلة.العشرية :
        إذا كتبنا.فاصلة.عشرية = خطأ :
            الشاشة : الحق.نص (".")
            كتبنا.فاصلة.عشرية = صحيح
        تم
--------
    أو تسلم إشارة من ضغط زر1 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("1")
--------
    أو تسلم إشارة من ضغط زر2 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("2")
--------
    أو تسلم إشارة من ضغط زر3 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("3")
--------
    أو تسلم إشارة من ضغط زر4 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("4")
--------
    أو تسلم إشارة من ضغط زر5 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("5")
--------
    أو تسلم إشارة من ضغط زر6 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("6")
--------
    أو تسلم إشارة من ضغط زر7 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("7")
--------
    أو تسلم إشارة من ضغط زر8 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("8")
--------
    أو تسلم إشارة من ضغط زر9 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("9")
--------
    أو تسلم إشارة من ضغط زر0 :
        إذا تفريغ :
            الشاشة : حدد.النص ("")
            تفريغ = خطأ
        تم
        الشاشة : الحق.نص ("0")
    تم
تابع
يبدو البرنامج طويلاً، لكن تذكر أنه كله أجزاء متكررة: الكود الخاصة بالعمليات مكررة أربع مرات والجزء الخاص بالأرقام عشر مرات! هناك بالتأكيد طرق لاختصار هذه الكود كما قلت، لكن حاليا...إنها تعمل :)


مازال هناك بعض الإمكانات التي يمكن إضافتها:
  • السماح بإدخال سلسلة مثل 12 / + / 13 / + / 15 بحيث تظهر نتيجة "12+13" عند ضغط علامة زائد الثانية قبل استمرار العمليات
  • إجراء العمليات بالترتيب الرياضي الصحيح، يعني لو أدخل المستخدم 7+5×2 تكون النتيجة 17 وليس 24
  • تدارك أخطاء المستخدم المحتملة
لكن هذه الإمكانيات خارج نطاق هذا المثال التوضيحي على أية حال. يمكنك أن تكتبها أنت إن أردت ^^