تحقيق الذات في كتابة البرمجيات بلغة كلمات

من كلِمَات

(تم التحويل من Book)
اذهب إلى: تصفح, البحث

محتويات

تحميل لغة كلمات

يمكنك الحصول على نسخة مبدئية من مفسّر لغة كلمات من الرابط الآتي:

http://code.google.com/p/kalimat/downloads/list

أو من هنا:

http://www.kalimat-lang.com/w/files/a/ac/Kalimat_31_December_2012.zip

قم بتحميل هذه النسخة واستخلاص كل الملفات المضغوطة بصيغة ZIP. بعد ذلك شغّل برنامج kalimat.exe لتبدأ بيئة كلمات بالعمل.

رابط لهذا الكتاب

يمكن العودة لهذا الكتاب بسهولة (أو تمريره لآخرين) عن طريق الرابط التالي: http://www.kalimat-lang.com/wiki/Book

القواعد الثلاثة الأساسية

  1. البرنامج في أبسط صوره هو مجموعة من الأوامر المكتوبة
  2. كل أمر يجب أن يكون في سطر خاص به
  3. الأوامر تُنفّذ بالترتيب من الأعلى للأسفل

لنكتب أول برنامج!

اطبع 18
اطبع 12 + 13
اطبع "مرحبا"
اطبع "5+5"، 5+5
  • الأمر الأول مكون من جزئين: امر الطباعة نفسه (كلمة "اطبع") والقيمة المطلوب طبعها (18).
  • الأمر الثاني بدلا من تقديم قيمة جاهزة لطباعتها فهو يقدم تعبيرا يمكن منه حساب القيمة المطلوبة هو 12+13.
  • الأمر الثالث يطبع قيمة نصية. كل تعبير في صورة كلام بين علامتي "..." هو قيمة نصية تؤخذ كما هي بالضبط.
ملاحظة: نحن في الحساب قد اعتدنا ان القيم هي الأرقام، لكننا نحتاج للقيم النصية في برامج كثيرة (مثل برامج الchat أو برنامج دفتر مواعيد او مسابقة اسئلة وأجوبة)-- لذلك معظم لغات البرمجة تتعامل مع النصوص أيضا. بعد قليل سنكتشف أنه مثل الأرقام هناك عمليا ت "حسابية" يمكن إجراؤها على النصوص!
  • الأمر الرابع نتعلم منه شيئين:
  1. يمكن طباعة اكثر من قيمة بفصلهم بعلامة الفاصلة
  2. التعبير "5+5" سيطبع كما هو ولن يُحسب منه شيئا لأن الكلام بين علامتي تنصيص، بينما التعبير الذي يليه 5+5 يعبر عن عملية حسابية سيجريها مفسر كلمات قبل طباعة النتيجة. جرب تنفيذ هذا الأمر وانظر ما سيحدث! ماذا تتوقع؟

المتغيرات

تعال نتخيل اننا نريد برنامجاً يوافق المستخدم على أي شيء يقوله: مثلا لو قال المستخدم "هشام عبقري"، يرد البرنامج قائلا "نعم هشام عبقري". لو قال المستخدم "2+2=5" يرد البرنامج "نعم 2+2=5"، وهكذا.

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

اقرأ شيئا من المستخدم
اطبع كلمة "نعم" يليها الشيء الذي قرأته من المستخدم

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

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

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

هيا نعود إلى البرنامج الذي يوافقك في كل شيء. سنحتاج فيه أمر جديد هو أمر اقرأ.

هذا الأمر يأتي بصورة كلمة اقرأ يتبعها اسم متغير؛ وحينما ينفّذ هذا الأمر فإن الكمبيوتر سينتظر منك أن تكتب له شيئا وتضغط مفتاح <enter> فإن فعلت ذلك يأخذ البرنامج ما كتبت ويخزنه في المتغير المطلوب.

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

اقرأ ر
اطبع "نعم"،" "، ر

هيا نتابع تنفيذ البرنامج خطوة بخطوة:

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

لذلك ستجد قد طبع على الشاشة "نعم أكره الواجبات المدرسية"(أو النص الذي أدخلته أياً كان) تماما كما أردنا!

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

تعال نكتب برنامجا آخر!

اطبع "ادخل اسمك"
اقرأ س1
اطبع "ادخل اسم ابيك"
اقرأ س2
اطبع "تشرفنا يا"، " "، س1، " "، س2

جرب أن تدخل هذا البرنامج وتنفذه. ماذا تتوقع أن يحدث؟

تمارين

  1. اكتب برنامجا يقرأ جملة ثم يطبعها مكررة مرتين، مثلا لو قلت له "الجو حار!" يكتب "الجو حار! الجو حار!"
  2. عدل البرنامج بحيث يقرأ جملة واسم شخص، ثم يكرر الجملة موجها الكلام إلى الشخص في المنتصف. مثلا لو ادخلت له "الجو حار" و "سمير" فيجب أن يكون الرد "الجو حار يا سمير الجو حار".
  3. اكتب برنامجا يسألك عن اسم شخص، وفعل مضارع، ومكان، واسم حيوان، ثم يطبع عبارة في صورة "في يوم كان <الشخص> <الفعل> مع <الحيوان> في <المكان>". جرب البرنامج مع أشخاص لا يعرفون ما الحكاية. جرب أنواع مختلفة من الجُمل :)

قراءة قيم عددية

تعال نكتب برنامجا يقرأ عددين ويحسب لنا حاصل ضربهم (علامة × هي مفتاح shift + خ):

اقرأ م
اقرأ ن
اطبع م×ن

جرب أن تنفّذ هذا البرنامج وتدخل له قيمتين مثل 10 و 11، ماذا سيحدث؟ تجد لغة كلمات تشكو لك: "عملية الضرب لا تُجرى إلا على أعداد!".

ولكن...ألم ندخل له أعداداً؟

في الواقع لم نفعل ذلك! تذكر أنه في كلمات هناك فرق بين القيمة العددية (مثل 100) وبين القيمة النصية (مثل "100"). يشبه الأمر رقم الهاتف أو رقم السيارة: رقم الهاتف عبارة عن مجموعة من الارقام تستخدم كما هي، ولا معنى لأن استخدمه في عمليات حسابية مثلا، لذلك فهو اشبه بقيمة نصية منها قيمة عددية ولو كان مكوّناً بالكامل من ارقام.

بنفس الطريقة الأمر اقرأ يعتبر نفسه دائما يقرأ قيم نصية ما لم نقل له العكس، ولكي نجعله يقرأ قيماً عددية نحتاج أن نسبق اسم المتغير بالعلامة # ليفهم أننا نريد تخزين قيمة عددية في المتغير.

اقرأ #م
اقرأ #ن
اطبع م×ن

الآن يعطي البرنامج النتيجة الصحيحة.

ملاحظة: العلامة # هي جزء من الأمر اقرأ وليست جزءا من اسم المتغير. لاحظ اننا في السطر الثالث استخدمنا م و ن كالمعتاد ولم نسمّهم مثلا #م و #ن.

الآن نستطيع أن نكتب برامجا تحسب بدلا منا! تعال مثلا نكتب برنامجا لحساب مساحة الدائرة ومحيطها (حسابا تقريبيا):

اطبع "ادخل نصف قطر الدائرة"
اقرأ #نق
اطبع "المساحة="، 3.14157 × نق × نق
اطبع "المحيط="، 3.14157 × 2 × نق

ويمكننا أيضا أن نكتب برنامج حساب بسيط(لاحظ أن علامة القسمة هي shift + خ):

اقرأ "ادخل الرقم الأول"، #س
اقرأ "ادخل الرقم الثاني"، #ص

اطبع "المجموع:"، س + ص
اطبع "الفرق:"، س - ص
اطبع "حاصل الضرب:"، س × ص
اطبع "ناتج القسمة:"، س ÷ ص

لاحظ كيف أن أمر اقرأ يمكن ان يوضع فيه رسالة قبل اسم المتغير؛ وفي هذه الحالة يعرض الأمر الرسالة على الشاشة قبل ان ينتظر منك ادخال القيمة.

القرارات

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

ما هي نوعية القرارات التي يمكن لبرنامج كبير أن يتخذها؟

  • السماح لمستخدم بالتعامل مع البرنامج فقط إذا كان يعرف كلمة السر.
  • تحريك شخصية في اللعبة ناحية اليمين إذا ضغط المستخدم مفتاح الحركة لليمين.
  • قراءة ملف من على الhard disk فقط إذا كان ذلك الملف موجودا.
  • إجراء عملية حسابية فقط إذا كان لها معنى (مثلا عدم محاولة القسمة على صفر).
  • ...وهكذا

هذه النوعية من القرارات لها أمر خاص في كلمات، هو أمر (ترقّب! ترقّب!)...إذا.

وذلك الأمر يكون في الصورة التالية:

إذا <شرط> :
    <أوامر>
تم
ملاحظة: لاحظ ان أمر إذا فيه الهمزة تحت الألف (بعكس الأوامر اطبع، اقرأ التي لا تبدأ بهمزة أصلا). لكي تكتب ألف تحتها همزة بلوحة المفاتيح اضغط shift + غ، وقد يساعدك على تذكر هذا المفتاح أنه يقع فوق زر الألف العادية.

مثلا هذا البرنامج:

اقرأ "كم سنك؟"، #س
إذا س = 10:
    اطبع "أنت في العاشرة!"
    اطبع "مبروك"
تم
اطبع "لقد انتهى البرنامج"
  • في البداية سيسألك البرنامج عن سنك ويضع الإجابة في المتغير س.
  • ثم سيكون تنفيذ عبارتي الطباعة في منتصف البرنامج مقيد بشرط أن تكون قيمة المتغير س تساوي 10، فإن كانت القيمة بالفعل كذلك فسيتم تنفيذ الجزء بين علامة النقطتين ':' و كلمة 'تم'، وإلا فلن يُنفّذ هذا الجزء من البرنامج
  • وسواءً تحقق ذلك الشرط أم لا فإن البرنامج سيتابع تنفيذ الأوامر من بعد كلمة تم، بحيث يطبع أخيراً عبارة "لقد انتهى البرنامج".

هيا نكتب برنامجاً آخر يجمع رقمين بشرط أن يعرف المستخدم كلمة السر:

اقرأ "ما هي كلمة السر؟"، ج
إذا ج = "ساندوتش":
    اقرأ "ما الرقم الأول؟"، #م
    اقرأ "ما الرقم الثاني؟"، #ن
    اطبع "المجموع هو:"، م+ن
تم

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

بمعنى أصح..نحن قد أخبرنا الأمر 'إذا' بما نريد أن يفعل لو تحقق الشرط، لكننا نريد أن نخبره بما يفعل لو لم يتحقق الشرط!

هذا سهل، كل ما علينا هو أن نستخدم مقطع "وإلا" كما يلي:

اقرأ "ما هي كلمة السر؟"، ج
إذا ج = "ساندوتش":
    اقرأ "ما الرقم الأول؟"، #م
    اقرأ "ما الرقم الثاني؟"، #ن
    اطبع "المجموع هو:"، م+ن
وإلا:
    اطبع "انت لم تعرف كلمة السر"
    اطبع "لذلك انت محروم من امكانية جمع رقمين"
تم

وأخيرا، إذا كان أمر إذا لا يقيّد سوى امراً واحداً يمكن كتابة الشرط والنتيجة في نفس السطر وحذف كلمة "تم"

اقرأ "هل أديت الواجبات المدرسية؟"، الرد
إذا الرد="نعم" : اطبع "أحسنت"

يمكن عمل نفس الشيء إذا تضمن الأمر جزء "وإلا"

اقرأ "هل أديت الواجبات المدرسية؟"، الرد
إذا الرد="نعم" : اطبع "أحسنت" وإلا: اطبع "قم ادّ الواجبات"

أمر اذهب إلى

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

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

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

سيتضح كل شيء في المثال الآتي:

علامة أ
اطبع "أريد المصروف يا أبي"
اذهب إلى أ
  • السطر الأول لن يكون له تأثير لأن كلمة علامة لا دور لها إلا مع أمر اذهب إلى
  • السطر الثاني سيطبع عبارة "أريد المصروف يا أبي"
  • السطر الثالث سيجعل مفسر كلمات يعود إلى السطر الأول ويبدأ تنفيذ البرنامج من جديد

وتكون النتيجة النهائية أن البرنامج سيظل يكرر طباعة عبارة "أريد المصروف يا أبي" بلا توقف حتى تغلق نافذة تنفيذ البرنامج.

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

علامة أ
اقرأ الجملة
اطبع "نعم "، الجملة
اقرأ "هل تريد ادخال جملة أخرى؟"، الرد
إذا الرد="نعم": اذهب إلى أ

هذا مثال لنتيجة تنفيذ البرنامج السابق (في صورة حوار بين المستخدم والكمبيوتر):

السماء زرقاء
نعم السماء زرقاء
هل تريد ادخال جملة أخرى؟ نعم
الملابس في الدولاب
نعم الملابس في الدولاب
هل تريد ادخال جملة أخرى؟ نعم
ناو هاو عاو
نعم ناو هاو عاو
هل تريد ادخال جملة أخرى؟ لا

تمارين

  1. اكتب برنامجا يقرأ رقمين ويطبع من فيهما الأكبر. (ملاحظة: علامة > على لوحة المفاتيح هي مفتاح shift + د).
  2. اكتب برنامجا يجعل المستخدم يخمّن كلمة سرية مخزونة في البرنامج، هذا مثال للحوار الذي يمكن أن يقوم بين البرنامج والمستخدم:
انا افكر في كلمة، ما هي؟
سيارة
خطأ!
شجرة
خطأ!
ورقة
احسنت!

التخصيص

عرفنا أن الأمر اقرأ يخزن قيمة في متغير؛ الطريقة الأخرى لتخزين قيمة هي أمر التخصيص، وهو يأتي في صورة:

<اسم متغير> = <قيمة>

مثلا:

س = 5
ص = 6
اسمي = "محمد"
ع = س + ص
  • الأمر الأول معناه "خزن القيمة العددية 5 في المتغير س" (والأمر الثاني يشبهه).
  • الأمر الثالث معناه "خزن القيمة النصية محمد في المتغير الذي يُدعى اسمي".
  • الأمر الرابع ينفذه مفسر كلمات في خطوتين:
    1. حساب قيمة التعبير س+ص، وهي 11 بسبب الأوامر السابقة
    2. تخزين النتيجة في المتغير ع

ماذا لو كتبنا البرنامج الآتي؟

س = 1
س = س + 5
اطبع س

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

  1. الأمر الأول يضع القيمة 1 في المتغير س
  2. الأمر الثاني سوف
    • يحسب القيمة س + 5، باستخدام قيمة س الموجودة حاليا (أي القيمة 1) فتكون النتيجة 6
    • يخزّن النتيجة المحسوبة في المتغير س، فتكون قيمة س الجديدة هي 6 بدلا من 1
  3. الأمر الثالث يطبع قيمة س فيظهر 6 على الشاشة.

لاحظ أن الخطوات في (٢) هنا هي نفسها بالضبط الخطوات في المثال السابق ع=س+ص! الكمبيوتر لا يهمه إذا كانت س موجودة على يمين علامة = وعلى يسارها، بل هو فقط ينفذ الأوامر المطلوبة منه حرفيا: يحسب القيمة الموجودة على يسار = ثم يخزنها في المتغير على اليمين.

الدالات

الدالة هي وحدة برمجية، كل دالة تحسب لك قيما معينة بحسب وظيفتها: فهناك دالة تحسب الجذر التربيعي لرقم، وهناك دالة تحسب طول النص (أي عدد الحروف والرموز فيه) وهناك دوال تحسب جيب أو ظل الزاوية، ودوال أخرى كثيرة.

اطبع "ادخل كلمة وسأخبرك بعدد حروفها"
اقرأ ن
اطبع طول(ن)

لاحظ كيف كتبنا في السطر الأخير التعبير طول(ن) ليُحسب منه القيمة المطلوب طباعتها. هذا التعبير اسمه استدعاء الدالة، حيث الدالة هنا اسمها "طول" والقيمة المقدمة لها هي قيمة المتغير ن.

تنفيذ البرنامج سيكون كالتالي:

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

توجد دوال كثيرة في لغة كلمات غير دالة "طول"، يمكنك أن ترى قائمة بها كلها هنا.

هناك دالة سنستخدمها لاحقا اسمها "عشوائي"، هذه الدالة تأخذ عددا يدخلها وتعطي لنا عددا صحيحا عشوائيا في النطاق:

صفر ≥ النتيجة > العدد المدخل

مثلا عشوائي(10) تعطينا عددا من صفر إلى تسعة، عشوائي(25) تعطينا عدداً عشوائيا من صفر إلى 24، وهكذا.

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

الجمع بين أدوات البرمجة

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

سنطبّق الآن فكرة تجميع المكونات عمليّاً بأن نكتب برنامجاً يجمع بين معظم ما تعلمناه حتى الآن: برنامج تخمين الأرقام.

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

هذا مثال للحوار بين الكمبيوتر والمستخدم:

أنا أفكر في رقم من 1 إلى 100
ماهو؟ 30
إجابتك أصغر من اللازم
ماهو؟ 90
إجابتك أكبر من اللازم
ماهو؟ 55
إجابتك أكبر من اللازم
ماهو؟ 43
أحسنت! إجابتك صحيحة!

وهذا هو البرنامج

القيمة.الصحيحة = عشوائي(100) + 1
اطبع "أنا أفكر في رقم من 1 إلى 100"
علامة ب
اقرأ "ما هو؟ "، #الرد
إذا الرد > القيمة.الصحيحة:
    اطبع "إجابتك أكبر من اللازم"
    اذهب إلى ب
تم

إذا الرد < القيمة.الصحيحة:
    اطبع "إجابتك أصغر من اللازم"
    اذهب إلى ب
تم

إذا الرد = القيمة.الصحيحة:
    اطبع "أحسنت! إجابتك صحيحة!"
تم

أعتقد أنك قد صرت تعرف البرمجة بما يكفي لتدرك وحدك كيف يعمل هذا البرنامج! هناك فقط ملاحظتين صغيرتين على هذا الجزء في البداية:

القيمة.الصحيحة = عشوائي(100) + 1
  • الملاحظة الأولى أن اسم المتغير مكون من كلمتين فصلنا بينهما بنقطة، وذلك لأنه ممنوع وجود مسافة في اسماء المتغيرات.
  • الملاحظة الثانية أنه كما نعلم، حين نستدعي الدالة عشوائي(100) ستعطي لنا قيمة بين صفر و99 لذلك جمعنا 1 على تلك القيمة قبل تخزينها في المتغير لتصبح بين 1 و100 كما أردنا.

مثال آخر

هيا نكتب برنامجاً آخر يجمع بين كل ما تعلمنا حتى الآن: برنامج اختبار الحساب. كالعادة سوف نصف البرنامج بتقديم مثال للحوار بينه وبين المستخدم:

ما نتيجة 12+14؟
30
خطأ!
هل تريد التجربة مرة أخرى؟ نعم
ما نتيجة 15+16؟
31
صواب!
هل تريد التجربة مرة أخرى؟ نعم
ما نتيجة 10+13؟
23
صواب!
هل تريد التجربة مرة أخرى؟ لا

وهذا هو البرنامج نفسه

علامة البداية
أ = عشوائي(20)
ب = عشوائي(20)
الاجابة.الصحيحة = أ + ب
اطبع "ما نتيجة "، أ، "+"، ب،"؟"
اقرأ #الرد
إذا الرد = الاجابة.الصحيحة: اطبع "صواب" وإلا: اطبع "خطأ"
اقرأ "هل تريد التجربة مرة أخرى؟ "، د
إذا د="نعم": اذهب إلى البداية

بعد حين يصير مملّاً أن نسأل المستخدم كل مرّة إذا كان يريد الاستمرار في حل المسائل أم لا. نريد طريقة أخرى لإيقاف البرنامج.

أحد الأفكار هي أن نسأل المستخدم عددا معينا من المسائل (فليكن خمسة) ثم نتوقف. من السهل تعديل البرنامج ليتصرف بهذه الطريقة الجديدة:

المرات = 0
علامة البداية
أ = عشوائي(20)
ب = عشوائي(20)
الاجابة.الصحيحة = أ + ب
اطبع "ما نتيجة "، أ، "+"، ب،"؟"
اقرأ #الرد
إذا الرد = الاجابة.الصحيحة: اطبع "صواب" وإلا: اطبع "خطأ"
المرات = المرات + 1
إذا المرات < 5: اذهب إلى البداية

معظم سطور البرنامج كما هي ماعدا بضع تغييرات:

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

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

تمارين

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

المزيد عن أمر إذا

أنواع جديدة من الشروط

نحن قد جربنا ثلاثة أنواع من الشروط:

  • تساوي قيمتين (باستخدام علامة =)
  • وجود قيمة اكبر من أخرى أو أصغر منها (علامات <، >)

لكي نكمل مجموعتنا نقدم علامات أخرى:

  • >= ومعناها "أكبر من أو يساوي" مثل علامة ≥ في الحساب.
  • <= ومعناها "أصغر من أر يساوي" مثل علامة ≤ في الحساب.
  • <> ومعناها "لا يساوي" مثل علامة ≠.

الروابط المنطقية

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

شرط1 وأيضا شرط2

هنا يتحقق الشرط الكبير فقط إذا تحقق الجزئين معاً.

شرط1 أو شرط2

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

ليس شرط

ليس أ يتحقق إن لم يتحقق أ نفسه، والعكس صحيح

ليس شرط1 ولا شرط2

يجب أن لا يتحقق أي من الشرطين لكي يتحقق الشرط الكبير.

ملاحظة: يمكن الجمع بين أكثر من شرطين في معظم هذه الأوامر؛ مثلا يمكنني أن أقول أ وأيضا ب وأيضا ج ، أ أو ب أو ج، ليس أ ولا ب ولا ج

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

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

استخدام أكثر من شرط

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

اقرأ "ادخل العدد الأول "، #أ
اقرأ "ادخل العدد الثاني "، #ب

إذا أ>ب :
    اطبع "العدد الأول هو الأكبر"
وإلا إذا ب>أ :
    اطبع "العدد الثاني هو الأكبر"
وإلا:
    اطبع "العددان متساويان"
تم
  • في البدء سيقرأ البرنامج العددان أ و ب، ثم يدخل في تنفيذ أمر إذا
  • لو تحقق الشرط الأول أ>ب فسيطبع البرنامج أن العدد الأول هو الأكبر ثم ينتهي تنفيذ أمر إذا.
  • أما في حالة عدم تحقق الشرط الأول فسيجرب الشرط الثاني ب>أ، فإن تحقق هذا الشرط الثاني فسيطبع البرنامج أن الثاني هو الأكبر ثم ينتهي تنفيذ أمر إذا.
  • وإن لم يتحقق أي من الشروط المكتوبة وكان في النهاية مقطع وإلا: بدون شروط (مثلما يوجد في المثال) فسوف ينفذ الأوامر المذكورة بعد مقطع وإلا:.

لكن هل هناك ضرورة أصلا لهذه الطريقة في كتابة الأمر إذا؟ ألم نكن نستطيع أن نكتب نفس البرنامج بثلاثة أوامر إذا منفصلة كما فعلنا في برنامج تخمين الأرقام؟

هناك سببان للطريقة الجديدة:

  1. تجميع الشروط المرتبطة بنفس الهدف في أمر واحد يسهّل فهم البرنامج للعين التي تقرأه.
  2. أحيانا مقطع "وإلا إذا" يسهّل كتابة الشروط المطلوبة. انظر لهذا البرنامج، الذي يحسب التقدير من الدرجة:
اقرأ "ادخل الدرجة(بين صفر ومائة):"، #د
إذا د<35:
    اطبع "ضعيف جدا"
وإلا إذا د<50:
    اطبع "ضعيف"
وإلا إذا د< 65:
    اطبع "مقبول"
وإلا إذا د< 80:
    اطبع "جيد"
وإلا إذا د< 90:
    اطبع "جيد جدا"
وإلا:
    اطبع "امتياز"
تم

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

  1. سيرى أولا إن كانت د<35، فيجدها ليست كذلك
  2. ثم ينظر إن كانت د<50 فيجدها ليست كذلك
  3. ثم ينظر إن كانت د<65 فيجدها بالفعل كذلك، فيطبع البرنامج كلمة "مقبول" ثم يخرج من أمر إذا ولا يجرب أي شرط آخر.

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

اقرأ "ادخل الدرجة(بين صفر ومائة):"، #د

إذا د<35:
    اطبع "ضعيف جدا"
تم

إذا د>=35 وأيضا د<50:
    اطبع "ضعيف"
تم

إذا د>= 50 وأيضا د< 65:
    اطبع "مقبول"
تم

(...الخ)

طرق أخرى للتحكم

هناك فئة خاصة من المتغيرات اسمها المتغير العداد، وقد رأينا مثالاً له في برنامج اختبار الحساب (النسخة التي تسأل خمس مسائل): المتغير الذي سميناه المرات.

العداد اسمه كذلك لأنه عادةً ما يعبر عن عدد شيء: عدد المسائل التي حلها المتسخدم، عدد الدوائر التي يجب أن نرسمها، عدد السطور التي قرأناها من ملف، وهكذا

ويتكرر هذا النمط من البرمجة كثيراً:

1- ضع قيمة ابتدائية في العداد
2- نفذ العمليات المطلوبة
3- زود قيمة العداد
4- إذا لم يبلغ العداد القيمة النهائية، اذهب إلى 2

هذه الطريقة في البرمجة اسمها التكرار الحَلَقي، أو loops. ومن كثرة انتشارها هناك وسائل خاصة لكتابتها في كثير من لغات البرمجة. في لغة كلمات هذه الوسيلة الخاصة هي أمر لكل، وصورته كالآتي:

لكل <متغير> من <البداية> إلى <النهاية> :
    <أوامر>
تابع

ابسط مثال لهذا الأمر:

لكل أ من 1 إلى 5:
    اطبع أ
تابع

سوف يعطي هذا البرنامج النتيجة التالية:

1
2
3
4
5

هل هناك طريقة أخرى لكتابة هذا البرنامج؟ نعم كان يمكن أن نكتبه في تلك الصورة:

أ=1
علامة س
اطبع أ
أ = أ + 1
إذا أ<=5: اذهب إلى س

رغم أن البرنامجان متكافئان في نتيجتهما، إلا أن البرنامج الأول افضل بكثير في توضيح نية المبرمج، وبمجرد النظر له تعرف أن المقصود هو العدّ من 1 إلى 5 وأن العداد هو أ.

مثلث النجوم

نريد عمل برنامج مثلث النجوم، هذا عرض لتشغيل البرنامج (الجزء المكتوب بخط سميك كتبه المستخدم):

ما حجم المثلث؟
5
*
**
***
****
*****

هذه المرة لن اكتب لك البرنامج ثم اشرحه، بل سنكتب البرنامج سوياً خطوة خطوة.

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

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

حسناً..لابد من خطة إذن:

1.اسأل المستخدم عن حجم المثلث
2.اطبع عدداً من السطور بذلك الحجم يحقق شروط البرنامج

هذه الخطة ليست جيدة جداً، فقد تحايلنا على الموقف بكلمة "يحقق شروط البرنامج" بدلاً من أن نذكر ماهية هذه الشروط تحديداً. هذا لا ينفع-- فلنجرب مرة أخرى:

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

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

1.اسأل المستخدم عن حجم المثلث، وسمه ن
2.اطبع عدد ن من الأسطر، كل منهم يحقق الشرط الآتي:
   إذا كنا في السطر رقم أ فيجب أن يكون السطر فيه عدد
   من النجوم يساوي أيضا أ.

جميل جداً! الآن يمكننا أن نبدأ في تحويل الخطة إلى برنامج. سوف اكتب الخطة الآن في مراحل تحويلها، وفي كل مرة سأعلّم بالخط الثقيل على الجزء الذي سيتحول الآن إلى برنامج.

1.اسأل المستخدم عن حجم المثلث، وسمه ن
2.اطبع عدد ن من الأسطر، كل منهم يحقق الشرط الآتي:
   إذا كنا في السطر رقم أ فيجب أن يكون السطر فيه عدد
   من النجوم يساوي أيضا أ.

واضح أن أول جزء سنحوله هو السؤال عن حجم المثلث (وهذا جزء سهل). ستصبح الخطة الآن كالآتي:

اطبع "ما حجم المثلث؟"
اقرأ #ن
اطبع عدد ن من الأسطر، كل منهم يحقق الشرط الآتي:
   إذا كنا في السطر رقم أ فيجب أن يكون السطر فيه عدد
   من النجوم يساوي أيضا أ.

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

اطبع "ما حجم المثلث؟"
اقرأ #ن
لكل أ من 1 إلى ن:
    اطبع عدداً من النجوم المتجاورة يساوي أ
تابع

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

اطبع "ما حجم المثلث؟"
اقرأ #ن
لكل أ من 1 إلى ن:
    لكل ب من 1 إلى أ:
        اطبع "*"
    تابع
تابع

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

ما حجم المثلث؟
3
*
*
*
*
*
*

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

ألا توجد طريقة نقول بها للبرنامج "اطبع هذه الأشياء وابق في نفس السطر، لأننا نريد أن نطبع أشياء قادمة في السطر نفسه؟"

في الواقع توجد طريقة لذلك. جرب هذا البرنامج الآن في كلمات:

اطبع "الجو "
اطبع "جميل"

اطبع "الجو "...
اطبع "جميل"

ستكون النتيجة كالآتي:

الجو 
جميل
الجو جميل

يتضح إذن أن أمر اطبع لا يذهب لسطر جديد لو وضعنا ثلاث نقاط متجاورة ... في نهايته. هيا نستغل هذه المعلومة الجديدة:

اطبع "ما حجم المثلث؟"
اقرأ #ن
لكل أ من 1 إلى ن:
    لكل ب من 1 إلى أ:
        اطبع "*" ...
    تابع
تابع

هل سيجعل هذا البرنامج يتصرف بشكل صحيح؟ ليس بالضبط:

ما حجم المثلث؟
3
******

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

اطبع "ما حجم المثلث؟"
اقرأ #ن
لكل أ من 1 إلى ن:
    اطبع عدداً من النجوم المتجاورة يساوي أ
    انتقل لسطر جديد
تابع
حسناً، وكيف ننتقل لسطر جديد؟ ببساطة عن طريق أن نطلب طباعة نص فارغ! يعني هكذا:
اطبع ""

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

اطبع "ما حجم المثلث؟"
اقرأ #ن
لكل أ من 1 إلى ن:
    لكل ب من 1 إلى أ:
        اطبع "*" ...
    تابع
    اطبع ""
تابع

وهذا البرنامج يقوم بالمطلوب بالضبط:

ما حجم المثلث؟
6
*
**
***
****
*****
******

لقد قمنا بإنجاز عظيم! يمكننا أن نرتاح قليلاً قبل أن نستمر.

تمارين

  • عدل برنامج مثلث النجوم بحيث يرسم مستطيلاً من النجوم بطول وعرض يدخلهما المستخدم، هكذا مثلاً:
ما عرض المستطيل؟
4
ما ارتفاع المستطيل؟
6
****
****
****
****
****
****
  • عدل البرنامج بحيث يطبع مثلثاً مقلوباً من النجوم:
ما حجم المثلث؟
4
****
***
**
*
  • عدل البرنامج بحيث يرسم مستطيلاً مفرّغاً:
ما عرض المستطيل؟
4
ما ارتفاع المستطيل؟
6
****
*  *
*  *
*  *
*  *
****

الرسومات

تحديد الأماكن على الشاشة

شاشة تنفيذ البرنامج مكونة من نقط صغيرة جداً، والكمبيوتر يلوّن كل نقطة باللون المناسب لتظهر الصورة التي نريد. كيف نحدد للكمبيوتر اننا نريد التعامل مع نقطة معينة؟ كي نجيب على السؤال لابد أن نعرف أولاً نظام الإحداثيات في البرنامج:

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

Coordinate-system.png

يجب أن نعرف أيضاً:

  • أن عرض الشاشة 800 نقطة وارتفاعها 600 نقطة.
  • وأن نقطة الأصل في المكان س= صفر، ص=صفر.
  • وأن قيمة س تتزايد من اليمين إلى اليسار
  • بينما قيمة ص تتزايد من الأعلى للأسفل.

هذه إذن أمثلة لبعض النقاط (بالأحمر) في نظام الإحداثيات الحالي:

Coordinate-system-sample-points.png

ملاحظة: النقط في الصورة مكبرة عن النقط الحقيقية بغرض التوضيح، لأن النقط الحقيقية بالكاد تُرى بالعين المجردة!

أمر ارسم.نقطة

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

ارسم.نقطة(<س>، <ص>)، <اللون>

قد عرفنا ما معنى (س، ص) في هذا الأمر، إنهما عددان يعبران عن مكان النقطة المطلوب رسمها، فما معنى اللون؟ في كلمات هناك 16 لوناً جاهزين تستخدمهما جميع أوامر الرسم، وكل لون له رقم: أول هذه الأرقام هو صفر (الأسود) وآخرهم 15 (الأبيض)، والألوان الأخرى (أحمر، أخضر...الخ) بين هذين الرقمين.

Color-map.png

ماذا لو لم نحدد لون النقطة؟ في تلك الحالة سيرسمها مفسر كلمات باللون الأسود ويكون شكل الأمر هكذا:

ارسم.نقطة(<س>، <ص>)

كيف نرسم نقطة في مكان عشوائي؟ تذكر أن قيمة س (المكان على محور السينات) هي دائماً بين 0 و799. لذلك لو أردنا الحصول على قيمة عشوائية لـ س فسينفعنا استدعاء الدالة عشوائي(800). نفس النظام بالنسبة لقيمة ص، في تلك الحالة يكفي أن ننادي عشوائي(600). ماذا عن اللون؟ لأنه بين صفر و15 يمكننا أن ننادي عشوائي(16).

هيا نستغل تلك المعلومات في برنامج يرش باقة من الألوان على الشاشة عن طريق رسم خمسين ألف نقطة عشوائية:

لكل أ من 1 إلى 50000:
    س = عشوائي(800)
    ص = عشوائي(600)
    ل = عشوائي(16)
    ارسم.نقطة(س، ص)، ل
تابع

طبعاً كان يمكن أن نسمي المتغيرين أي شيء غير س/ص، لأن المهم فقط هو مكانهما في أمر ارسم.نقطة. بل كان يمكن ان نستدعي الدالة عشوائي مباشرة بداخل الأمر نفسه هكذا:

لكل أ من 1 إلى 50000:
    ارسم.نقطة (عشوائي(800)، عشوائي(600)عشوائي(16)
تابع

في الحالتين سيكون تنفيذ البرنامج يشبه الآتي:

Random-pixels.png

أمر ارسم.خط

رسم نقطة على الشاشة ليس بالشيء المشوق جداً..هيا نرسم شيئا أعقد: الخط. رسمه يكون بالأمر التالي:

ارسم.خط(<س1>، <ص1>)-(<س2>، <ص2>)، <اللون>

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

هيا نعدّل برنامج النقاط العشوائية بحيث يرسم هذه المرة خطوطاً عشوائية. لأن الخطوط تملأ الشاشة أسرع من النقاط فسنرسم عدد أقل من الخطوط، قل مائتين مثلاً:

لكل أ من 1 إلى 200:
    س1 = عشوائي(800)
    ص1 = عشوائي(600)
    س2 = عشوائي(800)
    ص2 = عشوائي(600)
    ل = عشوائي(16)
    ارسم.خط(س1، ص1)-(س2، ص2)، ل
تابع

Random-lines.png

هل سنفعل شيئاً بأوامر الرسم غير رسم خطوط ونقاط عشوائية؟ تعال نجرب مثلاً رسم شبكة من المربعات:

لكل أ من 1 إلى 8:
    ارسم.خط(0، أ×50)-(400، أ×50)
تابع

لكل أ من 1 إلى 8:
    ارسم.خط(أ×50، 0)-(أ×50، 400)
تابع

سيرسم هذا البرنامج الشكل الأتي:

Eight-by-eight-grid.png

كيف يعمل البرنامج؟ في البداية وضعت خطة:

  • ستكون الشبكة 8 صفوف من المربعات و8 أعمدة
  • طول وعرض كل مربع 50 نقطة
  • لذلك فإن طول الشبكة وعرضها يساوي 50×8 = 400 نقطة
  • الشبكة تبدأ من ركن الشاشة العلوي على اليمين-- أي من النقطة (0، 0)

ثم ينقسم البرنامج لجزئين:

  1. الجزء الأول يرسم ثمانية خطوط أفقية
  2. الجزء الثاني يرسم ثمانية خطوط رأسية.

ننظر للجزء الأول:

لكل أ من 1 إلى 8:
    ارسم.خط(0، أ×50)-(400، أ×50)
تابع

هذا البرنامج يرسم ثمانية خطوط كالآتي:

من (0، 50)  إلى (400، 50)
من (0، 100) إلى (400، 100)
من (0، 150) إلى (400، 150)
...وهكذا إلى:
من (0، 400) إلى (400، 400)

نلاحظ إذن:

  • لكي يكون الخط أفقياً لابد أن تكون نقطتاه لهما نفس قيمة ص (لأننا لا نتحرك رأسيا في أي مكان على الخط)
  • نريد أن يمتد الخط بالعرض من س=0 إلى س=400 لكي يأخذ عرض الشبكة كلها
  • نريد أن تكون المسافة الرأسية بين كل خط 50 نقطة لذلك جعلنا ص=50، ص=100، ص=150..حتى ص=400

نفس الكلام بالنسبة للجزء الثاني لكن استبدلنا السينات والصادات:

لكل أ من 1 إلى 8:
    ارسم.خط(أ×50، 0)-(أ×50، 400)
تابع

والخطوط التي يرسمها:

من (50 ، 0) إلى (50 ، 400)
من (100، 0) إلى (100، 400)
من (150، 0) إلى (150، 400)
...وهكذا إلى:
من (400، 0) إلى (400، 400)
  • الخطوط نفسها تتحرك افقياً (س1 وس2 يزدادون بمقدار 50 نقطة كل مرة).
  • لكن كل خط هو رأسي (س1 دائما تساوي س2 في الخط الواحد).
  • و ص1 دائما تساوي صفر، ص2 تساوي 400، بحيث يمتد الخط من أعلى الشبكة لأسفلها

امر ارسم.مستطيل

امر ارسم.دائرة

المصفوفات

مقدمة للمصفوفات

الوان.الطيف = ["احمر"، "برتقالي"، "اصفر"، "اخضر"،
               "ازرق"، "نيلي"، "بنفسجي"]

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

ما معنى الوصول لقيمة برقمها؟ هكذا مثلاً:

الوان.الطيف = ["احمر"، "برتقالي"، "اصفر"، "اخضر"،
               "ازرق"، "نيلي"، "بنفسجي"]
اطبع الوان.الطيف[2]

قيمة التعبير الوان.الطيف[2] هي ثاني عنصر في المصفوفة، لذلك ستجد البرنامج السابق قد طبع النص برتقالي على الشاشة.

ملاحظة: يمكن كتابة عناصر المصفوفة على أكثر من سطر بشرط أن تكون علامة الفاصلة (،) هي آخر شيء في كل سطر سابق.

البحث في مصفوفة

هيا نستخدم معلوماتنا الجديدة في برنامج أكبر:

الوان.الطيف = ["احمر"، "برتقالي"، "اصفر"، "اخضر"،
               "ازرق"، "نيلي"، "بنفسجي"]

اطبع "ادخل لوناً وسأخبرك إن كان من الوان الطيف أم لا"
اقرأ اللون
لكل أ من 1 إلى 7:
    إذا اللون = الوان.الطيف[أ]:
        اطبع "نعم انه من الوان الطيف"
    تم
تابع

تعال نتتبع تنفيذ البرنامج مرة لو ادخلت له القيمة اصفر (وهو من الوان الطيف بالطبع) ومرة لو ادخلت القيمة لبني، أي قيمة ليست من الوان الطيف.

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

إذن نتيجة البرنامج النهائية هي طباعة العبارة "نعم انه من الوان الطيف" مرة واحدة.

ماذا لو كنا قد ادخلنا القيمة "لبني"؟ في تلك الحالة لم يكن شرط الأمر إذا ليتحقق ابداً لأن قيمة المتغير اللون لن تساوي مطلقاً الوان.الطيف[أ]، إذ أن هذا اللون ليس موجوداً في المصفوفة.

لكن هذا البرنامج ليس في افضل صوره. انه لا يقول شيئاً لو لم يكن اللون موجوداً ضمن مصفوفتنا. كيف نحل هذه المشكلة؟ يمكننا أن نستخدم امر اذهب إلى بهذه الطريقة:

الوان.الطيف = ["احمر"، "برتقالي"، "اصفر"، "اخضر"،
               "ازرق"، "نيلي"، "بنفسجي"]

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

حساب مجموع الأعداد

نريد كتابة برنامج يحسب مجموع اعداد مخزونة في مصفوفة.

  • في البداية سوف تكون الأعداد مخزّنة في البرنامج نفسه.
  • ثم سنعدّل البرنامج بحيث يقرأ الأعداد من المستخدم.

هيا نكتب خطة أولا:

-عرف مصفوفة فيها بعض القيم العددية
-احسب مجموع هذه المصفوفة

تنفيذ أول جزء من الخطة سهل:

م = [5، 38، 12، 70، 120، 8، 5، 3]
احسب مجموع هذه المصفوفة

كيف سنحسب مجموع الأعداد؟ سيكون الأمر أسهل لو وضعنا الهدف في صيغة رياضية. ما هو التعريف الرياضي لذلك المجموع؟

المجموع: م[1] + م[2] + م[3] + ...حتى كل عناصر المصفوفة

هذا افضل، لكن مازلنا لا نعرف كيف نكتب البرنامج. وجود م[1]، م[2]...في الموضوع يوحي لنا أننا نستطيع استخدام أمر لكل في البرنامج. فلنجرب إذا:

م = [5، 38، 12، 70، 120، 8، 5، 3]
لكل أ من 1 إلى 8:
    ماذا نفعل بـ م[أ]؟؟؟؟؟
تابع
هنا سوف نطبع المجموع بعد أن نحسبه

(جعلنا أ من واحد إلى ثمانية لأن المصفوفة بها ثمانية قيم)

بقى أن نعرف ماذا سنضع بين لكل وتابع. أو بمعنى آخر ماذا سنفعل بكل قيمة ممكنة لـ م[أ] : الطبيعي أننا نريد أن نضيفها إلى المجموع الذي نريد أن نحسبه، يعني كل مرة ينفذ فيها الجزء بين لكل وتابع يجب أن يزيد المجموع بمقدار م[أ]. كيف نفعل ذلك برمجياً؟ بأن نعرّف متغيراً ونضيف إليه القيمة المطلوب اضافتها:

م = [5، 38، 12، 70، 120، 8، 5، 3]
لكل أ من 1 إلى 8:
    ج = ج + م[أ]
تابع
اطبع "المجموع هو "، ج

لكن لو جربنا تشغيل البرنامج سنجد مفسر كلمات يشكو ويقول متغير غير معروف 'ج'! في الواقع هذا خطأ منطقي في برنامجنا، لأننا نحاول ان نعدل قيمة ج بينما هو ليس لديه قيمة أصلا في البداية. ما هي القيمة التي ينبغي أن تأخذها ج في أول البرنامج؟ نريد قيمة لا تؤثر على المجموع الذي نحسبه حين نبدأ في اضافة عناصر المصفوفة --أي القيمة صفر.

ج = 0
م = [5، 38، 12، 70، 120، 8، 5، 3]
لكل أ من 1 إلى 8:
    ج = ج + م[أ]
تابع
اطبع "المجموع هو "، ج

هذا البرنامج سيطبع القيمة الصحيحة! لكن بقى شيء...

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

المشكلة أن هذه خطوة إضافية يجب أن نقوم بها كل مرة وقد ننساها في أية وقت، ألا توجد طريقة لجعل التكرار يتم بعدد عناصر المصفوفة أياً كان بدون تغيير امر لكل؟

يمكن ذلك باستخدام الدالة عدد، وهي تأخذ مصفوفة وتعيد لنا عدد العناصر التي فيها، فيكون البرنامج كالتالي:

ج = 0
م = [5، 38، 12، 70، 120، 8، 5، 3]
لكل أ من 1 إلى عدد(م):
ج = ج + م[أ]
تابع
اطبع "المجموع هو "، ج

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

هناك طريقتان لإنشاء مصفوفة في لغة كلمات:

  1. حين تكون كل عناصر المصفوفة معروفة يمكننا انشاؤها بوضع كل عناصرها بين [ و ]
  2. في حالة عدم معرفة عناصر المصفوفة لكن معرفة عدد تلك العناصر نستطيع استخدام الدالة مصفوفة، وهي دالة لو أخذت عدد ن (مثلا) فستعطينا مصفوفة تستوعب عدد ن من العناصر.

هذا جيد! سنفعل الآتي إذاً:

اقرأ "كم عددا تريد أن تجمع؟"، #ع
م = مصفوفة(ع)
لكل أ من 1 إلى ع:
    اقرأ "ادخل قيمة:"، م[أ]
تابع

ج = 0
م = [5، 38، 12، 70، 120، 8، 5، 3]
لكل أ من 1 إلى عدد(م):
ج = ج + م[أ]
تابع
اطبع "المجموع هو "، ج
  • في البداية سيسأل البرنامج عن عدد القيم المطلوب جمعها
  • ثم سيصنع مصفوفة حجمها هو نفسه ذلك العدد
  • ثم في تكرار حلقي سيسأل عن قيمة كل عنصر في المصفوفة، م[أ]
  • ثم سيبدأ عملية الجمع بالضبط مثل البرنامج السابق

وهذا مثال لتنفيذ البرنامج:

كم عددا تريد أن تجمع؟ 5
ادخل قيمة:12
ادخل قيمة:5
ادخل قيمة:100
ادخل قيمة:72
ادخل قيمة:27
المجموع هو 216

تمارين

  1. اكتب برنامجاً يقرأ مجموعة من الأعداد في مصفوفة ثم يطبع لك تلك الأعداد بالعكس (مثلا لو أدخلت له 12، 28، 5 سيطبع 5، 28، 12).
  2. اكتب برنامجاً يقرأ عدد ن ومجموعة من الأعداد في مصفوفة ثم يطبع للمستخدم القيم في المصفوفة التي هي أكبر من ن.

القيم المنطقية

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

اطبع 5>4
اطبع 1=2
اطبع ليس 1=2

ستجد ان النتيجة المطبوعة كالآتي:

صحيح
خطأ
صحيح

ما معنى هذه التجربة؟ ما اصلاً معنى شيء مثل اطبع 5>4؟ هل هذه قيمة يمكن طبعها؟

في لغة كلمات (ولغات برمجة أخرى كثيرة) هذا بالفعل تعبيرٌ يعطي قيماً هي القيم المنطقية (boolean values)، ومجموعة القيم المنطقية تحتوي فقط على قيمتين: القيمة صحيح والقيمة خطأ

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

لذلك يمكنني أن أفعل الآتي:

اقرأ #أ
اقرأ #ب
ك = أ > ب
إذا ك:
    اطبع "العدد الأول أكبر"
وإلا:
    اطبع "العدد الثاني أكبر"
تم

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

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

اقرأ #أ
اقرأ #ب
تساويا = أ = ب
إذا تساويا:
    اطبع "العددان متساويان"
وإلا:
    اطبع "العددان غير متساويان"
تم

السطر المكتوب بالخط السميك معناه كما نعلم:

  1. احسب القيمة المنطقية أ = ب
  2. ضع النتيجة في المتغير تساويا

ما فائدة اعتبار القيم المنطقية قيماً عادية في اللغة؟ هناك فوائد كثيرة، منها مثلاً:

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

المتغير الراية

هناك ادوار كثيرة للمتغيرات قد عرفناها:

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

<للتكملة...>

عمليات على النصوص

كما وعدت في أول هذا الكتاب، سنعرف الآن بعض العمليات على النصوص. اول عملية هي عملية الإلصاق (concatenation) أي ضمّ نصين مع بعضهما لصنع نص جديد، مثلاً:

س = "البحر "
ص = "الأحمر"
ع = س + ص
اطبع ع

سوف يطبع هذا البرنامج عبارة البحر الأحمر على الشاشة، لأن المعامل + حين يطبّق على نصين فإنه يعطينا نتيجة الصاقهما.

هناك أيضاً استخراج أجزاء من النصوص، وكلمات تقدم لنا ثلاث دالات من هذا النوع:

  • دالة أول وهي تأخذ رقما ونصا وتعود بالحروف الأولى في النص بحسب الرقم. مثلا أول(3، "صنعاء") تعود لنا بالقيمة النصية صنع. لماذا صممت الدالة بحيث تأخذ رقما ثم نصا؟ لكي يمكن قراءة التعبير أول(3، "صنعاء") كالآتي: "أول ثلاثة في صنعاء".
  • دالة آخر وهي تأخذ رقما ونصا وتعود بالحروف الأخيرة في النص بحسب الرقم. مثلا آخر(3، "تكريم") تعود لنا بالقيمة النصية ريم.
  • دالة وسط وهي تأخذ نصا ثم رقم م ورقم ن بحيث تعطينا جزء من النص يبدأ من الخانة م وطوله ن. مثلا وسط("مركبات"، 2، 3) يعطينا القيمة النصية ركب.

هناك دالات للبحث عن نص في نص آخر.

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

لدينا أيضا الدالة تقليم(ن) وهي تأخذ نصاً وتعيد لنا قيمة مثل النص الأول لكن مع مسح أية مسافات في أوله أو آخره (لكن تترك المسافات في وسطه).

مثلاً تقليم(" أنا قد وصلت ") تعيد لنا القيمة النصية "أنا قد وصلت".

وأخيراً هناك دالة مهمة هي تفصيص(ن، ف)

  • وهي تأخذ النص ن والفاصل ف (يجب أن يكون ف نصاً مكوناً من حرفٍ واحدٍ).
  • وتعود بمصفوفة من النصوص عبارة عن تقطيع النص ن على حدود ف
  • مثلا تفصيص("تفاحة*برتقالة*موزة"، "*") تعود بالمصفوفة ["تفاحة"، "برتقالة"، "موزة"]
  • لاحظ كيف أن الفاصل نفسه (* في المثال السابق) لا يظهر في القيمة المرجوع بها.

برنامج دليل الهاتف

تمهيد

الآن قد صرنا نستطيع أن نكتب برنامجاً ذو فائدة حقيقية! نريد أن نكتب برنامج دليل الهاتف، وقبل أن نفعل ذلك سوف نكتب له توصيفاً (specification).


توصيف - برنامج دليل الهاتف

  1. البرنامج يقدم قائمة رئيسية للمستخدم بها الاختيارات الآتية: البحث عن اسم، اضافة اسم ورقم هاتف، تعديل رقم، او مسح سجلّ.
  2. عند اختيار أي أمر وتنفيذه يعود البرنامج إلى القائمة الرئيسية مرة أخرى.
  3. عند اختيار البحث عن اسم يسأل البرنامج عن اسم الشخص ثم يعرض رقم هاتفه لو كان موجوداً، وإلا يقول أنه غير موجود. [اختيارياً: يمكن أن يعرض البرنامج اضافة الرقم المرتبط بالاسم لو لم يكن الاسم موجوداً، فربما كانت نية المستخدم اضافة اسم لكنه كان يتأكد أولا أن ذلك الاسم ليس بموجود].
  4. عند اختيار اضافة اسم يسأل البرنامج عن الاسم والرقم ويخزنهما في ذاكرة الجهاز.
  5. عند اختيار تعديل رقم يدخل المستخدم الاسم، ولو كان ذلك الأسم مسجلاً فسيعرض البرنامج الرقم القديم ويسأل عن الرقم الجديد ثم يخزن الأسم برقمه الجديد. لو لم يكن الاسم مسجلاً فسيقول البرنامج أن الاسم غير موجود ويرجع كالمعتاد للقائمة الرئيسية.
  6. عند اختيار مسح سجل سوف يسأل البرنامج المستخدم عن الاسم، لو كان موجودا فسيعرض الاسم ورقم الهاتف، ثم يسأل المستخدم إن كان متأكداً أنه يريد بالفعل أن يمسح السجل. إن أجاب المستخدم بنعم فسيقوم البرنامج بالمسح.
  7. سوف يقوم البرنامج بتسجيل البيانات بصفة دائمة، بحيث لا تضيع البيانات لو اغلقنا البرنامج وفتحناه من جديد.

كما ترى فإنه برنامج طموح جداً! إنه كبير ومعقد، كما أننا في الواقع لا نملك بعد كل المعلومات المطلوبة لصنعه. مثلاً لعمل الجزء رقم 7 نحتاج أن نتعلم التعامل مع الملفات أولا...

من أجل هذا سوف نقوم بعمل البرنامج تدريجياً جزءاً بجزء. سوف ننفذ أولا الأجزاء 1-4 ثم نعود في جزء لاحق إلى الأجزاء 5-7.

أخيراً اعلم أن هذا البرنامج يجمع بين كل ما تعلمناه من قبل، لذلك أرجو أن تكون قد قرأت الأجزاء السابقة جيداً!

هيا نبدأ

من السهل أن نقوم بالأجزاء رقم 1 و2:

علامة بداية.القائمة
اطبع " ==== برنامج دليل الهاتف ===="
اطبع ""
اطبع "   1 - البحث عن اسم"
اطبع "   2 - اضافة اسم ورقم"
اطبع ""
اقرأ "ادخل اختيارك"، #ن

-- هنا سوف نقوم بتنفيذ ما اختار المستخدم

اذهب إلى بداية.القائمة

حتى الآن البرنامج طبيعي جداً. لكن هناك سطر غريب فيه:

-- هنا سوف نقوم بتنفيذ ما اختار المستخدم

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

التفسير هو أن ذلك السطر يبدأ بشطرتين '--'، وأي سطر في تلك الصورة هو ملاحظة أو تعليق (comment) في البرنامج. التعليقات في لغات البرمجة تكون كلاماً موجهاً للإنسان الذي يتعامل مع البرنامج ولا يفعل مفسر اللغة به شيئا، وللتعليقات فوائد كثيرة في تنظيم المبرمج لأفكاره أو شرح كيفية عمل اجزاء البرنامج لمن يقرأه.

هيا نتابع:

علامة بداية.القائمة
اطبع " ==== برنامج دليل الهاتف ===="
اطبع ""
اطبع "   1 - البحث عن اسم"
اطبع "   2 - اضافة اسم ورقم"
اطبع ""
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    --هنا سوف نبحث عن الاسم
وإلا إذا ن=2:
    --هنا سوف نضيف اسماً ورقماً جديدين
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

التفكير في شكل البيانات

يمكننا أن نخزن كل بياناتنا في مصفوفة. المشكلة أن كل بيان لدينا ليس شيئا بسيطاً مثل عدد، بل هو مركب من جزئين: اسم الشخص ورقم هاتفه. كيف نتصرف في هذا؟

  • يمكننا عمل مصفوفتين، واحدة للاسماء والأخرى للأرقام
  • يمكننا -بطريقة أو أخرى- صنع بيان واحد مركّب من جزئين.

طريقة المصفوفتين تنفع لكن لها عيوب كثيرة: حين نضيف بيانات لابد ان نضيف في اكثر من مكان، حين نمسح لابد أن نمسح من اكثر من مكان، لو أردنا تخزين بيانات أخرى مثل العنوان والبريد الالكترونيّ سنجد انفسنا نتعامل مع مصفوفات أكثر من اللازم...الأمر كله أعقد مما ينبغي.

لنبحث في الطريقة الأخرى: كيف يمكننا أن نضم بيانين إلى بعض لتكوين بيان أكبر؟ لو كان البيانان نصوصاً يمكننا أن نلصقهما ببعض عن طريق المعامل + لتكوين نص أكبر.

لكن عند قراءة النص الكبير من المصفوفة، كيف سنفصله إلى مكوناته الأساسية --الاسم ورقم الهاتف؟ لو أننا فصلنا بين المكونات بفاصل معين (مثلاً "أحمد*0444960") يمكن وقتها استخدام دالة تفصيص لفصلها عن بعض.

هل هناك طرق أخرى؟ نعم: يمكننا تخزين كل اسم ورقم هاتف في مصفوفة صغيرة من عنصرين، وتخزين كل هذه الأزواج في مصفوفة كبيرة مثل هذا:

ب = [["شادي"، "26853277"]، ["عمتي أمنية"، "44556667"]، ["السباك"، 
"81745235"]، ["ابي"، "44637120"]]

سوف نستخدم حاليا هذه الطريقة (المصفوفات الصغيرة) لأنها أكثر تنظيماً من طريقة النص الكبير والفاصل. فكر مثلا ماذا لو استخدمنا النجمة * للفصل بين الاسم ورقم الهاتف ثم كان هناك رقم هاتف خاص فيه علامة *؟ وقتها سيعطي البرنامج نتيجة خاطئة.

اضافة اسماء جديدة

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

تذكر أن البرنامج حاليا يبدو هكذا:

علامة بداية.القائمة
اطبع " ==== برنامج دليل الهاتف ===="
اطبع ""
اطبع "   1 - البحث عن اسم"
اطبع "   2 - اضافة اسم ورقم"
اطبع ""
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    --هنا سوف نبحث عن الاسم
وإلا إذا ن=2:
    --هنا سوف نضيف اسماً ورقماً جديدين
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

نريد أن نصنع مصفوفة تحمل بياناتنا. كم سيكون حجم تلك المصفوفة؟ نحن لا نعلم! سوف نعطيها حجما معقولا، مائة عنصر مثلا، يكفي لتخزين بيانات معظم الناس. سيصير البرنامج هكذا:

البيانات = مصفوفة(100)
علامة بداية.القائمة
اطبع " ==== برنامج دليل الهاتف ===="
اطبع ""
اطبع "   1 - البحث عن اسم"
اطبع "   2 - اضافة اسم ورقم"
اطبع ""
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    --هنا سوف نبحث عن الاسم
وإلا إذا ن=2:
    --هنا سوف نضيف اسماً ورقماً جديدين
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

الآن لدينا شيء نخزن فيه الاسماء والارقام. هيا نتابع البرمجة...

هنا نقطة: نحن لا نريد أن نسرد البرنامج كله من البداية كلما عدلنا فيه شيئا صغيرا، لذلك سنعرض منه فقط الجزء المهم بالنسبة لنا حاليا: سوف نكتب الأسطر الخاصة بعملية اضافة بيانات جديدة ثم عليك بعد ذلك أن تضعها في مكانها الصحيح عند السطر الذي يقول هنا سوف نضيف اسماً ورقماً جديدين

-- الجزء الخاص باضافة البيانات
اقرأ "الاسم:"، أ
اقرأ "الرقم:"، ر
التركيبة = مصفوفة(2)
التركيبة[1] = أ
التركيبة[2] = ر
-- هنا علينا أن نضيف تركيبتنا إلى المصفوفة المسماه '''البيانات'''

حسن! لقد قرأنا الأسم ورقم الهاتف (الذي هو في صورة نصية لأنه لا معنى له حسابيا كعدد).

وبعد ذلك صنعنا مصفوفة من عنصرين ووضعناها في المتغير المسمى التركيبة، وجعلنا أول عناصرها الاسم وثاني عناصرها الرقم.

الآن...كيف نخزن تلك التركيبة في المصفوفة البيانات؟ الطبيعي أن نقول

البيانات[؟] = التركيبة

لكن ما هي القيمة التي سنستخدمها مكان علامة الاستفهام؟ نحن نريد أول مرة أن نخزن في المكان 1، ثاني مرة في المكان 2..وهكذا، لذلك سنستخدم متغير عداد ولنجعله في البداية بواحد، ثم نزوّد قيمته كلما أضفنا شيئا في المصفوفة.

لذلك علينا أن نعدل في مكانين في البرنامج، أولهم بداية البرنامج الرئيسي:

البيانات = مصفوفة(100)
العداد=0
علامة بداية.القائمة
اطبع " ==== برنامج دليل الهاتف ===="
...الخ

وثانيهم الجزء الذي نضيف فيه بيانات:

-- الجزء الخاص باضافة البيانات
اقرأ "الاسم:"، أ
اقرأ "الرقم:"، ر

التركيبة = مصفوفة(2)
التركيبة[1] = أ
التركيبة[2] = ر
العداد = العداد + 1
البيانات[العداد] = التركيبة

هكذا نحن:

  1. نقرأ البيانات في المستخدم
  2. ثم نركّبها مع بعضها في مصفوفة صغيرة
  3. ثم نزود قيمة العداد ليدلنا على المكان الذي سنخزن فيه القيم، ونضع القيمة في المصفوفة الكبيرة المسماة البيانات.
    • في البداية ستكون قيمة العداد = 0
    • عند اضافة أول عنصر نزود العداد ليصبح 1 ثم نخزن البيانات في البيانات[1]
    • عند اضافة ثاني عنصر نزود العداد ليصبح 1 ثم نخزن البيانات في البيانات[2]
    • ...وهكذا، ونلاحظ دائماً أنه بعد اضافة أي عنصر فإن قيمة العداد دائما تساوي عدد العناصر المُخزّنة.

ماذا لو كان المستخدم كثير المعارف وحاول أن يضيف عنصرا بعد العنصر رقم مائة؟ في تلك الحالة سيحاول البرنامج أن يكتب في المكان رقم 101 في المصفوفة وستجد مفسر كلمات يشكو لك ويقول "رقم العنصر المطلوب خارج نطاق المصفوفة". من حقنا أن نضع حداً اقصى للبيانات، لكننا لا نريد أن نجعل البرنامج 'ينفجر' في وجه المستخدم لو فعل شيئاً خطأً!

سوف نعدّل البرنامج ليتعامل مع هذه الحالة:

-- الجزء الخاص باضافة البيانات
إذا العداد < 100:
    اقرأ "الاسم:"، أ
    اقرأ "الرقم:"، ر

    التركيبة = مصفوفة(2)
    التركيبة[1] = أ
    التركيبة[2] = ر
    العداد = العداد + 1
    البيانات[العداد] = التركيبة
وإلا:
    اطبع "آسف، الذاكرة ممتلئة"
تم

لكن تذكر! لا ينبغي أن نكتب شيئا مثل إذا العداد < 100 لأنه لو أردنا تغيير حجم المصفوفة سنضطر لتغيير هذه المائة أيضاً! الأفضل أن نكتب إذا العداد < عدد(البيانات)

(أسم الدالة هنا خدّاع لأن الدالة عدد تعطينا سعة المصفوفة كلها بغض النظر عن عدد البيانات الحقيقة المسجلة فيها، لكن لا بأس-- المهم أن البرنامج سيعمل كما يجب لو قدمنا هذا التغيير.)

البحث في المصفوفة

الآن يمكننا أن نبحث في المصفوفة! كما قلنا سوف نوضح هنا فقط الأجزاء المهمة، وعليك أن تضيف أنت الأسطر المكتوبة هنا في المكان المناسب، عند التعليق الذي يقول هنا سوف نبحث عن الاسم

من حسن الحظ أننا قد كتبنا برامجا تبحث في المصفوفات من قبل. ما سنكتبه الآن يشبهها جدا:

-- الجزء الخاص بالبحث عن الاسم
اقرأ "الاسم:"،ط
وجدناه = خطأ
لكل أ من 1 إلى العداد:
    التركيبة = البيانات[أ]
    الاسم = التركيبة[1]
    الرقم = التركيبة[2]
    إذا الاسم = ط:
       وجدناه = صحيح
       اذهب إلى نهاية.البحث
    تم
تابع
علامة نهاية.البحث
إذا وجدناه:
    اطبع "الرقم الخاص ب"، الاسم، " هو "، الرقم
   وإلا:
       اطبع "لم نجد هذا الاسم: "، ط
 تم

(تذكر أنه بعد اضافة عناصر في المصفوفة فإن قيمة العداد تدل على عدد البيانات المضافة).

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

وأخيراً قد انتهينا! هيا ننظر للبرنامج كاملاً حتى الآن:

البيانات = مصفوفة(100)
العداد=0

علامة بداية.القائمة
اطبع " ==== برنامج دليل الهاتف ===="
اطبع ""
اطبع "   1 - البحث عن اسم"
اطبع "   2 - اضافة اسم ورقم"
اطبع ""
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    -- الجزء الخاص بالبحث عن الاسم------
    اقرأ "الاسم:"،ط
    وجدناه = خطأ
    لكل أ من 1 إلى العداد:
        التركيبة = البيانات[أ]
        الاسم = التركيبة[1]
        الرقم = التركيبة[2]
        إذا الاسم = ط:
           وجدناه = صحيح
           اذهب إلى نهاية.البحث
        تم
    تابع
    علامة نهاية.البحث
    إذا وجدناه:
        اطبع "الرقم الخاص ب"، الاسم، " هو "، الرقم
    وإلا:
        اطبع "لم نجد هذا الاسم: "، ط
    تم
    -- نهاية جزء البجث عن الاسم------
وإلا إذا ن=2:
    -- الجزء الخاص باضافة البيانات------
    إذا العداد < 100:
        اقرأ "الاسم:"، أ
        اقرأ "الرقم:"، ر

        التركيبة = مصفوفة(2)
        التركيبة[1] = أ
        التركيبة[2] = ر
        العداد = العداد + 1
        البيانات[العداد] = التركيبة
    وإلا:
        اطبع "آسف، الذاكرة ممتلئة"
    تم
    -- نهاية جزء إضافة البيانات
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

تحسين تصميم البرنامج

لقد قمنا بعمل جيد حقاً! نريد الآن تطوير البرنامج

  • ربما نجعله اسهل في الاستخدام
  • ربما نجعله أكثر صلابة في مواجهة أخطاء المستخدم (ماذا يحدث لو اضاف اسما قد أضافه من قبل؟)
  • ...ولا ننسى أنه هناك إمكانيات في توصيف البرنامج لم ننفذها بعد، مثل تعديل رقم أو مسح سجل!

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

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

الإجراءات

لو تأملنا البرنامج لوجدنا أنه ينقسم لثلاثة أجزاء أساسية، كل منهم يعد وحده مثل برنامج آخر صغير:

  • الجزء الرئيسي الذي يعرض قائمة للمستخدم ويقرأ اختياراته
  • الجزء الذي يضيف اسما ورقما في المصفوفة
  • الجزء الذي يبحث عن البيانات

(نلاحظ أيضا أن الجزء الأول بمثابة "القائد" الذي يتحكم في باقي الأجزاء)

نحن نريد أن نكتب كل جزء من هؤلاء على حدىً. نستطيع أن نستعين بأداة في لغة كلمات هي الإجراءات، والإجراء عبارة عن مجموعة من الأوامر نجمعها مع بعضٍ ونعطيها اسماً (هذا يسمى تعريف الإجراء) ثم حين نحتاج لتنفيذ هذه الأوامر نعطي اسم الإجراء لمفسر كلمات ونطلب منه أن ينفذه (هذا يسمى استدعاء الإجراء).

تعريف الإجراءات

تعريف إجراء في كلمات يأخذ الشكل التالي:

إجراء <اسم الإجراء>():
<أوامر>
نهاية

(يمكن لهذا التعريف أن يأتي في أول البرنامج أو في آخره، أو حتى في وسطه).

تعال نكتب مثالاً:

إجراء رحب.بي():
    اطبع "أهلاً يا نجوى"
نهاية

لو كتبت هذا المثال في لغة كلمات ونفذته لن تجد شيئا قد طُبع على الشاشة، لماذا؟ لأننا قد عرفنا الإجراء لكن لم نستدعه! أي أننا قد علّمنا البرنامج كيف يطبع رسالة الترحيب لكن لم نطلب منه في الواقع طباعتها!

استدعاء الإجراءات

أما استدعاء الإجراء فيأتي في الصورة التالية، في أي مكان يمكن فيه كتابة أمر:

<اسم الإجراء>()
ملاحظة:القوسين بعد اسم الإجراء لهما أهمية قصوى، سواء في تعريف الإجراء أو أثناء استدعائه، وحذفهما يغير معنى البرنامج.

هيا الآن نجمع بين تعريف إجراء واستدعائه:

إجراء رحب.بي():
    اطبع "أهلاً يا نجوى"
نهاية

لكل أ من 1 إلى 5:
    رحب.بي()
تابع

سوف يكون مخرج ذلك البرنامج:

أهلاً يا نجوى
أهلاً يا نجوى
أهلاً يا نجوى
أهلاً يا نجوى
أهلاً يا نجوى

كان يمكن أيضا استدعاء الإجراء قبل تعريفه، وسوف تفهم لغة كلمات المطلوب:

لكل أ من 1 إلى 5:
    رحب.بي()
تابع

إجراء رحب.بي():
    اطبع "أهلاً يا نجوى"
نهاية

المزيد عن الإجراءات

إن الإجراءات تعطينا قوة كبيرة جداً في البرمجة، كأننا نعرّف أوامرنا الخاصة في لغة كلمات!

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

ألا ينبغي أن تكون نفس الإمكانية في الإجراءات أيضاً؟ يمكننا عمل ذلك عن طريق تقديم معطيات أو عوامل للإجراء. وطريقة تعريف إجراء بمعطيات تكون كالآتي:

إجراء <اسم الإجراء>(<قائمة المعطيات>):
    <أوامر>
نهاية

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

تعال نعرّف إجراءً ونستدعيه في نفس البرنامج:

إجراء رحب(الشخص):
    اطبع "أهلاً يا "، الشخص
نهاية
 
رحب("نجوى")
رحب("سلوى")
رحب("منى")
رحب("ضحى")

(تذكر: لابد من تقديم قيم العوامل بين قوسين عند استدعاء الإجراء!)

ماذا يحدث في البرنامج الآتي:

إجراء اطبع.متوسط(أ، ب):
    م = (أ + ب) ÷ 2
    اطبع م
نهاية

م = 20
ن = 40
اطبع.متوسط(م، ن)

هنا نلاحظ أن البرنامج الرئيسي يحدد قيمة معينة للمتغير م هي 40، بينما الإجراء يغير هو الآخر قيمة م لو استدعيناه (يضع فيها المتوسط الذي سيحسبه). هل سيؤدي استدعاء الإجراء إلى تغيير قيمة م في البرنامج الرئيسي؟ تعال نجرب شيئاً:

إجراء اطبع.متوسط(أ، ب):
    م = (أ + ب) ÷ 2
    اطبع م
نهاية

م = 20
ن = 40
اطبع.متوسط(م، ن)
اطبع م

سوف نجد أن البرنامج قد طبع لنا:

30
40

القيمة المطبوعة الأولى (30) هي نتيجة أمر اطبع م أثناء استدعاء الإجراء، بينما القيمة المطبوعة الثانية (40) هي نتيجة أمر اطبع م في البرنامج الرئيسي، والبرنامج يتصرف كأنهما قيمتين مختلفتين!

في الواقع هما بالفعل كذلك: تذكر أن الهدف من الإجراءات هو أن نفكر في كل جزء من البرنامج بصفة مستقلة عن باقي البرنامج. تخيل أننا قد عرفنا إجراءً وعرفنا فيه متغيرات، هل سيكون علينا مراجعة باقي البرنامج للتأكد أننا لا نؤثر على قيمة متغيرات مهمّة بنفس الأسماء المستخدمة في ذلك الإجراء؟ والعكس صحيح: ماذا لو عرفنا متغيرات في البرنامج الرئيسي، هل يجب أن نراجع كل الإجراءات للاطمئنان على عدم حدوث ملابسات؟ ماذا لو كانت المتغيرات اسمها أ أو ب أو س أو ص، وهذه الاسماء تُستخدم في كل مكان تقريباً!

لتفادي تلك المشكلة فإن لغة كلمات مصممة بحيث أنه حين تعرّف متغيرا بداخل إجراء فإن هذا المتغير يكون محليّاً، أي ذو قيمة خاصة في الإجراء وحده غير مرتبطة بأي قيم له خارج الإجراء.

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

ملاحظة: قائمة معطيات الإجراء هي أيضا تُعتبر متغيرات محلّية.

الإجراءات في برنامج دليل الهاتف

الآن يمكننا أن نحسّن تصميم البرنامج:

البيانات = مصفوفة(100)
العداد=0

علامة بداية.القائمة
اعرض.القائمة()
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    ابحث.عن.اسم()
وإلا إذا ن=2:
    اضف.بيان()
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

ماذا فعلنا هنا؟ لقد انتزعنا كل جزء مستقل في البرنامج ووضعنا بدلاً منه استدعاء إجراء. لن يعمل البرنامج بالطبع إلا حين نعرّف الإجراءات نفسها:

إجراء اعرض.القائمة():
    اطبع " ==== برنامج دليل الهاتف ===="
    اطبع ""
    اطبع "   1 - البحث عن اسم"
    اطبع "   2 - اضافة اسم ورقم"
    اطبع ""
نهاية
إجراء ابحث.عن.اسم():
    اقرأ "الاسم:"،ط
    وجدناه = خطأ
    لكل أ من 1 إلى العداد:
        التركيبة = البيانات[أ]
        الاسم = التركيبة[1]
        الرقم = التركيبة[2]
        إذا الاسم = ط:
           وجدناه = صحيح
           اذهب إلى نهاية.البحث
        تم
    تابع
    علامة نهاية.البحث
    إذا وجدناه:
        اطبع "الرقم الخاص ب"، الاسم، " هو "، الرقم
    وإلا:
        اطبع "لم نجد هذا الاسم: "، ط
    تم
نهاية
إجراء اضف.بيان():
    إذا العداد < 100:
        اقرأ "الاسم:"، أ
        اقرأ "الرقم:"، ر

        التركيبة = مصفوفة(2)
        التركيبة[1] = أ
        التركيبة[2] = ر
        العداد = العداد + 1
        البيانات[العداد] = التركيبة
    وإلا:
        اطبع "آسف، الذاكرة ممتلئة"
    تم
نهاية

أنظر كيف أن كل إجراء من هؤلاء صغير يشبه البرامج القديمة التي كنا نكتبها قبل دليل الهاتف :) بقى نقطة واحدة: لو حاولنا تشغيل البرنامج الآن ستجد مفسر كلمات يشكو ويقول: متغير غير معروف: 'العداد' ماذا يحدث هنا؟ إن الإجراء ابحث.عن.اسم يستخدم المتغير العداد بالرغم من أنه لا يعرّف متغيراً بهذا الاسم. تذكر أن كل إجراء له متغيراته المحلية الخاصة به ولا يرى المتغيرات الخاصة بالإجراءات الأخرى أو الخاصة بالبرنامج الرئيسيّ...

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

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

<اسم متغير> مشترك

لاحظ أن مثل هذا الأمر لابد أن يكون في البرنامج الرئيسي وليس بداخل أي إجراء.

حسناً إذا: بتغيير بسيط في البرنامج الرئيسي نكون قد اصلحنا المشكلة (ستظل الإجراءات كما هي):

البيانات مشترك
العداد مشترك
البيانات = مصفوفة(100)
العداد=0

علامة بداية.القائمة
اعرض.القائمة()
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    ابحث.عن.اسم()
وإلا إذا ن=2:
    اضف.بيان()
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

لا تقلق

قد تأتي الآن، عزيزي القاريء، وتشعر أن الأمور قد صارت صعبة. أقول لك إن ما يحدث الآن جزءٌ طبيعي من نموك الفكري كمبرمج. وأنت بالفعل قد كبرت فكرياً من قبل! الا تذكر برامجك الأولى التي تطبع جملاً على الشاشة؟ أين أنت منها الآن؟ :)

المبرمجون المتمرسون الذين صنعوا أو شاركوا في صنع البرامج المعروفة التي نستخدمها او الذين صمموا لغات برمجة خاصة بهم؛ هؤلاء أيضا قد بدأوا مثلك بالمتغيرات وعرض الأشياء على الشاشة، ثم كبروا خطوة بخطوة إلى أن صاروا مثلما هم عليه الآن.

إذا واجهتك مشاكل في الإجراءات يمكنك أن تعيد قراءة الأجزاء السابقة أكثر من مرة لو لزم الأمر، وخذ كل الوقت الذي تريد. كل هذا عاديٌّ جدا.

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

تعديل البيانات

الآن وقد نظمنا البرنامج قليلاً يمكننا إضافة إمكانات جديدة. فلننفّذ الآن المطلب رقم 5 في توصيف البرنامج:

عند اختيار تعديل رقم يدخل المستخدم الاسم، ولو كان ذلك الأسم مسجلاً فسيعرض
البرنامج الرقم القديم ويسأل عن الرقم الجديد ثم يخزن الأسم برقمه الجديد.
 لو لم يكن الاسم مسجلاً فسيقول البرنامج أن الاسم غير موجود ويرجع كالمعتاد 
للقائمة الرئيسية. 

أولا نضيف أمراً جديداً إلى القائمة:

إجراء اعرض.القائمة():
   اطبع " ==== برنامج دليل الهاتف ===="
   اطبع ""
   اطبع "   1 - البحث عن اسم"
   اطبع "   2 - اضافة اسم ورقم"
   اطبع "   3 - تعديل رقم"
   اطبع ""
نهاية

ثم بعد ذلك نغيّر البرنامج الرئيسي لينادي إجراء ينفذ هذا الاختيار (الإجراء نفسه لم نكتبه بعد):

البيانات = مصفوفة(100)
العداد=0

علامة بداية.القائمة
اعرض.القائمة()
اقرأ "ادخل اختيارك"، #ن

إذا ن=1:
    ابحث.عن.اسم()
وإلا إذا ن=2:
    اضف.بيان()
وإلا إذا ن=3:
    عدل.رقم()
وإلا:
    اطبع "رجاءً اختر أمرا من الاختيارات الموجودة"
تم

اذهب إلى بداية.القائمة

لم يبق إذن سوى كتابة الإجراء الذي يقوم بالتعديل:

إجراء عدل.رقم():
    <سوف نكتب أوامر هنا>
نهاية

<للتكملة...>

معاينة
أدوات شخصية