المسارات
/
Python
Python
/
التمارين
/
مثلث باسكال
مثلث باسكال

مثلث باسكال

متوسط

مقدمة

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

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

على مدار الساعة التالية، يكشف لك مدرّسك عن أمور مذهلة تختبئ في هذا المثلث:

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

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

التعليمات

مهمتك هي إخراج أول N صف من مثلث باسكال.

مثلث باسكال مصفوفة مثلثية من الأعداد الصحيحة الموجبة.

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

الصف الأول (الأعلى) يحتوي على قيمة واحدة: 1. تُحسب قيم الصفوف التالية بجمع العددين الواقعين مباشرةً على يمين ويسار الموضع الحالي في الصف السابق.

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

مثال

لنلقِ نظرة على الصفوف الخمسة الأولى من مثلث باسكال:

    1
   1 1
  1 2 1
 1 3 3 1
1 4 6 4 1

الصف الأعلى يحتوي على قيمة واحدة هي 1.

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

أما بقية القيم فلديها موضعان يجب أخذهما في الاعتبار. على سبيل المثال، القيمة الوسطى في الصف الخامس (1 4 6 4 1) هي 6، لأن القيمتين على يسارها ويمينها في الصف السابق هما 3 و3:

كيف يُطبَّق هذا التمرين في Python: العودية

صُمِّم هذا التمرين ليكتمل باستخدام recursion بدلًا من الحلقات. والدالة العودية هي دالة تستدعي نفسها، وهذا مفيد عند حل مسائل معرَّفة بدلالة نفسها. ولتفادي العودية اللانهائية (أو بتعبير أدق، لتفادي طفح المكدس)، نلجأ إلى ما يُسمى «الحالة الأساسية». وعندما نصل إلى الحالة الأساسية تُرجَع قيمة غير عودية، وهذا يسمح للنداء السابق بأن يحل ويُرجع قيمته، وهكذا تتوالى العودة عبر المكدس حتى يُرجع أول نداء الجواب. ويمكننا كتابة دالة عودية لإيجاد ناتج 5! (أي 5 * 4 * 3 * 2 * 1) كما يلي:

def factorial(number):
  if number <= 1:  # base case
    return 1

  return number * factorial(number - 1) # recursive case

print(factorial(5)) # returns 120

وأخيرًا، تجدر الإشارة إلى أن Python تحدّ من عدد المرات التي يمكن فيها إجراء نداءات عودية (1000 افتراضيًا) ولا تُحسّن العودية الذيلية.

رسائل الاستثناء

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

يتطلب هذا التمرين تحديدًا أن تستخدم عبارة raise لكي «تُطلق» عدة ValueErrors إذا مُرِّرت إلى الدالة rows() قيمة سالبة. ولن تنجح الاختبارات إلا إذا رفعت exception باستخدام raise وأرفقت معه رسالة.

ولرفع ValueError مع رسالة، اكتب الرسالة كوسيط إلى نوع exception:

# if the rows function is passed a negative number.
raise ValueError("number of rows is negative")
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Python Exercism

مستعد لبدء مثلث باسكال؟

سجّل في Exercism لتتعلّم وتتقن Python عبر 17 مفهومًا146 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.