بلاك جاك

بلاك جاك

تمرين تعلّمي

مقدمة

المقارنات

يدعم Python عوامل المقارنة الأساسية التالية:

العامل العملية الوصف
> "أكبر من" تكون a > b مساوية لـ True إذا كانت قيمة a أكبر تمامًا من قيمة b
< "أصغر من" تكون a < b مساوية لـ True إذا كانت قيمة a أصغر تمامًا من قيمة b
== "يساوي" تكون a == b مساوية لـ True إذا كانت قيمة a مساوية تمامًا لقيمة b
>= "أكبر من أو يساوي" تكون a >= b مساوية لـ True إذا كانت a > b أو a == b من حيث القيمة
<= "أصغر من أو يساوي" تكون a <= b مساوية لـ True إذا كانت a < b أو a == b من حيث القيمة
!= "لا يساوي" تكون a != b مساوية لـ True إذا كانت a == b مساوية لـ False
is "الهوية" تكون a is b مساوية لـ True إذا وفقط إذا كان a وb هما الكائن نفسه
is not "نفي الهوية" تكون a is not b مساوية لـ True إذا لم يكن a وb هما الكائن نفسه
in "اختبار الاحتواء" تكون a in b مساوية لـ True إذا كان a عضوًا في b أو مجموعة فرعية منها أو عنصرًا فيها
not in "نفي اختبار الاحتواء" تكون a not in b مساوية لـ True إذا لم يكن a عضوًا في b ولا مجموعة فرعية منها ولا عنصرًا فيها

كلها لها الأولوية نفسها (وهي أعلى من أولوية العمليات المنطقية، لكنها أقل من أولوية العمليات الحسابية أو عمليات البت).

المقارنة بين أنواع البيانات المختلفة

الكائنات التي تنتمي إلى أنواع مختلفة (ما عدا الأنواع العددية) لا تتساوى أبدًا عند المقارنة افتراضيًا. كذلك فإن النسخ غير المتطابقة من class لن تتساوى عند المقارنة، إلا إذا عرّف class طرق المقارنة الغنية الخاصة التي تخصّص سلوك المقارنة الافتراضي لـ object. سيُغطّى التخصيص عبر rich comparisons في تمرين لاحق. لمزيد من التفاصيل (الكثير منها) حول هذا الموضوع، راجع مقارنات القيم في توثيق Python.

الأنواع العددية استثناء (في الغالب) من قاعدة تطابق الأنواع هذه. يمكن اعتبار integer مساويًا لـ float (أو اعتبار octal مساويًا لـ hexadecimal)، ما دام من الممكن تحويل النوعين ضمنيًا لأغراض المقارنة.

بالنسبة إلى الأنواع العددية الأخرى في المكتبة القياسية لـ Python (complex وdecimal وfractions)، تُعرَّف عوامل المقارنة حيث "يكون ذلك منطقيًا" (حيث لا يغيّر التحويل الضمني النتيجة)، لكنها تُطلق TypeError إذا تعذّر تحويل الكائنات الأساسية بدقة لأغراض المقارنة. لمزيد من المعلومات عن القواعد التي يستخدمها Python في التحويل العددي، راجع التحويلات الحسابية في توثيق Python.

>>> import fractions

# A string cannot be converted to an int.
>>> 17 == '17'
False

# An int can be converted to float for comparison.
>>> 17 == 17.0
True

# The fraction 6/3 can be converted to the int 2
# The int 2 can be converted to 0b10 in binary.
>>> 6/3 == 0b10
True

# An int can be converted to a complex number with a 0 imaginary part.
>>> 17 == complex(17)
True

# The fraction 2/5 can be converted to the float 0.4
>>> 0.4 == 2/5
True

>>> complex(2/5, 1/2) == complex(0.4, 0.5)
True

أي مقارنة ترتيبية بين عدد ونوع NaN (ليس عددًا) تكون False. ومن الآثار الجانبية المربكة لتعريف NaN في Python أن NaN لا يتساوى أبدًا مع NaN عند المقارنة.

>>> x = float('NaN')

>>> 3 < x
False

>>> x < 3
False

# NaN never compares equal to NaN
>>> x == x
False

مقارنة السلاسل النصية

على عكس الأعداد، تُقارَن السلاسل النصية (str) معجميًا، باستخدام نقاط ترميز Unicode الخاصة بها (أي نتيجة تمرير كل نقطة ترميز في str إلى الدالة المدمجة ord()، التي تُرجع int). إذا تطابقت جميع نقاط الترميز في السلسلتين وكانت بالترتيب نفسه، تُعدّ السلسلتان متساويتين. تُجرى هذه المقارنة على أساس الأزواج: الأول مع الأول، والثاني مع الثاني، وهكذا. في Python 3.x، لا يمكن تحويل str وbytes أو مقارنتهما مباشرة.

>>> 'Python' > 'Rust'
False

>>> 'Python' > 'JavaScript'
True

# Examples with Mandarin.
# hello < goodbye
>>> '你好' < '再见'
True

# ord() of first characters
>>> ord('你'), ord('再')
(20320, 20877)

# ord() of second characters
>>> ord('好'), ord('见')
(22909, 35265)

# And with Korean words.
# Pretty < beautiful.
>>> '예쁜' < '아름다운'
False

>>> ord('예'), ord('아')
(50696, 50500)

تسلسل المقارنات

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

على سبيل المثال، x < y <= z تكافئ x < y and y <= z، باستثناء أن y يُقيَّم مرة واحدة فقط. في كلتا الحالتين، لا يُقيَّم z إطلاقًا عندما يكون x < y مساويًا لـ False. يُسمى هذا غالبًا short-circuit evaluation، حيث يتوقف التقييم إذا كانت قيمة صدق التعبير قد تحددت بالفعل.

يدعم Short circuiting كلًا من العوامل المنطقية المتنوعة والدوال، وكذلك تسلسل المقارنات في Python. وعلى عكس كثير من لغات البرمجة الأخرى، بما فيها C وC++ وC# وJava، فإن التعبيرات المتسلسلة مثل a < b < c في Python تُفسَّر تفسيرًا رياضيًا تقليديًا وتتبع أسبقية تقليدية.

>>> x = 2
>>> y = 5
>>> z = 10

>>> x < y < z
True

>>> x < y > z
False

>>> x > y < z
False

مقارنة هوية الكائن

يختبر العاملان is وis not هوية الكائن، لا قيمته. لا تتغير هوية الكائن أبدًا بعد إنشائه، ويمكن معرفتها باستخدام الدالة id().

تكون <apple> is <orange> مساوية لـ True إذا وفقط إذا كان id(<apple>) == id(<orange>). ويكون <apple> is not <orange> عكس ذلك.

نظرًا إلى كونهما كائنين مفردين، ينبغي دائمًا مقارنة None وNotImplemented بالعناصر باستخدام is وis not. راجع وثائق مرجع Python حول مقارنات القيم وPEP8 لمزيد من التفاصيل عن هذه الاتفاقية.

>>> my_fav_numbers = [1, 2, 3]

>>> your_fav_numbers = my_fav_numbers

>>> my_fav_numbers is your_fav_numbers
True

# The returned id will differ by system and python version.
>>> id(my_fav_numbers)
4517478208

# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
# Assigning a new name does not create a new object.
>>> id(your_fav_numbers)
4517478208


>>> my_fav_numbers is not your_fav_numbers
False

>>> my_fav_numbers is not None
True

>>> my_fav_numbers is NotImplemented
False

مقارنات الانتماء

يختبر العاملان in وnot in الانتماء. تكون <fish> in <soup> مساوية لـ True إذا كان <fish> عضوًا في <soup> (إذا كان <fish> مجموعة فرعية من <soup> أو محتوى داخلها)، وتكون False خلاف ذلك. وتُرجع <fish> not in <soup> النفي، أو عكس <fish> in <soup>.

بالنسبة إلى نوعي السلسلة النصية وbytes، تكون <name> in <fullname> مساوية لـ True إذا وفقط إذا كانت <name> سلسلة فرعية من <fullname>.

# A set of lucky numbers.
>>> lucky_numbers = {11, 22, 33}
>>> 22 in lucky_numbers
True

>>> 44 in lucky_numbers
False

# A dictionary of employee information.
>>> employee = {'name': 'John Doe', 
                'id': 67826, 'age': 33, 
                'title': 'ceo'}

# Checking for the membership of certain keys.
>>> 'age' in employee
True

>>> 33 in employee
False

>>> 'lastname' not in employee
True

# Checking for substring membership
>>> name = 'Super Batman'
>>> 'Bat' in name
True

>>> 'Batwoman' in name
False

التعليمات

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

ملاحظة: في هذا التمرين، يرمز A إلى الآس، و_J_ إلى الجاك، و_Q_ إلى الملكة، و_K_ إلى الملك. وتُستبعد أوراق الجوكر. ونفترض استخدام مجموعة قياسية من 52 ورقة بالرموز الفرنسية، لكن في معظم النسخ تُخلط عدة مجموعات معًا للعب.

1. حساب قيمة الورقة

في البلاك جاك، يعود القرار إلى كل لاعب على حدة فيما إذا كانت ورقة الآس تساوي 1 أو 11 نقطة (وسنتناول هذا لاحقًا). الأوراق المصوّرة (J وQ وK) تُحتسب بـ10 نقاط، وأي ورقة أخرى تساوي قيمتها «النقاط» (العددية).

عرّف الدالة value_of_card(<card>) ذات المعامل card. ينبغي أن تُرجع الدالة القيمة العددية للسلسلة النصية للورقة المُمرَّرة. ولأن ورقة الآس يمكن أن تأخذ أكثر من قيمة (1 أو 11)، فعلى هذه الدالة أن تثبّت قيمة ورقة الآس عند 1 في الوقت الحالي. لاحقًا، ستُنفّذ دالة لتحديد قيمة ورقة الآس بالنظر إلى يد قائمة.

>>> value_of_card('K')
10

>>> value_of_card('4')
4

>>> value_of_card('A')
1

2. تحديد الورقة الأعلى قيمة

عرّف الدالة higher_card(<card_one>, <card_two>) ذات المعاملين card_one وcard_two. لأغراض احتساب النقاط، قيمة J أو Q أو K هي 10. ينبغي أن تُرجع الدالة الورقة الأعلى قيمة عند احتساب النقاط. إذا كانت الورقتان متساويتين في القيمة، فأرجِع كليهما. ويمكن إرجاع الورقتين باستخدام فاصلة في عبارة return:

# Using a comma in a return creates a Tuple.  Tuples will be covered in a later exercise.
>>> def returning_two_values(value_one, value_two):
        return value_one, value_two

>>> returning_two_values('K', '3')
('K', '3')

يمكن أن تأخذ ورقة الآس أكثر من قيمة، لذا سنثبّت قيمة أوراق A عند 1 في هذه المهمة.

>>> higher_card('K', '10')
('K', '10')

>>> higher_card('4', '6')
'6'

>>> higher_card('K', 'A')
'K'

3. حساب قيمة الآس

كما ذُكر سابقًا، يمكن أن تساوي ورقة الآس إما 1 أو 11 نقطة. ويسعى اللاعبون إلى الاقتراب قدر الإمكان من 21 نقطة دون تجاوز 21 (وهو ما يُعرف بـ«الاحتراق»).

عرّف الدالة value_of_ace(<card_one>, <card_two>) ذات المعاملين card_one وcard_two، وهما ورقتان موجودتان في اليد قبل الحصول على ورقة الآس. وسيكون على دالتك أن تقرر ما إذا كانت ورقة الآس القادمة ستحصل على قيمة 1 أو قيمة 11، ثم تُرجع تلك القيمة. تذكّر: يجب أن تكون قيمة اليد مع الآس أعلى ما يمكن دون تجاوز 21.

تلميح: إذا كانت لدينا بالفعل ورقة آس في اليد، فستكون قيمة الآس القادم 1.

>>> value_of_ace('6', 'K')
1

>>> value_of_ace('7', '3')
11

4. تحديد اليد الطبيعية أو يد البلاك جاك

إذا حصل اللاعب على ورقة آس (A) وورقة بعشر نقاط (10 أو K أو Q أو J) كأول ورقتين، فستكون نقاطه 21. وتُعرف هذه باسم يد البلاك جاك.

عرّف الدالة is_blackjack(<card_one>, <card_two>) ذات المعاملين card_one وcard_two، وهما ورقتان. حدّد ما إذا كانت اليد المكوّنة من ورقتين تمثّل بلاك جاك، وأرجِع القيمة المنطقية True إن كان الأمر كذلك، وFalse خلاف ذلك.

ملاحظة: يمكن إجراء حساب النقاط بعدة طرق. لكن إن أمكن، نودّ منك التحقق من وجود ورقة آس وورقة بعشر نقاط داخل اليد (أو في موضع معيّن)، بدلًا من جمع قيم اليد.

>>> is_blackjack('A', 'K')
True

>>> is_blackjack('10', '9')
False

5. تقسيم الأزواج

إذا كانت الورقتان الأولىان في اليد متساويتين في القيمة (على سبيل المثال، ستّتان أو Q وK)، فيمكن للاعب أن يختار التعامل معهما كيدين منفصلتين. وتُعرف هذه العملية بـ«تقسيم الأزواج».

عرّف الدالة can_split_pairs(<card_one>, <card_two>) ذات المعاملين card_one وcard_two، وهما ورقتان. حدّد ما إذا كان يمكن تقسيم هذه اليد المكوّنة من ورقتين إلى زوجين. إذا كان يمكن تقسيم اليد، فأرجِع القيمة المنطقية True، وإلا فأرجِع False

>>> can_split_pairs('Q', 'K')
True

>>> can_split_pairs('10', 'A')
False

6. مضاعفة الرهان

عندما يكون مجموع الورقتين الأصليتين 9 أو 10 أو 11 نقطة، يمكن للاعب أن يضع رهانًا إضافيًا مساويًا لرهانه الأصلي. وتُعرف هذه بـ«مضاعفة الرهان».

عرّف الدالة can_double_down(<card_one>, <card_two>) ذات المعاملين card_one وcard_two، وهما ورقتان. حدّد ما إذا كان يمكن «مضاعفة» اليد المكوّنة من ورقتين، وأرجِع القيمة المنطقية True إن أمكن ذلك، وFalse خلاف ذلك.

>>> can_double_down('A', '9')
True

>>> can_double_down('10', '2')
False
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Python Exercism

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

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