بلاك جاك

بلاك جاك

تمرين تعلّمي

مقدمة

يمكن لدالة switch() أن تكون بديلًا موجزًا عن سلسلة طويلة من اختبارات if ... else if. وغالبًا ما يكون المتغير الذي يتم التبديل عليه سلسلة نصية، وإن كان كذلك فيمكن حذف علامات الاقتباس من المحدِّد.

star <- function(type) {
  switch(type,
    M = , # will "fall through" if no value given
    K = "red dwarf",
    G = "Earth-like",
    "bigger star" # only correct for O,B,A,F
  )
}

> star("M")
[1] "red dwarf"

لاحظ أن الخيارات لن تنتقل إلى الخيار التالي إلا إذا تُركت القيمة فارغة، كما في الحالة M في المثال أعلاه. ولا حاجة إلى تضمين عبارات break كما هو الحال في بعض اللغات الأخرى.

عند التبديل على أنواع character، تكون القيمة الأخيرة هي القيمة الافتراضية، كما هنا. أما أنواع الأعداد الصحيحة فلا يمكن إعطاؤها قيمة افتراضية.

الدوال في dplyr

إن دالة switch في R الأساسية محدودة جدًا: فهي لا تُجري إلا مطابقة تامة مع مدخل واحد. بدا ذلك معقولًا عند إصدار R الأول عام 1993، لكنه يحتاج إلى تحسين للاستخدام الحديث.

Note

كما ذُكر في مفهوم Conditionals، صُمّمت مجموعة الحزم tidyverse لتكمّل وظائف R الأساسية (وأحيانًا لتحلّ محلها) دون التأثير على التوافق مع الإصدارات السابقة.

يمكن إحضار حزمة dplyr إلى النطاق بإضافة library(dplyr) (للحزمة الواحدة) أو library(tidyverse) (لكل المجموعة) إلى أعلى الكود.

توفّر مكتبة dplyr دالتين إضافيتين مرتبطتين بـswitch.

الدالتان recode_values وreplace_values

تسمح هاتان الدالتان المرتبطتان بإجراء تحويل شبيه بالتبديل على مستوى المتجهات، يربط القيم القديمة بقيم جديدة.

الفرق الأساسي بينهما هو أن recode_values() تُنشئ متجهًا جديدًا بالكامل، بينما تسمح replace_values() بتحديثات جزئية لمتجه موجود.

المطابقة لا تزال تامة، لكن:

  • يمكن أن تكون الخيارات على اليسار متجهات، ويتحقق التطابق إذا طابق أي عنصر منها.
  • تُربط الخيارات على اليسار بالنتائج على اليمين بعلامة التلدة ~ بدلًا من =.
  • يمكن تحديد قيمة افتراضية في جميع الحالات.
library(dplyr)

x <- c("a", "b", "a", "d", "b", NA, "c", "e", "z")
recode_values(
  x,
  "a" ~ 1,
  "b" ~ 2,
  "c" ~ 3,
  c("d", "e") ~ 4, # either "d' or "e" will match
  NA ~ 0,          # matches missing values
  default = 100   # note the different syntax for the default
)
#> [1]   1   2   1   4   2   0   3   4 100

دالة case_when

تأخذ case_when صياغة case_match خطوة إلى الأمام، إذ تسمح بأي تعبير منطقي على يسار ~.

لا يُمرَّر متجه الإدخال (x في المثال أدناه) كوسيط، بل يكفي أن يكون معرَّفًا مسبقًا.

x <- 1:10
case_when(
  x < 3 ~ "low",
  between(x, 3, 5) ~ "mid",
  between(x, 6, 8) ~ "high",
  .default = "what?"
)
#>  [1] "low"   "low"   "mid"   "mid"   "mid"   "high"  "high"  "high"  "what?" "what?"

دالة between() هي أيضًا جزء من dplyr.

التعليمات

في هذا التمرين سنحاكي الجولة الأولى من لعبة Blackjack.

ستتلقى بطاقتين وستتمكن من رؤية البطاقة المكشوفة للموزّع. تُمثَّل جميع البطاقات باستخدام سلسلة نصية مثل "ace" و"king" و"three" و"two" وغيرها. وقيم كل بطاقة كالتالي:

بطاقة قيمة بطاقة قيمة
ace 11 eight 8
two 2 nine 9
three 3 ten 10
four 4 jack 10
five 5 queen 10
six 6 king 10
seven 7 other 0

ملاحظة: عادةً يمكن لبطاقات "ace" أن تأخذ القيمة 1 أو 11، لكن للتبسيط سنفترض أنها تأخذ القيمة 11 فقط.

بناءً على بطاقتيك وبطاقة الموزّع، توجد استراتيجية للجولة الأولى من اللعبة، تكون فيها الخيارات التالية:

  • التوقف (S)
  • طلب بطاقة (H)
  • التقسيم (P)
  • الفوز تلقائيًا (W)

ورغم أنها ليست مثالية بعد، ستتبع الاستراتيجية التي كان صديقك Alex يطوّرها، وهي كالتالي:

  • إذا كان لديك زوج من بطاقات "ace" فيجب دائمًا أن تقسّمه.
  • إذا كان لديك Blackjack (بطاقتان مجموعهما 21)، ولم يكن لدى الموزّع بطاقة "ace" أو بطاقة مصوّرة أو بطاقة "ten"، فأنت تفوز تلقائيًا. أما إذا كان لدى الموزّع أي من تلك البطاقات، فعليك أن تتوقف وتنتظر كشف البطاقة الأخرى.
  • إذا كان مجموع بطاقتيك ضمن النطاق [17، 20] فينبغي أن تتوقف دائمًا.
  • إذا كان مجموع بطاقتيك ضمن النطاق [12، 16] فينبغي أن تتوقف دائمًا، إلا إذا كانت بطاقة الموزّع 7 أو أعلى، فعندئذ ينبغي أن تطلب بطاقة دائمًا.
  • إذا كان مجموع بطاقتيك 11 أو أقل فينبغي أن تطلب بطاقة دائمًا.

1. احسب قيمة أي بطاقة معطاة.

نفّذ دالة parse_card لحساب القيمة الرقمية لبطاقة:

parse_card("ace")
# => 11

2. نفّذ منطق القرار للجولة الأولى.

اكتب دالة first_turn تنفّذ منطق القرار كما وُصف أعلاه:

first_turn(card1, card2, dealer_card)

إليك بعض الأمثلة على النتائج المتوقعة:

first_turn("ace", "ace", "jack") == "P"
first_turn("ace", "king", "ace") == "S"
first_turn("five", "queen", "ace") == "H"
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
R Exercism

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

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