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

علماً بأن هناك فوائد عائدة على البرنامج من خلال الشفرة البرمجية المختصرة؛ فهي تتعامل بلطف أكثر مع الذاكرة والمعالج.

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

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

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

    int pwr2(int b,int x){
    int c = b;

    for(x; x>1; x--)
        b *= c;

    return b;
}

وفرحت عندما كانت النتائج سليمة ولم اكن اتوقع ان هناك شفرة اكثر اختصاراً منها.

وتفاجأت بشفره اخرى واردة بالمنهج عجيبة وهي تستخدم اسلوب ريكيرجن (Recursion) الذي ذكرته سابقا وكانت بالشكل التالي:

int pwr(int b, int x){
    if(x != 1)
       return b*pwr(b,x-1);
}

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

ايضاً هناك الفكتوريال ( مضروب العدد ): فـ 5! = 5 × 4 × 3 ×2 تساوي 120

هنا كان تخميني صحيحاً فهكذا ظهرت معي الدالة.

int fact(int n){
    if(n != 1)
        return n*fact(n-1);
}

حسناً سأشرح المثال السابق عملية Recursion هي مشابهة نوعاً ما لعمليات التكرار مثل while,for لكن عمليات التكرار تبداء من نقطة وتنتهي بنقطة اخرى بينما Recursion تبداء بنقطة وتنتهي بنفس النقطة التي بدأت منها. أي رحلة ذهاب واياب :))

في المثال السابق لنفترض ان المدخل كان 5 ستظهر لنا النتيجة 120 بالخطوات التالية:

  • ذهاب الخطوة الاولى: يضرب خمسة بناتج اياب الخطوة الثانية ويطرح واحد من الرقم خمسة ويرسله لـذهاب الخطوة الثانية.
  • ذهاب الخطوة الثانية: يضرب أربعة بناتج اياب الخطوة الثالثة ويطرح واحد من الرقم اربعة ويرسله لـذهاب الخطوة الثالثة.
  • ذهاب الخطوة الثالثة: يضرب ثلاثه بناتج اياب الخطوة الرابعة ويطرح واحد من الرقم ثلاثة ويرسله لـذهاب الخطوة الرابعة.
  • ذهاب الخطوة الرابعة: يضرب اثنين بناتج اياب الخطوة الخامسة ويطرح واحد من الرقم اثنين ويرسله لـذهاب الخطوة الخامسة
  • ذهاب الخطوة الخامسة: يجد ان الرقم واحد وهو لايستوفي الشرط لذلك لا يحجز لرحلة ذهاب اخرى :))
  • أياب الخطوة الرابعة: لايجد مردود من ذهاب الخطوة الخامسة ويعود برقم اثنين.
  • أياب الخطوة الثالثة: كان رقم ثلاثه في صالة الانتظار ! وتعود الخطوة الرابعة حاملة رقم اثنين وتضرب بـ 3 وتكون النتيجة 6
  • أياب الخطوة الثانية: كان رقم أربعه في صالة الانتظار وعادت الخطوة الثالثة تحمل الرقم 6. عندما نضرب رقم 6 بـ 4 تكون النتيجه 24
  • اياب الخطوة الأولى: كان رقم خمسة في صالة الانتظار وعادت الخطوة الثانية تحمل الرقم 24 لتضرب بالرقم خمسة وتكون النتيجه النهائيه 120

Tower Of Hanoi:

وعند بحثي ايضاً وجدت لعبة جميلة جداً وبسيطة ايضاً. قرأت عنها في كتاب محاضر اخر وكانت ممتعة ولكن هناك دالة Recursion ربما تكون افسدت متعة اللعبة. اللعبة اسمها Tower of Hanoi وهذا رابطاً لها هي ممتعه يمكنك تجربتهاً http://www.mathsisfun.com/games/towerofhanoi.html

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

جرب اللعبة وقلي ما رأيك ؟ هل يمكن برمجة دالة تساعدك على معرفة نقل الـ 10 طبقات الى البرج الثالث بأقل خطوات ممكنة ؟ اذا كان الجواب نعم، كم تتوقع عدد الاسطر في هذه الدالة ؟ عدد الاسطر ! حسناً هي مجرد 7 اسطر.

void TowerOfHanoi(int n, string source, string temp, string destination, int& i){
    if(n ==1)
        cout << ++i << ": Move disk " << n << " from " << source << " to " << destination << endl;
    else{
        TowerOfHanoi(n - 1, source, destination, temp,i);
        cout << ++i << ": Move disk " << n << " from " << source << " to " << destination << endl;
        TowerOfHanoi(n - 1,temp , source, destination,i);
    }
}

واستخدامها يكون بالشكل التالي: int i = 0; TowerOfHanoi(3, "Tower1", "Tower2", "Tower3",i);

المدخلات التي تطلبها الدالة: 1. عدد الطبقات. 2. اسم افتراضي للبرج الاول 3. اسم افتراضي للبرج الثاني 4. اسم افتراضي للبرج الثالث 5. متغير رقمي تكون قيمته 0 ليظهر عدد الحركات

هذه الداله سترشدك كيف تحل لعبة Tower Of Hanoi بأقل خطوات ممكنة حتى لو كان عدد الطبقات 20 ! فكرة كتابة الدالة عظيمة. في بداية الموضوع مثّلت لغة البرمجة باللغة العادية ولكل مبرمج اسلوبه. مبرمج هذه الداله وصل لمرحلة الفلسفه :))

فلسفة هذه الدالة:

اذا استطعت ان تحل ذات الثلاث طبقات يعني انك تستطيع حل ذات الاربع. كذلك يمكنك حل ذات الخمس طالما تستطيع حل ذات الاربع .. الخ !

تحليل رياضي للعبة Tower Of Hanoi قد يفيدك لفهم واستيعاب عمل الدالة:

  • اذا كان هناك طبقة واحده على البرج، عدد الخطوات 1 سيكون كا التالي

    ((2^1) -1 )
    
  • اذا كانت هناك طبقتين على البرج، عدد الخطوات 3 تحسب كا التالي:

    ((2^2) -1)
    
  • اذا كانت ثلاث طبقات .... عدد الخطوات 7:

    ((2^3) -1)
    
  • اذا كان هناك n طبقات على البرج عدد الخطوات تحسب كا التالي:

    (2^n) - 1
    

ملاحظة: الشفرات السابقة كتبتها بلغة C++ ،ايضاً اعدت كتابة دالة Tower Of Hanoi مرة اخرى بلغة PHP وباللغة العربية ليستفيدوا الجميع.

  function TowerOfHanoi($n, $source, $temp, $destination, & $i){

  if($n == 1)
    echo ++$i.": حرك الطبقة ".$n." من ".$source." إلى ". $destination."<br>";
  else{
    TowerOfHanoi($n -1, $source, $destination, $temp, $i);
    echo ++$i.": حرك الطبقة ".$n." من ".$source." إلى ". $destination."<br>";
    TowerOfHanoi($n -1,$temp, $source, $destination, $i);
  }
}

استخدام الدالة كالتالي:

  $i = 0;
  echo TowerOfHanoi(3,"البرج الأول","البرج الثاني","البرج الثالث",$i)

المدخل الاول هو عدد الطبقات.

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

اتمنى تكون المشاركة مفيدة.

دمتم،؛