المسارات
/
Python
Python
/
التمارين
/
ألعاب الورق
ألعاب الورق

ألعاب الورق

تمرين تعلّمي

مقدمة

‏list هي مجموعة قابلة للتعديل من العناصر في تسلسل. ومثل معظم المجموعات (راجع الأنواع المدمجة tuple وdict وset)، يمكن للمصفوفات أن تحمل مراجع إلى أي نوع بيانات (أو عدة أنواع)، بما في ذلك مصفوفات أخرى. ومثل أي تسلسل، يمكن الوصول إلى العناصر عبر رقم 0-based index من اليسار و-1-based index من اليمين. ويمكن نسخ المصفوفات كاملةً أو جزئيًا عبر تدوين التقطيع أو <list>.copy().

تدعم المصفوفات كلا من عمليات التسلسل الشائعة والقابلة للتعديل مثل min()/max()، و<list>.index()، و<list>.append()، و<list>.reverse(). ويمكن تكرار عناصر المصفوفة باستخدام بناء for item in <list>. ويمكن استخدام for index, item in enumerate(<list>) عندما تحتاج إلى كل من فهرس العنصر وقيمة العنصر.

خلف الكواليس، تُنفَّذ lists كمصفوفات ديناميكية، على غرار النوع ArrayList في Java، وهي تُستخدم غالبًا لتخزين مجموعات من بيانات متشابهة (سلاسل نصية، أعداد، مجموعات إلخ.) ذات طول غير معروف. والمصفوفات بنية بيانات بالغة المرونة والفائدة، والكثير من الطرق والعمليات المدمجة في Python تُنتج مصفوفات كمخرجات لها.

الإنشاء

يمكن تعريف list كـ قيمة حرفية باستخدام الأقواس المربعة [] وفواصل بين العناصر:

>>> no_elements = []

>>> no_elements
[]

>>> one_element = ["Guava"]

>>> one_element
['Guava']

>>> elements_separated_with_commas = ["Parrot", "Bird", 334782]

>>> elements_separated_with_commas
['Parrot', 'Bird', 334782]

لتحسين قابلية القراءة، يمكن استخدام فواصل الأسطر عند وجود عناصر كثيرة أو بنى بيانات متداخلة داخل list:

>>> lots_of_entries = [
      "Rose",
      "Sunflower",
      "Poppy",
      "Pansy",
      "Tulip",
      "Fuchsia",
      "Cyclamen",
      "Lavender"
   ]
   
>>> lots_of_entries
['Rose', 'Sunflower', 'Poppy', 'Pansy', 'Tulip', 'Fuchsia', 'Cyclamen', 'Lavender']

# Each data structure is on its own line to help clarify what they are.
>>> nested_data_structures = [
      {"fish": "gold", "monkey": "brown", "parrot": "grey"},
      ("fish", "mammal", "bird"),
      ['water', 'jungle', 'sky']
   ]
   
>>> nested_data_structures
[{'fish': 'gold', 'monkey': 'brown', 'parrot': 'grey'}, ('fish', 'mammal', 'bird'), ['water', 'jungle', 'sky']]

يمكن استخدام الدالة البانية list() فارغةً أو مع كائن قابل للتكرار كوسيط. تمر الدالة البانية على العناصر في الكائن القابل للتكرار وتضيفها إلى list بالترتيب:

>>> no_elements = list()

>>> no_elements
[]

# The tuple is unpacked and each element is added.
>>> multiple_elements_from_tuple = list(("Parrot", "Bird", 334782))

>>> multiple_elements_from_tuple
['Parrot', 'Bird', 334782]

# The set is unpacked and each element is added.
>>> multiple_elements_from_set = list({2, 3, 5, 7, 11})

>>> multiple_elements_from_set
[2, 3, 5, 7, 11]

قد تكون النتائج مفاجئة عند استخدام الدالة البانية list مع string أو dict:

# String elements (Unicode code points) are iterated through and added *individually*.
>>> multiple_elements_string = list("Timbuktu")

>>> multiple_elements_string
['T', 'i', 'm', 'b', 'u', 'k', 't', 'u']

# Unicode separators and positioning code points are also added *individually*.
>>> multiple_code_points_string = list('अभ्यास')

>>> multiple_code_points_string
['अ', 'भ', '्', 'य', 'ा', 'स']

# The iteration default for dictionaries is over the keys, so only key data is inserted into the list.
>>> source_data = {"fish": "gold", "monkey": "brown"}

>>> multiple_elements_dict_1 = list(source_data)
['fish', 'monkey']

لأن الدالة البانية list لا تقبل كوسائط إلا الكائنات القابلة للتكرار (أو لا شيء)، فإن الكائنات التي لا تقبل التكرار ترفع خطأ في النوع. وبالتالي، يكون إنشاء list بعنصر واحد باستخدام الأسلوب الحرفي أسهل بكثير.

# Numbers are not iterable, and so attempting to create a list with a number passed to the constructor fails.
>>> one_element = list(16)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable

# Tuples *are* iterable, so passing a one-element tuple to the constructor does work, but it's awkward
>>> one_element_from_iterable = list((16,))

>>> one_element_from_iterable
[16]

الوصول إلى العناصر

يمكن الوصول إلى العناصر داخل المصفوفات (وكذلك العناصر في أنواع التسلسل الأخرى str وtuple) عبر 0-based index و_تدوين الأقواس_. ويمكن أن تكون الفهارس من left --> right (بدءًا من الصفر) أو من right --> left (بدءًا من -1).

فهرس من اليسار ⟹






0
👇🏾
1
👇🏾
2
👇🏾
3
👇🏾
4
👇🏾
5
👇🏾
P y t h o n
👆🏾
-6
👆🏾
-5
👆🏾
-4
👆🏾
-3
👆🏾
-2
👆🏾
-1





⟸ فهرس من اليمين
>>> breakfast_foods = ["Oatmeal", "Fruit Salad", "Eggs", "Toast"]

# Oatmeal is at index 0 or index -4.
>>> breakfast_foods[0]
'Oatmeal'

>>> breakfast_foods[-4]
'Oatmeal'

# Eggs are at index -2 or 2
>>> breakfast_foods[-2]
'Eggs'

>>> breakfast_foods[2]
'Eggs'

# Toast is at -1
>>> breakfast_foods[-1]
'Toast'

يمكن الوصول إلى قسم من العناصر داخل list عبر تدوين التقطيع (<list>[start:stop]). يُعرَّف التقطيع بأنه تسلسل عناصر عند الموضع index، بحيث يكون start <= index < stop. و_التقطيع_ يُرجع نسخة من العناصر «المقطوعة» ولا يعدّل list الأصلية.

يمكن أيضًا استخدام معامل step بصيغة [start:stop:step] لتجاوز عناصر list أو تصفيتها (على سبيل المثال، step بقيمة 2 يعني اختيار عنصر من كل عنصرين في النطاق):

>>> colors = ["Red", "Purple", "Green", "Yellow", "Orange", "Pink", "Blue", "Grey"]

# If there is no step parameter, the step is assumed to be 1.
>>> middle_colors = colors[2:6]

>>> middle_colors
['Green', 'Yellow', 'Orange', 'Pink']

# If the start or stop parameters are omitted, the slice will
# start at index zero, and will stop at the end of the list.
>>> primary_colors = colors[::3]

>>> primary_colors
['Red', 'Yellow', 'Blue']

العمل مع المصفوفات

عند استخدام الدالة المدمجة sum() مع مصفوفة، فإنها تُرجع مجموع كل الأعداد في المصفوفة:

>>> number_list = [1, 2, 3, 4]
>>> sum(number_list)
10

يمكنك أيضًا الحصول على طول المصفوفة باستخدام الدالة len():

>>> long_list = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
>>> len(long_list)
10

يمكن أيضًا دمج المصفوفات بأساليب متنوعة:

# Using the plus + operator unpacks each list and creates a new list, but it is not efficient.
>>> new_via_concatenate = ["George", 5] + ["cat", "Tabby"]

>>> new_via_concatenate
['George', 5, 'cat', 'Tabby']

# Likewise, using the multiplication operator * is the equivalent of using + n times.
>>> first_group = ["cat", "dog", "elephant"]
>>> multiplied_group = first_group * 3

>>> multiplied_group
['cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant']

توفّر المصفوفات مُكرِّرًا، ويمكن المرور عليها بحلقة كما هو الحال مع أنواع التسلسل الأخرى.

#  Looping through the list and printing out each element.
>>> colors = ["Orange", "Green", "Grey", "Blue"]

>>> for item in colors:
...     print(item)
...
Orange
Green
Grey
Blue

للحصول على شرح أكثر تعمقًا عن loops وiterators، أكمل مفهوم loops.

التعليمات

تتطلّع إيليز بشوق كبير إلى لعب البوكر (وغيرها من ألعاب الورق) خلال رحلتها المقبلة إلى Vegas. وبما أنها من أشدّ المعجبين بـ«التتبّع الذاتي»، فإنها تريد أن تجمع بعض الدوال الصغيرة التي ستساعدها في مهام التتبّع، وقد طلبت مساعدتك في التفكير فيها.

1. تتبّع جولات البوكر

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

نفّذ دالة get_rounds(<round_number>) تأخذ رقم الجولة الحالية وتُرجع list واحدة تحتوي على تلك الجولة و_الجولتين التاليتين_ القادمتين:

>>> get_rounds(27)
[27, 28, 29]

2. الاحتفاظ بكل الجولات في المكان نفسه

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

نفّذ دالة concatenate_rounds(<rounds_1>, <rounds_2>) تأخذ مصفوفتين وتُرجع list واحدة تتكوّن من كل الجولات في list الأولى، تليها كل الجولات في list الثانية:

>>> concatenate_rounds([27, 28, 29], [35, 36])
[27, 28, 29, 35, 36]

3. إيجاد الجولات السابقة

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

نفّذ دالة list_contains_round(<rounds>, <round_number>) تأخذ وسيطين: مصفوفة بالجولات التي لُعبت، ورقم جولة. ستُرجع الدالة True إذا كانت الجولة ضمن مصفوفة الجولات الملعوبة، وFalse إذا لم تكن:

>>> list_contains_round([27, 28, 29, 35, 36], 29)
True

>>> list_contains_round([27, 28, 29, 35, 36], 30)
False

4. حساب متوسط قيم البطاقات

تريد إيليز تجربة لعبة جديدة تُسمّى Black Joe. وهي شبيهة بـ Black Jack، حيث يكون هدفك أن يكون مجموع البطاقات في يدك مساويًا لقيمة مستهدفة، لكن الهدف في Black Joe هو أن يكون متوسط قيم البطاقات مساويًا 7. ويمكن إيجاد المتوسط بجمع كل قيم البطاقات ثم قسمة هذا المجموع على عدد البطاقات في اليد.

نفّذ دالة card_average(<hand>) تُرجع متوسط قيم البطاقات في يد من Black Joe.

>>> card_average([5, 6, 7])
6.0

5. متوسطات بديلة

في Black Joe، السرعة مهمة. ستُحاول إيليز أن تجد أسلوبًا أسرع لحساب المتوسط.

وقد فكّرت في أسلوبين للحصول على عدد شبيه بالمتوسط:

  • أخذ متوسط أول عدد و_آخر_ عدد في اليد.
  • استخدام الوسيط (البطاقة الوسطى) في اليد.

نفّذ الدالة approx_average_is_average(<hand>)، حيث hand مصفوفة تحتوي على قيم البطاقات في يدك.

أرجِع True إذا كان ناتج أحد الأسلوبين المذكورين أعلاه or كليهما عددًا يساوي المتوسط الفعلي.

ملاحظة: أطوال كل الأيدي فردية، لتسهيل إيجاد الوسيط.

>>> approx_average_is_average([1, 2, 3])
True

>>> approx_average_is_average([2, 3, 4, 8, 8])
True

>>> approx_average_is_average([1, 2, 3, 5, 9])
False

6. تقنيات أخرى لحساب المتوسط

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

نفّذ دالة average_even_is_average_odd(<hand>) تُرجع قيمة منطقية تشير إلى ما إذا كان متوسط البطاقات عند الفهارس الزوجية مساويًا لمتوسط البطاقات عند الفهارس الفردية.

>>> average_even_is_average_odd([1, 2, 3])
True

>>> average_even_is_average_odd([1, 2, 3, 4])
False

7. قواعد الجولة الإضافية

كل يد رقم 11 في Black Joe هي يد إضافية لها قاعدة إضافية: إذا كانت آخر بطاقة تسحبها هي الولد، فإنك تضاعف قيمتها.

نفّذ دالة maybe_double_last(<hand>) تأخذ يدًا وتتحقّق مما إذا كانت البطاقة الأخيرة ولدًا (11). إذا كانت البطاقة الأخيرة ولدًا (11)، فاضاعف قيمتها قبل إرجاع اليد.

>>> hand = [5, 9, 11]
>>> maybe_double_last(hand)
[5, 9, 22]

>>> hand = [5, 9, 10]
>>> maybe_double_last(hand)
[5, 9, 10]
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Python Exercism

مستعد لبدء ألعاب الورق؟

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